From 3078dfcc89cadbbf59e06f85246490c8cbfc8038 Mon Sep 17 00:00:00 2001 From: jiawulu Date: Wed, 21 Jun 2017 19:40:59 +0800 Subject: [PATCH] [atlas-graddle-plugin] concurrent for tpatch bundle task --- atlas-demo/AtlasDemo/app/build.gradle | 20 +- atlas-gradle-plugin/atlas-plugin/build.gradle | 4 +- .../tasks/tpatch/TPatchDiffApkBuildTask.java | 24 +- .../builder/tasks/tpatch/TPatchTask.java | 2 + atlas-gradle-plugin/dexpatch/build.gradle | 2 +- .../com/taobao/android/BasePatchTool.java | 40 +- .../java/com/taobao/android/TPatchTool.java | 539 ++++++++++-------- .../tpatch/builder/PatchFileBuilder.java | 219 +++---- .../com/taobao/android/utils/Profiler.java | 488 ++++++++++++++++ atlas-gradle-plugin/settings.gradle | 2 +- 10 files changed, 948 insertions(+), 392 deletions(-) create mode 100644 atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/utils/Profiler.java diff --git a/atlas-demo/AtlasDemo/app/build.gradle b/atlas-demo/AtlasDemo/app/build.gradle index 1e3259133..9c94751da 100644 --- a/atlas-demo/AtlasDemo/app/build.gradle +++ b/atlas-demo/AtlasDemo/app/build.gradle @@ -40,15 +40,15 @@ android { } } - // productFlavors { - // dev { - // minSdkVersion 14 - // } - // - // beta { - // minSdkVersion 21 - // } - // } + productFlavors { + dev { + minSdkVersion 14 + } + + beta { + minSdkVersion 21 + } + } } atlas { @@ -101,7 +101,7 @@ dependencies { bundleCompile project(':secondbundle') bundleCompile project(':remotebundle') bundleCompile project(':publicbundle') - bundleCompile project(':databindbundle') + //bundleCompile project(':databindbundle') compile 'com.android.support:appcompat-v7:25.1.0' compile 'com.android.support:design:25.1.0' diff --git a/atlas-gradle-plugin/atlas-plugin/build.gradle b/atlas-gradle-plugin/atlas-plugin/build.gradle index e1d74ed45..8fbdf3201 100644 --- a/atlas-gradle-plugin/atlas-plugin/build.gradle +++ b/atlas-gradle-plugin/atlas-plugin/build.gradle @@ -242,9 +242,9 @@ dependencies { compile "com.taobao.android:aapt:2.3.1.rc2" - compile "com.taobao.android:dex_patch:1.4.0.9-rc16" + compile "com.taobao.android:dex_patch:1.4.0.9-rc16-SNAPSHOT" testCompile "junit:junit:4.11" } -version = '2.3.3.beta1' \ No newline at end of file +version = '2.3.3.beta1.fast_tpatch-SNAPSHOT' \ No newline at end of file diff --git a/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchDiffApkBuildTask.java b/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchDiffApkBuildTask.java index 19699f79b..e15cee461 100644 --- a/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchDiffApkBuildTask.java +++ b/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchDiffApkBuildTask.java @@ -211,7 +211,6 @@ import java.io.File; import java.util.HashMap; -import java.util.Map; import java.util.concurrent.Callable; import java.util.zip.ZipEntry; @@ -221,6 +220,8 @@ import com.android.build.gradle.internal.variant.BaseVariantOutputData; import com.taobao.android.builder.extension.PatchConfig; import com.taobao.android.builder.tasks.manager.MtlBaseTaskAction; +import com.taobao.android.builder.tools.Profiler; +import com.taobao.android.builder.tools.zip.BetterZip; import com.taobao.android.builder.tools.zip.ZipUtils; import org.apache.commons.io.FileUtils; import org.gradle.api.tasks.InputFile; @@ -243,6 +244,9 @@ public void doApkBuild() throws Exception { apkFile = getApkFile(); diffAPkFile = getDiffAPkFile(); + Profiler.start("build tpatch apk"); + + Profiler.enter("prepare dir"); File tmpWorkDir = new File(diffAPkFile.getParentFile(), "tmp-apk"); if (tmpWorkDir.exists()) { FileUtils.deleteDirectory(tmpWorkDir); @@ -251,8 +255,10 @@ public void doApkBuild() throws Exception { tmpWorkDir.mkdirs(); } - Map zipEntityMap = new HashMap(); - ZipUtils.unzip(apkFile, tmpWorkDir.getAbsolutePath(), "UTF-8", zipEntityMap, true); + BetterZip.unzipDirectory(apkFile,tmpWorkDir); + + //Map zipEntityMap = new HashMap(); + //ZipUtils.unzip(apkFile, tmpWorkDir.getAbsolutePath(), "UTF-8", zipEntityMap, true); FileUtils.deleteDirectory(new File(tmpWorkDir, "assets")); FileUtils.deleteDirectory(new File(tmpWorkDir, "res")); @@ -264,12 +270,20 @@ public void doApkBuild() throws Exception { ZipUtils.unzip(getResourceFile(), resdir.getAbsolutePath(), "UTF-8", new HashMap(), true); FileUtils.copyDirectory(resdir, tmpWorkDir); - ZipUtils.rezip(diffAPkFile, tmpWorkDir, zipEntityMap); + + Profiler.release(); + + Profiler.enter("rezip"); + + BetterZip.zipDirectory(tmpWorkDir,diffAPkFile); + + //ZipUtils.rezip(diffAPkFile, tmpWorkDir, zipEntityMap); + Profiler.release(); FileUtils.deleteDirectory(tmpWorkDir); FileUtils.deleteDirectory(resdir); - + getLogger().warn(Profiler.dump()); } diff --git a/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchTask.java b/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchTask.java index 7c5c2b353..fde0b264c 100644 --- a/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchTask.java +++ b/atlas-gradle-plugin/atlas-plugin/src/main/java/com/taobao/android/builder/tasks/tpatch/TPatchTask.java @@ -306,6 +306,8 @@ public void doTPatch() throws Exception { TPatchTool tPatchTool = new TPatchTool(apkBO, newApkBO, patchContext.diffBundleDex); + //TODO + //tPatchTool.setVersionList(); List> remoteBundles = new ArrayList<>(); diff --git a/atlas-gradle-plugin/dexpatch/build.gradle b/atlas-gradle-plugin/dexpatch/build.gradle index 18850fcab..ad3784873 100644 --- a/atlas-gradle-plugin/dexpatch/build.gradle +++ b/atlas-gradle-plugin/dexpatch/build.gradle @@ -33,4 +33,4 @@ dependencies { group 'com.taobao.android' -version "1.4.0.9-rc16" +version "1.4.0.9-rc16-SNAPSHOT" diff --git a/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/BasePatchTool.java b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/BasePatchTool.java index 412d7a8f5..91459b380 100644 --- a/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/BasePatchTool.java +++ b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/BasePatchTool.java @@ -207,6 +207,15 @@ */ package com.taobao.android; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.Set; + import com.android.utils.ILogger; import com.android.utils.Pair; import com.google.common.collect.Lists; @@ -221,15 +230,6 @@ import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.util.List; -import java.util.Set; - /** * Created by shenghua.nish on 2016-03-19 下午9:51. */ @@ -295,24 +295,36 @@ public void setOnlyIncludeModifyBundle(boolean onlyIncludeModifyBundle) { * @return */ public boolean isModifyBundle(String bundleSoFileName) { + + DiffType diffType = getModifyType(bundleSoFileName); + + if (diffType == DiffType.NONE){ + return false; + } + + return DiffType.ADD.equals(diffType) || DiffType.MODIFY.equals(diffType); + + } + + + public DiffType getModifyType(String bundleSoFileName) { for (ArtifactBundleInfo artifactBundleInfo : artifactBundleInfos) { String packageName = artifactBundleInfo.getPkgName(); if (null == packageName) { - return false; + return DiffType.NONE; } String bundleName = "lib" + packageName.replace('.', '_') + ".so"; if (bundleName.equals(bundleSoFileName)) { if (null != logger) { logger.info("[BundleDiffType]" + bundleSoFileName + ":" + artifactBundleInfo.getDiffType()); } - if (DiffType.ADD.equals(artifactBundleInfo.getDiffType()) || DiffType.MODIFY.equals(artifactBundleInfo.getDiffType())) { - return true; - } + return artifactBundleInfo.getDiffType(); } } - return false; + return DiffType.NONE; } + public String getBundleName(String bundleSoFileName) { return FilenameUtils.getBaseName(bundleSoFileName.replace("lib", "")); } diff --git a/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/TPatchTool.java b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/TPatchTool.java index da8671398..19d7f8fd3 100644 --- a/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/TPatchTool.java +++ b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/TPatchTool.java @@ -208,17 +208,40 @@ * */ +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.sql.Date; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.jar.Attributes; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + import com.alibaba.fastjson.JSON; + import com.android.utils.Pair; import com.google.common.collect.Lists; -import com.google.common.io.LineReader; -import com.taobao.android.apatch.ApkPatch; -import com.taobao.android.apatch.utils.TypeGenUtil; import com.taobao.android.differ.dex.ApkDiff; import com.taobao.android.differ.dex.BundleDiffResult; import com.taobao.android.differ.dex.PatchException; -import com.taobao.android.dx.merge.CollisionPolicy; -import com.taobao.android.dx.merge.DexMerger; import com.taobao.android.object.ApkFileList; import com.taobao.android.object.ArtifactBundleInfo; import com.taobao.android.object.BuildPatchInfos; @@ -226,11 +249,9 @@ import com.taobao.android.object.DiffType; import com.taobao.android.object.PatchBundleInfo; import com.taobao.android.object.PatchInfo; -import com.taobao.android.smali.AfBakSmali; -import com.taobao.android.smali.SmaliMod; -import com.taobao.android.tpatch.manifest.AndroidManifestDiffFactory; import com.taobao.android.task.ExecutorServicesHelper; import com.taobao.android.tpatch.builder.PatchFileBuilder; +import com.taobao.android.tpatch.manifest.AndroidManifestDiffFactory; import com.taobao.android.tpatch.model.ApkBO; import com.taobao.android.tpatch.model.BundleBO; import com.taobao.android.tpatch.utils.HttpClientUtils; @@ -239,8 +260,7 @@ import com.taobao.android.tpatch.utils.PathUtils; import com.taobao.android.utils.CommandUtils; import com.taobao.android.utils.PathMatcher; -import com.taobao.android.utils.SmaliCodeUtils; -import com.taobao.android.utils.ZipUtils; +import com.taobao.android.utils.Profiler; import com.taobao.update.UpdateInfo; import org.antlr.runtime.RecognitionException; import org.apache.commons.io.FileUtils; @@ -249,27 +269,7 @@ import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang3.StringUtils; -import org.jf.baksmali.baksmaliOptions; -import org.jf.dexlib2.DexFileFactory; -import org.jf.dexlib2.dexbacked.DexBackedClassDef; import org.jf.dexlib2.iface.ClassDef; -import org.jf.dexlib2.util.SyntheticAccessorResolver; -import org.jf.dexlib2.writer.builder.DexBuilder; -import org.jf.dexlib2.writer.io.FileDataStore; -import org.jf.util.ClassFileNameHandler; - -import java.io.*; -import java.net.URL; -import java.net.URLConnection; -import java.sql.Date; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.jar.Attributes; -import java.util.jar.JarOutputStream; -import java.util.jar.Manifest; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; /** * 生成为atlas做动态部署的diff工具类 @@ -293,22 +293,18 @@ public class TPatchTool extends BasePatchTool { private ApkDiff apkPatchInfos = new ApkDiff(); - private List bundleDiffResults = Collections.synchronizedList(new ArrayList<>()); private List patchInfos = Collections.synchronizedList(new ArrayList<>()); private final PathMatcher pathMatcher = new PathMatcher(); - - private final String ANDROID_MANIFEST = "AndroidManifest.xml"; - // 不进入patch包的主bundle资源的资料列表,dex,lib将做另外的对比 - private static final String[] DEFAULT_NOT_INCLUDE_RESOURCES = new String[]{"*.dex", - "lib/**", - "META-INF/**"}; + private static final String[] DEFAULT_NOT_INCLUDE_RESOURCES = new String[] {"*.dex", + "lib/**", + "META-INF/**"}; private String[] notIncludeFiles; @@ -330,13 +326,13 @@ public void setCreateAll(boolean createAll) { private List noPatchBundles = Lists.newArrayList(); - private ListwhiteList = new ArrayList<>(); + private List whiteList = new ArrayList<>(); public void setVersionList(List versionList) { this.versionList = versionList; } - private ListversionList = new ArrayList<>(); + private List versionList = new ArrayList<>(); private Map> bundleClassMap = new ConcurrentHashMap>(); @@ -406,14 +402,19 @@ public File doPatch(File outPatchDir, boolean createHistoryPatch, String patchHistoryUrl, String productName) throws Exception { + + Profiler.start("doPatch"); + + Profiler.enter("prepare"); isTpatch = true; pName = productName; - hisTpatchFolder = new File(outPatchDir.getParentFile().getParentFile().getParentFile().getParentFile(),"hisTpatch"); + hisTpatchFolder = new File(outPatchDir.getParentFile().getParentFile().getParentFile().getParentFile(), + "hisTpatch"); final File diffTxtFile = new File(outPatchDir, "diff.json"); final File patchInfoFile = new File(outPatchDir, "patchInfo.json"); final File patchTmpDir = new File(outPatchDir, "tpatch-tmp"); File mainDiffFolder = new File(patchTmpDir, mainBundleName); -// FileUtils.cleanDirectory(outPatchDir); + // FileUtils.cleanDirectory(outPatchDir); patchTmpDir.mkdirs(); FileUtils.cleanDirectory(patchTmpDir); mainDiffFolder.mkdirs(); @@ -421,42 +422,62 @@ public File doPatch(File outPatchDir, readWhiteList(outPatchDir); lastPatchFile = getLastPatchFile(baseApkBO.getVersionName(), productName, outPatchDir); PatchUtils.getTpatchClassDef(lastPatchFile, bundleClassMap); + Profiler.release(); + Profiler.enter("unzip apks"); // 解压apk File unzipFolder = unzipApk(outPatchDir); final File newApkUnzipFolder = new File(unzipFolder, NEW_APK_UNZIP_NAME); final File baseApkUnzipFolder = new File(unzipFolder, BASE_APK_UNZIP_NAME); - - // 得到主bundle的dex diff文件 - File mianDiffDestDex = new File(mainDiffFolder, DEX_NAME); - File tmpDexFile = new File(patchTmpDir, mainBundleName + "-dex"); - createBundleDexPatch(newApkUnzipFolder, - baseApkUnzipFolder, - mianDiffDestDex, - tmpDexFile, - true); - - // 是否保留主bundle的资源文件 - if (isRetainMainBundleRes()) { - copyMainBundleResources(newApkUnzipFolder, - baseApkUnzipFolder, - new File(patchTmpDir, mainBundleName)); - } + Profiler.release(); ExecutorServicesHelper executorServicesHelper = new ExecutorServicesHelper(); String taskName = "diffBundleTask"; // 判断主bundle的so和awb的插件 - Collection soFiles = FileUtils.listFiles(newApkUnzipFolder, new String[]{"so"}, true); + + + Collection soFiles = FileUtils.listFiles(newApkUnzipFolder, new String[] {"so"}, true); + + //处理远程bundle if (splitDiffBundle != null) { for (Pair bundle : splitDiffBundle) { - processBundleFiles(bundle.getSecond().getBundleFile(), bundle.getFirst().getBundleFile(), patchTmpDir); - + executorServicesHelper.submitTask(taskName, new Callable() { + @Override + public Boolean call() throws Exception { + processBundleFiles(bundle.getSecond().getBundleFile(), bundle.getFirst().getBundleFile(), patchTmpDir); + return true; + } + }); } } + + Profiler.enter("awbspatch"); + executorServicesHelper.submitTask(taskName, new Callable() { + @Override + public Boolean call() throws Exception { + // 得到主bundle的dex diff文件 + File mianDiffDestDex = new File(mainDiffFolder, DEX_NAME); + File tmpDexFile = new File(patchTmpDir, mainBundleName + "-dex"); + createBundleDexPatch(newApkUnzipFolder, + baseApkUnzipFolder, + mianDiffDestDex, + tmpDexFile, + true); + + // 是否保留主bundle的资源文件 + if (isRetainMainBundleRes()) { + copyMainBundleResources(newApkUnzipFolder, + baseApkUnzipFolder, + new File(patchTmpDir, mainBundleName)); + } + return true; + } + }); + for (final File soFile : soFiles) { - System.out.println("do patch:"+soFile.getAbsolutePath()); + System.out.println("do patch:" + soFile.getAbsolutePath()); final String relativePath = PathUtils.toRelative(newApkUnzipFolder, - soFile.getAbsolutePath()); + soFile.getAbsolutePath()); if (null != notIncludeFiles && pathMatcher.match(notIncludeFiles, relativePath)) { continue; } @@ -465,14 +486,13 @@ public File doPatch(File outPatchDir, @Override public Boolean call() throws Exception { File destFile = new File(patchTmpDir, mainBundleName + "/" + - relativePath); + relativePath); File baseSoFile = new File(baseApkUnzipFolder, relativePath); - if (isBundleFile(soFile)){ + if (isBundleFile(soFile)) { processBundleFiles(soFile, baseSoFile, patchTmpDir); - }else { // 如果是bundle文件 - if (isFileModify(soFile,baseSoFile)) - FileUtils.copyFile(soFile, destFile); + } else { // 如果是bundle文件 + if (isFileModify(soFile, baseSoFile)) { FileUtils.copyFile(soFile, destFile); } } return true; } @@ -480,22 +500,26 @@ public Boolean call() throws Exception { } executorServicesHelper.waitTaskCompleted(taskName); - executorServicesHelper.stop(); + Profiler.release(); + + Profiler.enter("ziptpatchfile"); // 压缩patch文件夹,得到tpatch文件 File patchFile = createTPatchFile(outPatchDir, patchTmpDir); - PatchInfo curPatchInfo = createBasePatchInfo(patchFile); - BuildPatchInfos buildPatchInfos = null; - // 生成多版本的tpatch文件 - buildPatchInfos = createIncrementPatchFiles(productName, - patchFile, - outPatchDir, - newApkUnzipFolder, - curPatchInfo, - patchHistoryUrl); + Profiler.release(); + Profiler.enter("createhistpatch"); + BuildPatchInfos buildPatchInfos = createIncrementPatchFiles(productName, + patchFile, + outPatchDir, + newApkUnzipFolder, + curPatchInfo, + patchHistoryUrl); + Profiler.release(); + + Profiler.enter("writejson"); buildPatchInfos.getPatches().add(curPatchInfo); buildPatchInfos.setBaseVersion(baseApkBO.getVersionName()); buildPatchInfos.setDiffBundleDex(diffBundleDex); @@ -504,12 +528,14 @@ public Boolean call() throws Exception { FileUtils.writeStringToFile(outPatchJson, JSON.toJSONString(buildPatchInfos)); } - for (PatchInfo patchInfo:buildPatchInfos.getPatches()) { - UpdateInfo updateInfo = new UpdateInfo(patchInfo,buildPatchInfos.getBaseVersion()); - File updateJson = new File(outPatchDir, "update-"+patchInfo.getTargetVersion()+".json"); + for (PatchInfo patchInfo : buildPatchInfos.getPatches()) { + UpdateInfo updateInfo = new UpdateInfo(patchInfo, buildPatchInfos.getBaseVersion()); + File updateJson = new File(outPatchDir, "update-" + patchInfo.getTargetVersion() + ".json"); FileUtils.writeStringToFile(updateJson, JSON.toJSONString(updateInfo, true)); } + Profiler.release(); + Profiler.enter("cleanworkspace"); // 删除临时的目录 FileUtils.deleteDirectory(patchTmpDir); apkDiff.setBaseApkVersion(baseApkBO.getVersionName()); @@ -526,59 +552,61 @@ public Boolean call() throws Exception { FileUtils.writeStringToFile(patchInfoFile, JSON.toJSONString(apkPatchInfos)); FileUtils.copyFileToDirectory(diffTxtFile, outPatchDir.getParentFile(), true); FileUtils.copyFileToDirectory(newApkBO.getApkFile(), outPatchDir.getParentFile(), true); -// FileUtils.deleteDirectory(unzipFolder); + Profiler.release(); + + logger.warning(Profiler.dump()); + // FileUtils.deleteDirectory(unzipFolder); return patchFile; } private boolean isBundleFile(File file) { - if (whiteList.size() > 1){ - for (String bundleName:whiteList){ - if (file.getAbsolutePath().replace("\\","/").endsWith(bundleName)){ - return true; + if (whiteList.size() > 1) { + for (String bundleName : whiteList) { + if (file.getAbsolutePath().replace("\\", "/").endsWith(bundleName)) { + return true; + } } + } else { + return PatchUtils.isBundleFile(file); } - }else { - return PatchUtils.isBundleFile(file); - } - return false; + return false; } private void readWhiteList(File parentFile) throws Exception { - File whiteListFile = new File(parentFile,"bundleList.cfg"); - if (whiteListFile.exists()){ + File whiteListFile = new File(parentFile, "bundleList.cfg"); + if (whiteListFile.exists()) { BufferedReader br = null; - br = new BufferedReader(new InputStreamReader(new FileInputStream(whiteListFile), - "UTF-8")); + br = new BufferedReader(new InputStreamReader(new FileInputStream(whiteListFile), + "UTF-8")); String lineTxt = null; while ((lineTxt = br.readLine()) != null) { - whiteList.add(lineTxt); - } + whiteList.add(lineTxt); + } br.close(); } } - private File createTPatchFile(File outPatchDir, File patchTmpDir) throws IOException { // 首先压缩主bundle,先判断主bundle里有没有文件 File mainBundleFoder = new File(patchTmpDir, mainBundleName); File mainBundleFile = new File(patchTmpDir, mainBundleName + ".so"); if (FileUtils.listFiles(mainBundleFoder, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE) - .size() > 0) { + .size() > 0) { hasMainBundle = true; - CommandUtils.exec(mainBundleFoder,"zip -r "+mainBundleFile.getAbsolutePath()+" . -x */ -x .*"); + CommandUtils.exec(mainBundleFoder, "zip -r " + mainBundleFile.getAbsolutePath() + " . -x */ -x .*"); } FileUtils.deleteDirectory(mainBundleFoder); // 再压缩各自的bundle File patchFile = new File(outPatchDir, - "patch-" + newApkBO.getVersionName() + "@" + baseApkBO.getVersionName() + ".tpatch"); + "patch-" + newApkBO.getVersionName() + "@" + baseApkBO.getVersionName() + ".tpatch"); if (patchFile.exists()) { FileUtils.deleteQuietly(patchFile); } -// zipBundle(patchTmpDir, patchFile); - CommandUtils.exec(patchTmpDir,"zip -r "+patchFile.getAbsolutePath()+" . -x */ -x .*"); + // zipBundle(patchTmpDir, patchFile); + CommandUtils.exec(patchTmpDir, "zip -r " + patchFile.getAbsolutePath() + " . -x */ -x .*"); FileUtils.deleteDirectory(patchTmpDir); return patchFile; } @@ -632,90 +660,99 @@ private void processBundleFiles(File newBundleFile, final File newBundleUnzipFolder = new File(newBundleFile.getParentFile(), bundleName); final File baseBundleUnzipFolder = new File(baseBundleFile.getParentFile(), bundleName); - if (null != baseBundleFile && + DiffType modifyType = getModifyType(newBundleFile.getName()); + + logger.warning(">>> start to process bundle for patch " + bundleName + " >> difftype " + modifyType.toString() + " createALl:" + createAll); + + if (modifyType == DiffType.ADD) { + + FileUtils.copyFileToDirectory(newBundleFile, patchTmpDir); + + } else if (createAll || (modifyType == DiffType.MODIFY) ) { + + if (null != baseBundleFile && baseBundleFile.isFile() && baseBundleFile.exists() && !noPatchBundles.contains(baseBundleFile.getName() - .replace("_", ".") - .substring(3, - baseBundleFile.getName().length() - - 3)) && + .replace("_", ".") + .substring(3, + baseBundleFile.getName().length() - + 3)) && diffBundleDex) { - // 解压文件 - // 判断dex的差异性 - CommandUtils.exec(patchTmpDir,"unzip "+newBundleFile.getAbsolutePath()+" -d "+newBundleUnzipFolder.getAbsolutePath()); - CommandUtils.exec(patchTmpDir,"unzip "+baseBundleFile.getAbsolutePath()+" -d "+baseBundleUnzipFolder.getAbsolutePath()); - File destDex = new File(destPatchBundleDir, DEX_NAME); - File tmpDexFolder = new File(patchTmpDir, bundleName + "-dex"); - createBundleDexPatch(newBundleUnzipFolder, - baseBundleUnzipFolder, - destDex, - tmpDexFolder, - false); - - // 比较其他资源文件的差异性 - Collection newBundleResFiles = FileUtils.listFiles(newBundleUnzipFolder, - new IOFileFilter() { - - @Override - public boolean accept(File file) { - // 不包括dex文件 - if (file.getName() - .endsWith( - ".dex")) { - return false; - } - String relativePath = PathUtils - .toRelative( - newBundleUnzipFolder, - file.getAbsolutePath()); - if (null != - notIncludeFiles && - pathMatcher.match( - notIncludeFiles, - relativePath)) { - return false; - } - return true; - } - - @Override - public boolean accept(File file, - String s) { - return accept(new File( - file, - s)); - } - }, - TrueFileFilter.INSTANCE); - - for (File newBundleResFile : newBundleResFiles) { - String resPath = PathUtils.toRelative(newBundleUnzipFolder, - newBundleResFile.getAbsolutePath()); - File baseBundleResFile = new File(baseBundleUnzipFolder, resPath); - File destResFile = new File(destPatchBundleDir, resPath); - if (baseBundleResFile.exists()) { - if (isFileModify(newBundleResFile, - baseBundleResFile, - bundleName, - resPath)) { // 修改的资源 - FileUtils.copyFile(newBundleResFile, destResFile); - } - } else {// 新增的资源 - FileUtils.copyFile(newBundleResFile, destResFile); - } + doBundlePatch(newBundleFile, baseBundleFile, patchTmpDir, bundleName, destPatchBundleDir, + newBundleUnzipFolder, + baseBundleUnzipFolder); } - } else { // 新增的bundle,直接全量解压 - FileUtils.copyFileToDirectory(newBundleFile, patchTmpDir); } - if (!isModifyBundle(newBundleFile.getName()) && !createAll) { - FileUtils.deleteDirectory(destPatchBundleDir); - Iterator iterator = patchInfos.iterator(); - while (iterator.hasNext()) { - BundleDiffResult bundleDiffResult = iterator.next(); - if (bundleDiffResult.getBundleName().equals(bundleName.substring(3).replace("_", "."))) { - iterator.remove(); + } + + private void doBundlePatch(File newBundleFile, File baseBundleFile, File patchTmpDir, String bundleName, + File destPatchBundleDir, File newBundleUnzipFolder, File baseBundleUnzipFolder) + throws IOException, RecognitionException, PatchException { + // 解压文件 + // 判断dex的差异性 + CommandUtils.exec(patchTmpDir, + "unzip " + newBundleFile.getAbsolutePath() + " -d " + newBundleUnzipFolder.getAbsolutePath()); + CommandUtils.exec(patchTmpDir, "unzip " + baseBundleFile.getAbsolutePath() + " -d " + baseBundleUnzipFolder + .getAbsolutePath()); + File destDex = new File(destPatchBundleDir, DEX_NAME); + File tmpDexFolder = new File(patchTmpDir, bundleName + "-dex"); + createBundleDexPatch(newBundleUnzipFolder, + baseBundleUnzipFolder, + destDex, + tmpDexFolder, + false); + + // 比较其他资源文件的差异性 + Collection newBundleResFiles = FileUtils.listFiles(newBundleUnzipFolder, + new IOFileFilter() { + + @Override + public boolean accept(File file) { + // 不包括dex文件 + if (file.getName() + .endsWith( + ".dex")) { + return false; + } + String relativePath = PathUtils + .toRelative( + newBundleUnzipFolder, + file.getAbsolutePath()); + if (null != + notIncludeFiles && + pathMatcher.match( + notIncludeFiles, + relativePath)) { + return false; + } + return true; + } + + @Override + public boolean accept(File file, + String s) { + return accept(new File( + file, + s)); + } + }, + TrueFileFilter.INSTANCE); + + for (File newBundleResFile : newBundleResFiles) { + String resPath = PathUtils.toRelative(newBundleUnzipFolder, + newBundleResFile.getAbsolutePath()); + File baseBundleResFile = new File(baseBundleUnzipFolder, resPath); + File destResFile = new File(destPatchBundleDir, resPath); + if (baseBundleResFile.exists()) { + if (isFileModify(newBundleResFile, + baseBundleResFile, + bundleName, + resPath)) { // 修改的资源 + FileUtils.copyFile(newBundleResFile, destResFile); } + } else {// 新增的资源 + FileUtils.copyFile(newBundleResFile, destResFile); } } } @@ -738,7 +775,7 @@ private void copyMainBundleResources(final File newApkUnzipFolder, @Override public boolean accept(File file) { String relativePath = PathUtils.toRelative(newApkUnzipFolder, - file.getAbsolutePath()); + file.getAbsolutePath()); if (pathMatcher.match(DEFAULT_NOT_INCLUDE_RESOURCES, relativePath)) { return false; } @@ -756,7 +793,7 @@ public boolean accept(File file, String s) { for (File retainFile : retainFiles) { String relativePath = PathUtils.toRelative(newApkUnzipFolder, - retainFile.getAbsolutePath()); + retainFile.getAbsolutePath()); File baseFile = new File(baseApkUnzipFolder, relativePath); if (isFileModify(retainFile, baseFile)) { resoureModified = true; @@ -796,13 +833,13 @@ private File createBundleDexPatch(File newApkUnzipFolder, List newDexFiles = getFolderDexFiles(newApkUnzipFolder); File dexDiffFile = new File(tmpDexFile, "diff.dex"); TPatchDexTool dexTool = new TPatchDexTool(baseDexFiles, - newDexFiles, - DEFAULT_API_LEVEL, - bundleClassMap.get(tmpDexFile.getName().substring(0, - tmpDexFile.getName() - .length() - - 4)), - mainDex); + newDexFiles, + DEFAULT_API_LEVEL, + bundleClassMap.get(tmpDexFile.getName().substring(0, + tmpDexFile.getName() + .length() - + 4)), + mainDex); DexDiffInfo dexDiffInfo = dexTool.createTPatchDex(dexDiffFile); if (dexDiffFile.exists()) { dexs.add(dexDiffFile); @@ -825,7 +862,6 @@ private File createBundleDexPatch(File newApkUnzipFolder, return destDex; } - /** * 获取基准patch包的patchInfo对象 * @@ -845,7 +881,8 @@ public PatchInfo createBasePatchInfo(File file) { if (zipEntry.getName().startsWith("lib") && zipEntry.getName().indexOf("/") != -1) { modifyBundles.add(zipEntry.getName().substring(3, zipEntry.getName().indexOf("/")).replace("_", ".")); } else if (zipEntry.getName().endsWith(".so") && zipEntry.getName().indexOf("/") == -1) { - modifyBundles.add(zipEntry.getName().substring(3, zipEntry.getName().lastIndexOf(".")).replace("_", ".")); + modifyBundles.add( + zipEntry.getName().substring(3, zipEntry.getName().lastIndexOf(".")).replace("_", ".")); } } @@ -869,7 +906,7 @@ public PatchInfo createBasePatchInfo(File file) { continue; } } else if (DiffType.MODIFY.equals(artifactBundleInfo.getDiffType()) || - DiffType.ADD.equals(artifactBundleInfo.getDiffType())) { + DiffType.ADD.equals(artifactBundleInfo.getDiffType())) { PatchBundleInfo patchBundleInfo = new PatchBundleInfo(); patchBundleInfo.setNewBundle(DiffType.ADD.equals(artifactBundleInfo.getDiffType())); patchBundleInfo.setMainBundle(false); @@ -931,53 +968,52 @@ private BuildPatchInfos createIncrementPatchFiles(String productionName, String response = null; if (!StringUtils.isEmpty(patchHistoryUrl)) { String patchHisUrl = patchHistoryUrl + - "?baseVersion=" + - baseApkBO.getVersionName() + - "&productIdentifier=" + - productionName; - response = HttpClientUtils.getUrl(patchHisUrl); - - }else { - File localPatchInfo = new File(hisTpatchFolder,"patchs.json"); + "?baseVersion=" + + baseApkBO.getVersionName() + + "&productIdentifier=" + + productionName; + response = HttpClientUtils.getUrl(patchHisUrl); + + } else { + File localPatchInfo = new File(hisTpatchFolder, "patchs.json"); if (localPatchInfo.exists()) { response = FileUtils.readFileToString(localPatchInfo); } } historyBuildPatchInfos = JSON.parseObject(response, BuildPatchInfos.class); - if (historyBuildPatchInfos == null){ + if (historyBuildPatchInfos == null) { return new BuildPatchInfos(); } - Iterator patchInfos = historyBuildPatchInfos.getPatches().iterator(); - while (patchInfos.hasNext()) { - PatchInfo patchInfo = patchInfos.next(); - if (!patchInfo.getTargetVersion().equals(baseApkBO.getVersionName())) { - patchInfos.remove(); - } + Iterator patchInfos = historyBuildPatchInfos.getPatches().iterator(); + while (patchInfos.hasNext()) { + PatchInfo patchInfo = patchInfos.next(); + if (!patchInfo.getTargetVersion().equals(baseApkBO.getVersionName())) { + patchInfos.remove(); } - + } Map awbBundleMap = new HashMap(); for (ArtifactBundleInfo artifactBundleInfo : artifactBundleInfos) { String bundleFileSoName = "lib" + - artifactBundleInfo.getPkgName().replace('.', '_') + - ".so"; + artifactBundleInfo.getPkgName().replace('.', '_') + + ".so"; File bundleFile = new File(newApkUnzipFolder, - "lib" + - "/" + - "armeabi" + - "/" + - bundleFileSoName); + "lib" + + "/" + + "armeabi" + + "/" + + bundleFileSoName); if (bundleFile.exists()) { awbBundleMap.put(artifactBundleInfo.getArtifactId(), bundleFile); } } PatchFileBuilder patchFileBuilder = new PatchFileBuilder(historyBuildPatchInfos, - curTPatchFile, - curPatchInfo, - awbBundleMap, - targetDirectory, - baseApkBO.getVersionName()); + curTPatchFile, + curPatchInfo, + awbBundleMap, + targetDirectory, + baseApkBO.getVersionName()); patchFileBuilder.setNoPatchBundles(noPatchBundles); patchFileBuilder.setHistroyVersionList(versionList); @@ -1040,13 +1076,13 @@ private synchronized boolean isFileModify(File newFile, String newFileMd5 = MD5Util.getFileMD5String(newFile); String baseFileMd5 = MD5Util.getFileMD5String(baseFile); newFileMd5 = getBundleFileMappingMd5(getNewApkFileList(), - bundleFileName, - filePath, - newFileMd5); + bundleFileName, + filePath, + newFileMd5); baseFileMd5 = getBundleFileMappingMd5(getBaseApkFileList(), - bundleFileName, - filePath, - baseFileMd5); + bundleFileName, + filePath, + baseFileMd5); if (StringUtils.equals(newFileMd5, baseFileMd5)) { return false; } else if (newFile.getName().equals(ANDROID_MANIFEST)) { @@ -1063,7 +1099,7 @@ private boolean isManifestModify(File baseFile, File newFile) { androidManifestDiffFactory.diff(baseFile, newFile); for (AndroidManifestDiffFactory.DiffItem diffItem : androidManifestDiffFactory.diffResuit) { if (diffItem.Component instanceof com.taobao.android.tpatch.manifest.Manifest.Activity || - diffItem.Component instanceof com.taobao.android.tpatch.manifest.Manifest.Service) { + diffItem.Component instanceof com.taobao.android.tpatch.manifest.Manifest.Service) { return true; } } @@ -1145,16 +1181,16 @@ protected void addDirectory(JarOutputStream jos, String prefix) throws IOException { if (directory != null && directory.exists()) { Collection files = FileUtils.listFiles(directory, - TrueFileFilter.INSTANCE, - TrueFileFilter.INSTANCE); + TrueFileFilter.INSTANCE, + TrueFileFilter.INSTANCE); byte[] buf = new byte[8064]; for (File file : files) { if (file.isDirectory()) { continue; } String path = prefix + - "/" + - PathUtils.toRelative(directory, file.getAbsolutePath()); + "/" + + PathUtils.toRelative(directory, file.getAbsolutePath()); InputStream in = null; try { in = new FileInputStream(file); @@ -1215,30 +1251,27 @@ public ApkFileList getBaseApkFileList() { return null; } - -public static void main(String []args){ - ApkBO baseApkBo = new ApkBO(new File("/Users/lilong/Downloads/taobao-android-debug.apk"),"aa","1.0.0"); - ApkBO newApkB0 = new ApkBO(new File("/Users/lilong/Downloads/tpatch-diff.apk"),"aa","2.0.0"); - TPatchTool tPatchTool = new TPatchTool(baseApkBo,newApkB0,true); - try { - tPatchTool.doPatch(new File("/Users/lilong/Downloads/ccc"),true,null,true,null,null); - } catch (Exception e) { - e.printStackTrace(); - } - File dexFile = new File("/Users/lilong/Downloads/libcom_aligame_gamecenter_api_base/classes.dex"); - File newDexFile = new File("/Users/lilong/Downloads/libcom_aligame_gamecenter_api_diff/classes.dex"); - TPatchDexTool tPatchDexTool = new TPatchDexTool(dexFile,newDexFile,19,false); - try { - tPatchDexTool.createTPatchDex(new File("/Users/lilong/Downloads/libcom_aligame_gamecenter_api_diff/a.dex")); - } catch (IOException e) { - e.printStackTrace(); - } catch (PatchException e) { - e.printStackTrace(); - } catch (RecognitionException e) { - e.printStackTrace(); + public static void main(String[] args) { + ApkBO baseApkBo = new ApkBO(new File("/Users/lilong/Downloads/taobao-android-debug.apk"), "aa", "1.0.0"); + ApkBO newApkB0 = new ApkBO(new File("/Users/lilong/Downloads/tpatch-diff.apk"), "aa", "2.0.0"); + TPatchTool tPatchTool = new TPatchTool(baseApkBo, newApkB0, true); + try { + tPatchTool.doPatch(new File("/Users/lilong/Downloads/ccc"), true, null, true, null, null); + } catch (Exception e) { + e.printStackTrace(); + } + File dexFile = new File("/Users/lilong/Downloads/libcom_aligame_gamecenter_api_base/classes.dex"); + File newDexFile = new File("/Users/lilong/Downloads/libcom_aligame_gamecenter_api_diff/classes.dex"); + TPatchDexTool tPatchDexTool = new TPatchDexTool(dexFile, newDexFile, 19, false); + try { + tPatchDexTool.createTPatchDex(new File("/Users/lilong/Downloads/libcom_aligame_gamecenter_api_diff/a.dex")); + } catch (IOException e) { + e.printStackTrace(); + } catch (PatchException e) { + e.printStackTrace(); + } catch (RecognitionException e) { + e.printStackTrace(); + } } -} - - } diff --git a/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/tpatch/builder/PatchFileBuilder.java b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/tpatch/builder/PatchFileBuilder.java index 6b2765ca8..febd87d1f 100644 --- a/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/tpatch/builder/PatchFileBuilder.java +++ b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/tpatch/builder/PatchFileBuilder.java @@ -1,44 +1,45 @@ package com.taobao.android.tpatch.builder; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.sql.Date; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.jar.Attributes; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + import com.android.utils.ILogger; import com.taobao.android.BasePatchTool; -import com.taobao.android.TPatchDexTool; import com.taobao.android.TPatchTool; import com.taobao.android.differ.dex.PatchException; import com.taobao.android.object.BuildPatchInfos; import com.taobao.android.object.PatchBundleInfo; import com.taobao.android.object.PatchInfo; -import com.taobao.android.task.ExecutorServicesHelper; -import com.taobao.android.tpatch.model.BundleBO; import com.taobao.android.tpatch.utils.JarSplitUtils; import com.taobao.android.tpatch.utils.MD5Util; import com.taobao.android.tpatch.utils.PathUtils; import com.taobao.android.utils.CommandUtils; -import com.taobao.android.utils.ZipUtils; -import io.reactivex.*; -import io.reactivex.Observer; -import io.reactivex.disposables.Disposable; -import io.reactivex.functions.Function; -import io.reactivex.functions.Predicate; -import io.reactivex.schedulers.Schedulers; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang3.StringUtils; - -import java.io.*; -import java.net.URL; -import java.net.URLConnection; -import java.sql.Date; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.jar.Attributes; -import java.util.jar.JarOutputStream; -import java.util.jar.Manifest; -import java.util.zip.ZipEntry; - +import org.gradle.api.GradleException; public class PatchFileBuilder { @@ -51,7 +52,7 @@ public class PatchFileBuilder { private final File tPatchTmpFolder; private Map awbMaps; private Map hisPatchInfos = new HashMap(); - private ListversionList = new ArrayList<>(); + private List versionList = new ArrayList<>(); private final File patchsFolder; private List noPatchBundles; @@ -82,49 +83,36 @@ public void setNoPatchBundles(List noPatchBundles) { public BuildPatchInfos createHistoryTPatches(boolean diffBundleDex, final ILogger logger) throws PatchException { final BuildPatchInfos buildPatchInfos = new BuildPatchInfos(); List patchInfos = historyBuildPatchInfos.getPatches(); - io.reactivex.Observable.fromArray(patchInfos.toArray(new PatchInfo[patchInfos.size()])).filter(new Predicate() { + patchInfos.parallelStream().filter(new java.util.function.Predicate() { @Override - public boolean test(PatchInfo patchInfo) throws Exception { - if (!versionList.isEmpty() &&!versionList.contains(patchInfo.getPatchVersion())) { + public boolean test(PatchInfo patchInfo) { + if (!versionList.isEmpty() && !versionList.contains(patchInfo.getPatchVersion())) { return false; } return true; } - }).map(new Function() { + }).forEach(new Consumer() { @Override - public PatchInfo apply(PatchInfo patchInfo) throws Exception { + public void accept(PatchInfo patchInfo) { if (null != logger) { logger.info("[CreateHisPatch]" + patchInfo.getPatchVersion() + "...."); } hisPatchInfos.put(patchInfo.getPatchVersion(), patchInfo); - PatchInfo newPatchInfo = createHisTPatch(patchInfo.getPatchVersion(), logger); - return newPatchInfo; - } - }).subscribeOn(Schedulers.computation()).blockingSubscribe(new Observer() { - @Override - public void onSubscribe(Disposable d) { - - } - - @Override - public void onNext(PatchInfo value) { - buildPatchInfos.getPatches().add(value); - - } - - @Override - public void onError(Throwable e) { - if (null != logger) { - logger.error(e,"create history patch failed!"); + PatchInfo newPatchInfo = null; + try { + newPatchInfo = createHisTPatch(patchInfo.getPatchVersion(), logger); + } catch (Exception e) { + throw new GradleException(e.getMessage(), e); } - } - @Override - public void onComplete() { + synchronized (buildPatchInfos) { + buildPatchInfos.getPatches().add(newPatchInfo); + } } }); + return buildPatchInfos; } @@ -151,7 +139,7 @@ private PatchInfo createHisTPatch(String targetVersion, ILogger logger) throws I File curTPatchUnzipFolder = unzipCurTPatchFolder(patchName); // 处理awb的更新 List bundlePatches = diffPatch(hisPatchInfo, currentBuildPatchInfo); - PatchInfo newPatchInfo = processBundlePatch(hisPatchInfo, bundlePatches,curTPatchUnzipFolder); + PatchInfo newPatchInfo = processBundlePatch(hisPatchInfo, bundlePatches, curTPatchUnzipFolder); // 比对主bundle的信息 PatchBundleInfo curMainBundleInfo = getMainBundleInfo(currentBuildPatchInfo); @@ -174,20 +162,21 @@ private PatchInfo createHisTPatch(String targetVersion, ILogger logger) throws I // 生成tpatch文件 for (PatchBundleInfo bundleInfo : newPatchInfo.getBundles()) { - if (bundleInfo.getMainBundle() || bundleInfo.getNewBundle() || noPatchBundles.contains(bundleInfo.getPkgName())) { + if (bundleInfo.getMainBundle() || bundleInfo.getNewBundle() || noPatchBundles.contains( + bundleInfo.getPkgName())) { File bundleFolder = new File(destTPathTmpFolder, bundleInfo.getName()); File soFile = new File(destTPathTmpFolder, bundleInfo.getName() + ".so"); if (soFile.exists() || bundleInfo.getVersion().equals(ROLLBACK_VERSION)) { continue; } - CommandUtils.exec(bundleFolder,"zip -r "+soFile.getAbsolutePath()+" . -x */ -x .*"); -// zipBunldeSo(bundleFolder, soFile); + CommandUtils.exec(bundleFolder, "zip -r " + soFile.getAbsolutePath() + " . -x */ -x .*"); + // zipBunldeSo(bundleFolder, soFile); FileUtils.deleteDirectory(bundleFolder); } } File tPatchFile = new File(patchsFolder, newPatchInfo.getFileName()); - if (tPatchFile.exists()) FileUtils.deleteQuietly(tPatchFile); - CommandUtils.exec(destTPathTmpFolder,"zip -r "+tPatchFile.getAbsolutePath()+" . -x */ -x .*"); + if (tPatchFile.exists()) { FileUtils.deleteQuietly(tPatchFile); } + CommandUtils.exec(destTPathTmpFolder, "zip -r " + tPatchFile.getAbsolutePath() + " . -x */ -x .*"); if (null != logger) { logger.info("[TPatchFile]" + tPatchFile.getAbsolutePath()); } @@ -206,7 +195,7 @@ private void zipBunldeSo(File bundleFolder, File soOutputFile) throws PatchExcep FileOutputStream fileOutputStream = new FileOutputStream(soOutputFile); JarOutputStream jos = new JarOutputStream(new BufferedOutputStream(fileOutputStream), manifest); // Add ZIP entry to output stream. -// jos.setComment(patchVersion+"@"+targetVersion); + // jos.setComment(patchVersion+"@"+targetVersion); File[] files = bundleFolder.listFiles(); for (File file : files) { if (file.isDirectory()) { @@ -216,7 +205,7 @@ private void zipBunldeSo(File bundleFolder, File soOutputFile) throws PatchExcep } } IOUtils.closeQuietly(jos); - if (null != fileOutputStream) IOUtils.closeQuietly(fileOutputStream); + if (null != fileOutputStream) { IOUtils.closeQuietly(fileOutputStream); } } catch (IOException e) { throw new PatchException(e.getMessage(), e); } @@ -243,12 +232,13 @@ private List diffPatch(PatchInfo hisPatchInfo, PatchInfo currentPat bundlePatch.artifactId = curBundleInfo.getArtifactId(); bundlePatch.unitTag = curBundleInfo.getUnitTag(); bundlePatch.version = curBundleInfo.getVersion(); -// bundlePatch.srcUnitTag = curBundleInfo.getSrcUnitTag(); + // bundlePatch.srcUnitTag = curBundleInfo.getSrcUnitTag(); bundlePatch.newBundle = curBundleInfo.getNewBundle(); bundlePatch.hisPatchUrl = hisPatchInfo.getDownloadUrl(); bundlePatch.mainBundle = curBundleInfo.getMainBundle(); -// bundlePatch.baseVersion = curBundleInfo.getBaseVersion(); - if (hisBundles.containsKey(bundleName)&&!hisBundles.get(bundleName).getNewBundle()) { // 如果之前的patch版本也包含这个bundle的patch + // bundlePatch.baseVersion = curBundleInfo.getBaseVersion(); + if (hisBundles.containsKey(bundleName) && !hisBundles.get(bundleName) + .getNewBundle()) { // 如果之前的patch版本也包含这个bundle的patch PatchBundleInfo hisBundleInfo = hisBundles.get(bundleName); bundlePatch.baseVersion = hisBundleInfo.getVersion(); bundlePatch.srcUnitTag = hisBundleInfo.getUnitTag(); @@ -296,16 +286,19 @@ private File unzipCurTPatchFolder(String patchName) throws IOException { return curTPatchUnzipFolder; } curTPatchUnzipFolder.mkdirs(); - CommandUtils.exec(tPatchTmpFolder,"unzip "+currentPatchFile.getAbsolutePath()+" -d "+curTPatchUnzipFolder.getAbsolutePath()); -// ZipUtils.unzip(currentPatchFile, curTPatchUnzipFolder.getAbsolutePath()); + CommandUtils.exec(tPatchTmpFolder, + "unzip " + currentPatchFile.getAbsolutePath() + " -d " + curTPatchUnzipFolder + .getAbsolutePath()); + // ZipUtils.unzip(currentPatchFile, curTPatchUnzipFolder.getAbsolutePath()); File[] libs = curTPatchUnzipFolder.listFiles(); if (libs != null && libs.length > 0) { for (File lib : libs) { if (lib.isFile() && lib.getName().endsWith(".so")) { File destFolder = new File(lib.getParentFile(), FilenameUtils.getBaseName(lib.getName())); System.out.println(lib.getAbsolutePath()); - CommandUtils.exec(tPatchTmpFolder,"unzip "+lib.getAbsolutePath()+" -d "+destFolder.getAbsolutePath()); -// ZipUtils.unzip(lib, destFolder.getAbsolutePath()); + CommandUtils.exec(tPatchTmpFolder, + "unzip " + lib.getAbsolutePath() + " -d " + destFolder.getAbsolutePath()); + // ZipUtils.unzip(lib, destFolder.getAbsolutePath()); } } } @@ -320,8 +313,9 @@ private File unzipCurTPatchFolder(String patchName) throws IOException { * @param hisPatchInfo * @param bundlePatchs */ - private PatchInfo processBundlePatch(PatchInfo hisPatchInfo, List bundlePatchs,File curTPatchUnzipFolder) throws IOException, - PatchException { + private PatchInfo processBundlePatch(PatchInfo hisPatchInfo, List bundlePatchs, + File curTPatchUnzipFolder) throws IOException, + PatchException { String patchName = "patch-" + currentBuildPatchInfo.getPatchVersion() + "@" + hisPatchInfo.getPatchVersion(); PatchInfo patchInfo = new PatchInfo(); patchInfo.setFileName(patchName + ".tpatch"); @@ -340,7 +334,8 @@ private PatchInfo processBundlePatch(PatchInfo hisPatchInfo, List b continue; } else if (noPatchBundles.contains(bundlePatch.pkgName)) { - File currentBundle = new File(curTPatchUnzipFolder, "lib" + bundlePatch.pkgName.replace(".", "_") + ".so"); + File currentBundle = new File(curTPatchUnzipFolder, + "lib" + bundlePatch.pkgName.replace(".", "_") + ".so"); if (!currentBundle.exists()) { continue; } @@ -387,32 +382,38 @@ private PatchInfo processBundlePatch(PatchInfo hisPatchInfo, List b case ROLLBACK:// donothing break; case MERGE: - File hisBundleFolder = new File(hisTPatchUnzipFolder, bundleName); - if (!hisTPatchFile.exists()) { - if (StringUtils.isBlank(hisPatchInfo.getDownloadUrl()) && new File(TPatchTool.hisTpatchFolder, hisPatchInfo.getFileName()).exists()) { - File hisPatchFile = new File(TPatchTool.hisTpatchFolder, hisPatchInfo.getFileName()); - System.out.println("hisPatchFile:" + hisPatchFile.getAbsolutePath()); - if (hisPatchFile.exists()) { - FileUtils.copyFile(new File(TPatchTool.hisTpatchFolder, hisPatchInfo.getFileName()), hisTPatchFile); - CommandUtils.exec(tPatchTmpFolder, "unzip " + hisPatchFile + " -d " + hisTPatchUnzipFolder.getAbsolutePath()); -// ZipUtils.unzip(hisTPatchFile, hisTPatchUnzipFolder.getAbsolutePath()); - } - } else { - downloadTPathAndUnzip(hisPatchInfo.getDownloadUrl(), hisTPatchFile, hisTPatchUnzipFolder); - } - } - if (!hisBundleFolder.exists()){ - throw new IOException(hisBundleFolder.getAbsolutePath()+" is not exist in history bundle!"); + File hisBundleFolder = new File(hisTPatchUnzipFolder, bundleName); + if (!hisTPatchFile.exists()) { + if (StringUtils.isBlank(hisPatchInfo.getDownloadUrl()) && new File(TPatchTool.hisTpatchFolder, + hisPatchInfo.getFileName()) + .exists()) { + File hisPatchFile = new File(TPatchTool.hisTpatchFolder, hisPatchInfo.getFileName()); + System.out.println("hisPatchFile:" + hisPatchFile.getAbsolutePath()); + if (hisPatchFile.exists()) { + FileUtils.copyFile(new File(TPatchTool.hisTpatchFolder, hisPatchInfo.getFileName()), + hisTPatchFile); + CommandUtils.exec(tPatchTmpFolder, + "unzip " + hisPatchFile + " -d " + hisTPatchUnzipFolder + .getAbsolutePath()); + // ZipUtils.unzip(hisTPatchFile, hisTPatchUnzipFolder + // .getAbsolutePath()); + } + } else { + downloadTPathAndUnzip(hisPatchInfo.getDownloadUrl(), hisTPatchFile, hisTPatchUnzipFolder); + } + } + if (!hisBundleFolder.exists()) { + throw new IOException(hisBundleFolder.getAbsolutePath() + " is not exist in history bundle!"); } else { File fullAwbFile = awbMaps.get(bundlePatch.artifactId); - if (fullAwbFile == null){ + if (fullAwbFile == null) { System.out.println(bundlePatch.artifactId + " is not exits!"); FileUtils.copyDirectory(curBundleFolder, bundleDestFolder); break; } copyDiffFiles(fullAwbFile, curBundleFolder, hisBundleFolder, bundleDestFolder); - if (!bundleDestFolder.exists()||bundleDestFolder.listFiles().length == 0){ + if (!bundleDestFolder.exists() || bundleDestFolder.listFiles().length == 0) { addToPatch = false; } } @@ -427,7 +428,8 @@ private PatchInfo processBundlePatch(PatchInfo hisPatchInfo, List b /** * 复制拷贝有diff的文件 - * @param fullLibFile + * + * @param fullLibFile * @param curBundleFolder * @param hisBundleFolder * @param destBundleFolder @@ -444,11 +446,11 @@ private void copyDiffFiles(File fullLibFile, File curBundleFolder, File hisBundl FileDef curFileDef = entry.getValue(); File destFile = new File(destBundleFolder, curFilePath); -// if (curFilePath.endsWith(".dex")){ -// createHisBundleDex(curFileDef,hisBundleFileMap.get(curFilePath),destFile,fullLibFile); -// hisBundleFileMap.remove(curFilePath); -// continue; -// } + // if (curFilePath.endsWith(".dex")){ + // createHisBundleDex(curFileDef,hisBundleFileMap.get(curFilePath),destFile,fullLibFile); + // hisBundleFileMap.remove(curFilePath); + // continue; + // } if (hisBundleFileMap.containsKey(curFilePath)) { FileDef hisFileDef = hisBundleFileMap.get(curFilePath); if (curFileDef.md5.equals(hisFileDef.md5)) { @@ -470,22 +472,23 @@ private void copyDiffFiles(File fullLibFile, File curBundleFolder, File hisBundl } } - - - - private File getBaseDexFile(File newBundleFile,boolean base) { + private File getBaseDexFile(File newBundleFile, boolean base) { File newApkUnzipFolder = new File(newBundleFile.getAbsolutePath().split("lib/armeabi")[0]); File baseApkUnzipFolder = new File(newApkUnzipFolder.getParentFile(), BasePatchTool.BASE_APK_UNZIP_NAME); File baseBundleFile = null; File oldBundleFolder = null; if (base) { - baseBundleFile = new File(baseApkUnzipFolder, "lib" + File.separator + "armeabi" + File.separator + newBundleFile.getName()); - oldBundleFolder = new File(baseBundleFile.getParentFile(), FilenameUtils.getBaseName(baseBundleFile.getName())); + baseBundleFile = new File(baseApkUnzipFolder, + "lib" + File.separator + "armeabi" + File.separator + newBundleFile.getName()); + oldBundleFolder = new File(baseBundleFile.getParentFile(), + FilenameUtils.getBaseName(baseBundleFile.getName())); System.out.println("getBaseDexFile:" + new File(oldBundleFolder, "classes.dex").getAbsolutePath()); return new File(oldBundleFolder, "classes.dex"); - }else { - baseBundleFile = new File(newApkUnzipFolder, "lib" + File.separator + "armeabi" + File.separator + newBundleFile.getName()); - oldBundleFolder = new File(baseBundleFile.getParentFile(), FilenameUtils.getBaseName(baseBundleFile.getName())); + } else { + baseBundleFile = new File(newApkUnzipFolder, + "lib" + File.separator + "armeabi" + File.separator + newBundleFile.getName()); + oldBundleFolder = new File(baseBundleFile.getParentFile(), + FilenameUtils.getBaseName(baseBundleFile.getName())); System.out.println("getNewDexFile:" + new File(oldBundleFolder, "classes.dex").getAbsolutePath()); return new File(oldBundleFolder, "classes.dex"); } @@ -502,7 +505,7 @@ private Map getListFileMap(File folder) throws PatchException, Map map = new HashMap(); if (!folder.exists() || !folder.isDirectory()) { throw new PatchException("The input folder:" + folder.getAbsolutePath() - + " does not existed or is not a directory!"); + + " does not existed or is not a directory!"); } Collection files = FileUtils.listFiles(folder, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE); for (File file : files) { @@ -545,8 +548,9 @@ private void downloadTPathAndUnzip(String httpUrl, File saveFile, File tmpUnzipF if (!saveFile.exists() || !saveFile.isFile()) { downloadFile(httpUrl, saveFile); } -// ZipUtils.unzip(saveFile, tmpUnzipFolder.getAbsolutePath()); - CommandUtils.exec(tPatchTmpFolder,"unzip "+saveFile.getAbsolutePath()+" -d "+tmpUnzipFolder.getAbsolutePath()); + // ZipUtils.unzip(saveFile, tmpUnzipFolder.getAbsolutePath()); + CommandUtils.exec(tPatchTmpFolder, + "unzip " + saveFile.getAbsolutePath() + " -d " + tmpUnzipFolder.getAbsolutePath()); } /** @@ -684,7 +688,10 @@ class BundlePatch { * 表示当前patch的bundle与之前patch版本的策略,包括合并,回滚,无变化 */ enum BundlePolicy { - ADD, MERGE, REMOVE, ROLLBACK; + ADD, + MERGE, + REMOVE, + ROLLBACK; } } diff --git a/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/utils/Profiler.java b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/utils/Profiler.java new file mode 100644 index 000000000..a929d29e9 --- /dev/null +++ b/atlas-gradle-plugin/dexpatch/src/main/java/com/taobao/android/utils/Profiler.java @@ -0,0 +1,488 @@ +/* + * + * + * + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "[]" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright 2016 Alibaba Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + */ + +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package com.taobao.android.utils; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class Profiler { + + public static Logger sLogger = LoggerFactory.getLogger(Profiler.class); + + private static final ThreadLocal entryStack = new ThreadLocal(); + + public Profiler() { + } + + public static void start() { + start((String)null); + } + + public static void start(String message) { + entryStack.set(new Profiler.Entry(message, (Profiler.Entry)null, (Profiler.Entry)null)); + } + + public static void start(Profiler.Message message) { + entryStack.set(new Profiler.Entry(message, (Profiler.Entry)null, (Profiler.Entry)null)); + } + + public static void reset() { + entryStack.set((Object)null); + } + + public static void enter(String message) { + Profiler.Entry currentEntry = getCurrentEntry(); + if (currentEntry != null) { + currentEntry.enterSubEntry(message); + } + + } + + public static void enter(Profiler.Message message) { + Profiler.Entry currentEntry = getCurrentEntry(); + if (currentEntry != null) { + currentEntry.enterSubEntry(message); + } + + } + + public static void release() { + Profiler.Entry currentEntry = getCurrentEntry(); + if (currentEntry != null) { + currentEntry.release(); + } + + } + + public static long getDuration() { + Profiler.Entry entry = (Profiler.Entry)entryStack.get(); + return entry != null ? entry.getDuration() : -1L; + } + + public static String dump() { + return dump("", ""); + } + + public static String dump(String prefix) { + return dump(prefix, prefix); + } + + public static String dump(String prefix1, String prefix2) { + Profiler.Entry entry = (Profiler.Entry)entryStack.get(); + return entry != null ? entry.toString(prefix1, prefix2) : ""; + } + + public static Profiler.Entry getEntry() { + return (Profiler.Entry)entryStack.get(); + } + + private static Profiler.Entry getCurrentEntry() { + Profiler.Entry subEntry = (Profiler.Entry)entryStack.get(); + Profiler.Entry entry = null; + if (subEntry != null) { + do { + entry = subEntry; + subEntry = subEntry.getUnreleasedEntry(); + } while (subEntry != null); + } + + return entry; + } + + public interface Message { + + String getBriefMessage(); + + String getDetailedMessage(); + } + + public static final class Entry { + private final List subEntries; + private final Object message; + private final Profiler.Entry parentEntry; + private final Profiler.Entry firstEntry; + private final long baseTime; + private final long startTime; + private long endTime; + + private Entry(Object message, Profiler.Entry parentEntry, Profiler.Entry firstEntry) { + this.subEntries = new ArrayList(4); + this.message = message; + this.startTime = System.currentTimeMillis(); + this.parentEntry = parentEntry; + this.firstEntry = (Profiler.Entry)ObjectUtils.defaultIfNull(firstEntry, this); + this.baseTime = firstEntry == null ? 0L : firstEntry.startTime; + } + + public String getMessage() { + String messageString = null; + if (this.message instanceof String) { + messageString = (String)this.message; + } else if (this.message instanceof Profiler.Message) { + Profiler.Message messageObject = (Profiler.Message)this.message; + + messageString = messageObject.getDetailedMessage(); + + } + + return StringUtils.defaultIfEmpty(messageString, (String)null); + } + + public long getStartTime() { + return this.baseTime > 0L ? this.startTime - this.baseTime : 0L; + } + + public long getEndTime() { + return this.endTime < this.baseTime ? -1L : this.endTime - this.baseTime; + } + + public long getDuration() { + return this.endTime < this.startTime ? -1L : this.endTime - this.startTime; + } + + public long getDurationOfSelf() { + long duration = this.getDuration(); + if (duration < 0L) { + return -1L; + } else if (this.subEntries.isEmpty()) { + return duration; + } else { + for (int i = 0; i < this.subEntries.size(); ++i) { + Profiler.Entry subEntry = (Profiler.Entry)this.subEntries.get(i); + duration -= subEntry.getDuration(); + } + + return duration < 0L ? -1L : duration; + } + } + + public double getPecentage() { + double parentDuration = 0.0D; + double duration = (double)this.getDuration(); + if (this.parentEntry != null && this.parentEntry.isReleased()) { + parentDuration = (double)this.parentEntry.getDuration(); + } + + return duration > 0.0D && parentDuration > 0.0D ? duration / parentDuration : 0.0D; + } + + public double getPecentageOfAll() { + double firstDuration = 0.0D; + double duration = (double)this.getDuration(); + if (this.firstEntry != null && this.firstEntry.isReleased()) { + firstDuration = (double)this.firstEntry.getDuration(); + } + + return duration > 0.0D && firstDuration > 0.0D ? duration / firstDuration : 0.0D; + } + + public List getSubEntries() { + return Collections.unmodifiableList(this.subEntries); + } + + private void release() { + this.endTime = System.currentTimeMillis(); + } + + private boolean isReleased() { + return this.endTime > 0L; + } + + private void enterSubEntry(Object message) { + Profiler.Entry subEntry = new Profiler.Entry(message, this, this.firstEntry); + this.subEntries.add(subEntry); + } + + private Profiler.Entry getUnreleasedEntry() { + Profiler.Entry subEntry = null; + if (!this.subEntries.isEmpty()) { + subEntry = (Profiler.Entry)this.subEntries.get(this.subEntries.size() - 1); + if (subEntry.isReleased()) { + subEntry = null; + } + } + + return subEntry; + } + + @Override + public String toString() { + return this.toString("", ""); + } + + private String toString(String prefix1, String prefix2) { + StringBuffer buffer = new StringBuffer(); + this.toString(buffer, prefix1, prefix2); + return buffer.toString(); + } + + private void toString(StringBuffer buffer, String prefix1, String prefix2) { + buffer.append(prefix1); + String message = this.getMessage(); + long startTime = this.getStartTime(); + long duration = this.getDuration(); + long durationOfSelf = this.getDurationOfSelf(); + double percent = this.getPecentage(); + double percentOfAll = this.getPecentageOfAll(); + Object[] params = new Object[] {message, new Long(startTime), new Long(duration), new Long(durationOfSelf), + new Double(percent), new Double(percentOfAll)}; + StringBuffer pattern = new StringBuffer("{1,number} "); + if (this.isReleased()) { + pattern.append("[{2,number}ms"); + if (durationOfSelf > 0L && durationOfSelf != duration) { + pattern.append(" ({3,number}ms)"); + } + + if (percent > 0.0D) { + pattern.append(", {4,number,##%}"); + } + + if (percentOfAll > 0.0D) { + pattern.append(", {5,number,##%}"); + } + + pattern.append("]"); + } else { + pattern.append("[UNRELEASED]"); + } + + if (message != null) { + pattern.append(" - {0}"); + } + + buffer.append(MessageFormat.format(pattern.toString(), params)); + + for (int i = 0; i < this.subEntries.size(); ++i) { + Profiler.Entry subEntry = (Profiler.Entry)this.subEntries.get(i); + buffer.append('\n'); + if (i == this.subEntries.size() - 1) { + subEntry.toString(buffer, prefix2 + "`---", prefix2 + " "); + } else if (i == 0) { + subEntry.toString(buffer, prefix2 + "+---", prefix2 + "| "); + } else { + subEntry.toString(buffer, prefix2 + "+---", prefix2 + "| "); + } + } + + } + } +} diff --git a/atlas-gradle-plugin/settings.gradle b/atlas-gradle-plugin/settings.gradle index 6d76a4b75..f318398c9 100644 --- a/atlas-gradle-plugin/settings.gradle +++ b/atlas-gradle-plugin/settings.gradle @@ -1,5 +1,5 @@ include 'atlas-plugin' -//include 'dexpatch' +include 'dexpatch' include 'aapt' //include 'atlas-plugin' //include 'dexpatch'