use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class TinkerLoadLibrary method loadLibraryFromTinker.
/**
* sample usage for native library
*
* @param context
* @param relativePath such as lib/armeabi
* @param libName for the lib libTest.so, you can pass Test or libTest, or libTest.so
* @return boolean
* @throws UnsatisfiedLinkError
*/
public static boolean loadLibraryFromTinker(Context context, String relativePath, String libName) throws UnsatisfiedLinkError {
final Tinker tinker = Tinker.with(context);
libName = libName.startsWith("lib") ? libName : "lib" + libName;
libName = libName.endsWith(".so") ? libName : libName + ".so";
String relativeLibPath = relativePath + "/" + libName;
//TODO we should add cpu abi, and the real path later
if (tinker.isEnabledForNativeLib() && tinker.isTinkerLoaded()) {
TinkerLoadResult loadResult = tinker.getTinkerLoadResultIfPresent();
if (loadResult.libs != null) {
for (String name : loadResult.libs.keySet()) {
if (name.equals(relativeLibPath)) {
String patchLibraryPath = loadResult.libraryDirectory + "/" + name;
File library = new File(patchLibraryPath);
if (library.exists()) {
//whether we check md5 when load
boolean verifyMd5 = tinker.isTinkerLoadVerify();
if (verifyMd5 && !SharePatchFileUtil.verifyFileMd5(library, loadResult.libs.get(name))) {
tinker.getLoadReporter().onLoadFileMd5Mismatch(library, ShareConstants.TYPE_LIBRARY);
} else {
System.load(patchLibraryPath);
TinkerLog.i(TAG, "loadLibraryFromTinker success:" + patchLibraryPath);
return true;
}
}
}
}
}
}
return false;
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class TinkerLoadLibrary method loadArmLibrary.
/**
* you can use TinkerInstaller.loadLibrary replace your System.loadLibrary for auto update library!
* only support auto load lib/armeabi library from patch.
* for other library in lib/* or assets,
* you can load through {@code TinkerInstaller#loadLibraryFromTinker}
*/
public static void loadArmLibrary(Context context, String libName) {
if (libName == null || libName.isEmpty() || context == null) {
throw new TinkerRuntimeException("libName or context is null!");
}
Tinker tinker = Tinker.with(context);
if (tinker.isEnabledForNativeLib()) {
if (TinkerLoadLibrary.loadLibraryFromTinker(context, "lib/armeabi", libName)) {
return;
}
}
System.loadLibrary(libName);
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class DefaultPatchListener method patchCheck.
protected int patchCheck(String path) {
Tinker manager = Tinker.with(context);
//check SharePreferences also
if (!manager.isTinkerEnabled() || !ShareTinkerInternals.isTinkerEnableWithSharedPreferences(context)) {
return ShareConstants.ERROR_PATCH_DISABLE;
}
File file = new File(path);
if (!SharePatchFileUtil.isLegalFile(file)) {
return ShareConstants.ERROR_PATCH_NOTEXIST;
}
//patch service can not send request
if (manager.isPatchProcess()) {
return ShareConstants.ERROR_PATCH_INSERVICE;
}
//if the patch service is running, pending
if (TinkerServiceInternals.isTinkerPatchServiceRunning(context)) {
return ShareConstants.ERROR_PATCH_RUNNING;
}
return ShareConstants.ERROR_PATCH_OK;
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class BsDiffPatchInternal method extractBsDiffInternals.
private static boolean extractBsDiffInternals(Context context, String dir, String meta, File patchFile, int type) {
//parse
ArrayList<ShareBsDiffPatchInfo> patchList = new ArrayList<>();
ShareBsDiffPatchInfo.parseDiffPatchInfo(meta, patchList);
if (patchList.isEmpty()) {
TinkerLog.w(TAG, "extract patch list is empty! type:%s:", ShareTinkerInternals.getTypeString(type));
return true;
}
File directory = new File(dir);
if (!directory.exists()) {
directory.mkdirs();
}
//I think it is better to extract the raw files from apk
Tinker manager = Tinker.with(context);
ApplicationInfo applicationInfo = context.getApplicationInfo();
if (applicationInfo == null) {
// Looks like running on a test Context, so just return without patching.
TinkerLog.w(TAG, "applicationInfo == null!!!!");
return false;
}
ZipFile apk = null;
ZipFile patch = null;
try {
String apkPath = applicationInfo.sourceDir;
apk = new ZipFile(apkPath);
patch = new ZipFile(patchFile);
for (ShareBsDiffPatchInfo info : patchList) {
long start = System.currentTimeMillis();
final String infoPath = info.path;
String patchRealPath;
if (infoPath.equals("")) {
patchRealPath = info.name;
} else {
patchRealPath = info.path + "/" + info.name;
}
final String fileMd5 = info.md5;
if (!SharePatchFileUtil.checkIfMd5Valid(fileMd5)) {
TinkerLog.w(TAG, "meta file md5 mismatch, type:%s, name: %s, md5: %s", ShareTinkerInternals.getTypeString(type), info.name, info.md5);
manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
return false;
}
String middle;
middle = info.path + "/" + info.name;
File extractedFile = new File(dir + middle);
//check file whether already exist
if (extractedFile.exists()) {
if (fileMd5.equals(SharePatchFileUtil.getMD5(extractedFile))) {
//it is ok, just continue
TinkerLog.w(TAG, "bsdiff file %s is already exist, and md5 match, just continue", extractedFile.getPath());
continue;
} else {
TinkerLog.w(TAG, "have a mismatch corrupted dex " + extractedFile.getPath());
extractedFile.delete();
}
} else {
extractedFile.getParentFile().mkdirs();
}
String patchFileMd5 = info.patchMd5;
//it is a new file, just copy
ZipEntry patchFileEntry = patch.getEntry(patchRealPath);
if (patchFileEntry == null) {
TinkerLog.w(TAG, "patch entry is null. path:" + patchRealPath);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
return false;
}
if (patchFileMd5.equals("0")) {
if (!extract(patch, patchFileEntry, extractedFile, fileMd5, false)) {
TinkerLog.w(TAG, "Failed to extract file " + extractedFile.getPath());
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
return false;
}
} else {
//we do not check the intermediate files' md5 to save time, use check whether it is 32 length
if (!SharePatchFileUtil.checkIfMd5Valid(patchFileMd5)) {
TinkerLog.w(TAG, "meta file md5 mismatch, type:%s, name: %s, md5: %s", ShareTinkerInternals.getTypeString(type), info.name, patchFileMd5);
manager.getPatchReporter().onPatchPackageCheckFail(patchFile, BasePatchInternal.getMetaCorruptedCode(type));
return false;
}
ZipEntry rawApkFileEntry = apk.getEntry(patchRealPath);
if (rawApkFileEntry == null) {
TinkerLog.w(TAG, "apk entry is null. path:" + patchRealPath);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
return false;
}
String rawApkCrc = info.rawCrc;
//check source crc instead of md5 for faster
String rawEntryCrc = String.valueOf(rawApkFileEntry.getCrc());
if (!rawEntryCrc.equals(rawApkCrc)) {
TinkerLog.e(TAG, "apk entry %s crc is not equal, expect crc: %s, got crc: %s", patchRealPath, rawApkCrc, rawEntryCrc);
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
return false;
}
InputStream oldStream = null;
InputStream newStream = null;
try {
oldStream = apk.getInputStream(rawApkFileEntry);
newStream = patch.getInputStream(patchFileEntry);
BSPatch.patchFast(oldStream, newStream, extractedFile);
} finally {
SharePatchFileUtil.closeQuietly(oldStream);
SharePatchFileUtil.closeQuietly(newStream);
}
//go go go bsdiff get the
if (!SharePatchFileUtil.verifyFileMd5(extractedFile, fileMd5)) {
TinkerLog.w(TAG, "Failed to recover diff file " + extractedFile.getPath());
manager.getPatchReporter().onPatchTypeExtractFail(patchFile, extractedFile, info.name, type);
SharePatchFileUtil.safeDeleteFile(extractedFile);
return false;
}
TinkerLog.w(TAG, "success recover bsdiff file: %s, use time: %d", extractedFile.getPath(), (System.currentTimeMillis() - start));
}
}
} catch (Throwable e) {
// e.printStackTrace();
throw new TinkerRuntimeException("patch " + ShareTinkerInternals.getTypeString(type) + " extract failed (" + e.getMessage() + ").", e);
} finally {
SharePatchFileUtil.closeZip(apk);
SharePatchFileUtil.closeZip(patch);
}
return true;
}
use of com.tencent.tinker.lib.tinker.Tinker in project tinker by Tencent.
the class DexDiffPatchInternal method patchDexExtractViaDexDiff.
private static boolean patchDexExtractViaDexDiff(Context context, String patchVersionDirectory, String meta, final File patchFile) {
String dir = patchVersionDirectory + "/" + DEX_PATH + "/";
if (!extractDexDiffInternals(context, dir, meta, patchFile, TYPE_DEX)) {
TinkerLog.w(TAG, "patch recover, extractDiffInternals fail");
return false;
}
final Tinker manager = Tinker.with(context);
File dexFiles = new File(dir);
File[] files = dexFiles.listFiles();
optFiles.clear();
if (files != null) {
final String optimizeDexDirectory = patchVersionDirectory + "/" + DEX_OPTIMIZE_PATH + "/";
File optimizeDexDirectoryFile = new File(optimizeDexDirectory);
if (!optimizeDexDirectoryFile.exists() && !optimizeDexDirectoryFile.mkdirs()) {
TinkerLog.w(TAG, "patch recover, make optimizeDexDirectoryFile fail");
return false;
}
// add opt files
for (File file : files) {
String outputPathName = SharePatchFileUtil.optimizedPathFor(file, optimizeDexDirectoryFile);
optFiles.add(new File(outputPathName));
}
TinkerLog.w(TAG, "patch recover, try to optimize dex file count:%d", files.length);
// only use parallel dex optimizer for art
if (ShareTinkerInternals.isVmArt()) {
failOptDexFile.clear();
// try parallel dex optimizer
TinkerParallelDexOptimizer.optimizeAll(files, optimizeDexDirectoryFile, new TinkerParallelDexOptimizer.ResultCallback() {
long startTime;
@Override
public void onStart(File dexFile, File optimizedDir) {
startTime = System.currentTimeMillis();
TinkerLog.i(TAG, "start to parallel optimize dex %s, size: %d", dexFile.getPath(), dexFile.length());
}
@Override
public void onSuccess(File dexFile, File optimizedDir, File optimizedFile) {
// Do nothing.
TinkerLog.i(TAG, "success to parallel optimize dex %s, opt file size: %d, use time %d", dexFile.getPath(), optimizedFile.length(), (System.currentTimeMillis() - startTime));
}
@Override
public void onFailed(File dexFile, File optimizedDir, Throwable thr) {
TinkerLog.i(TAG, "fail to parallel optimize dex %s use time %d", dexFile.getPath(), (System.currentTimeMillis() - startTime));
failOptDexFile.add(dexFile);
}
});
// try again
for (File retryDexFile : failOptDexFile) {
try {
String outputPathName = SharePatchFileUtil.optimizedPathFor(retryDexFile, optimizeDexDirectoryFile);
if (!SharePatchFileUtil.isLegalFile(retryDexFile)) {
manager.getPatchReporter().onPatchDexOptFail(patchFile, retryDexFile, optimizeDexDirectory, retryDexFile.getName(), new TinkerRuntimeException("retry dex optimize file is not exist, name: " + retryDexFile.getName()));
return false;
}
TinkerLog.i(TAG, "try to retry dex optimize file, path: %s, size: %d", retryDexFile.getPath(), retryDexFile.length());
long start = System.currentTimeMillis();
DexFile.loadDex(retryDexFile.getAbsolutePath(), outputPathName, 0);
TinkerLog.i(TAG, "success retry dex optimize file, path: %s, opt file size: %d, use time: %d", retryDexFile.getPath(), new File(outputPathName).length(), (System.currentTimeMillis() - start));
} catch (Throwable e) {
TinkerLog.e(TAG, "retry dex optimize or load failed, path:" + retryDexFile.getPath());
manager.getPatchReporter().onPatchDexOptFail(patchFile, retryDexFile, optimizeDexDirectory, retryDexFile.getName(), e);
return false;
}
}
// for dalvik, machine hardware performance is much worse than art machine
} else {
for (File file : files) {
try {
String outputPathName = SharePatchFileUtil.optimizedPathFor(file, optimizeDexDirectoryFile);
long start = System.currentTimeMillis();
DexFile.loadDex(file.getAbsolutePath(), outputPathName, 0);
TinkerLog.i(TAG, "success single dex optimize file, path: %s, opt file size: %d, use time: %d", file.getPath(), new File(outputPathName).length(), (System.currentTimeMillis() - start));
} catch (Throwable e) {
TinkerLog.e(TAG, "single dex optimize or load failed, path:" + file.getPath());
manager.getPatchReporter().onPatchDexOptFail(patchFile, file, optimizeDexDirectory, file.getName(), e);
return false;
}
}
}
}
return true;
}
Aggregations