diff --git a/atlas-core/src/main/java/android/taobao/atlas/patch/AtlasHotPatchManager.java b/atlas-core/src/main/java/android/taobao/atlas/patch/AtlasHotPatchManager.java index 1fd01729a..061600338 100644 --- a/atlas-core/src/main/java/android/taobao/atlas/patch/AtlasHotPatchManager.java +++ b/atlas-core/src/main/java/android/taobao/atlas/patch/AtlasHotPatchManager.java @@ -87,7 +87,7 @@ private AtlasHotPatchManager(){ * @param patchEntries > * @throws IOException */ - public void installHotFixPatch(String targetVersion, HashMap> patchEntries) throws IOException{ + public void installHotFixPatch(String targetVersion, HashMap> patchEntries) throws IOException{ if(!sCurrentVersionPatchDir.exists()){ sCurrentVersionPatchDir.mkdirs(); } @@ -103,7 +103,7 @@ public void installHotFixPatch(String targetVersion, HashMap> entry = (Map.Entry) iter.next(); + Map.Entry> entry = (Map.Entry) iter.next(); File patchBundleDir = new File(sPatchVersionDir,entry.getKey()); patchBundleDir.mkdirs(); if(patchBundleDir.exists()){ diff --git a/atlas-update/build.gradle b/atlas-update/build.gradle index 8f7f25cf6..0982390f6 100644 --- a/atlas-update/build.gradle +++ b/atlas-update/build.gradle @@ -17,9 +17,10 @@ version = '1.1.4.15' apply plugin: 'com.android.library' -apply plugin: 'maven-publish' +//apply plugin: 'maven-publish' apply plugin: 'com.github.dcendents.android-maven' apply plugin: 'com.jfrog.bintray' +apply from: 'http://gitlab.alibaba-inc.com/android-build-system/buildscript/raw/master/mtl-publish.gradle' android { @@ -42,7 +43,7 @@ repositories { } dependencies { - compile 'com.taobao.android:atlas_core:5.0.7.34-beta1' + compile 'com.taobao.android:atlas_core:5.0.7.52-rc7-SNAPSHOT' compile 'io.reactivex.rxjava2:rxjava:2.0.1' compile 'org.reactivestreams:reactive-streams:1.0.0@jar' } diff --git a/atlas-update/src/main/java/com/taobao/atlas/update/AtlasUpdater.java b/atlas-update/src/main/java/com/taobao/atlas/update/AtlasUpdater.java index 77430f383..b6906485c 100644 --- a/atlas-update/src/main/java/com/taobao/atlas/update/AtlasUpdater.java +++ b/atlas-update/src/main/java/com/taobao/atlas/update/AtlasUpdater.java @@ -28,6 +28,8 @@ public class AtlasUpdater { + private static boolean usePatchDivider = true; + /** * 更新主入口 * @param updateInfo 更新的基础信息 @@ -68,7 +70,10 @@ public void onMergeResult(boolean result, String bundleName) { PatchCleaner.clearUpdatePath(updateInfo.workDir.getAbsolutePath()); + } + public static void dividePatch(boolean divide) { + usePatchDivider = divide; } @@ -88,6 +93,10 @@ public static void dexpatchUpdate(Context context, UpdateInfo updateInfo, File p if (TextUtils.isEmpty(versionName) || !versionName.equals(updateInfo.baseVersion)) { return; } + if (usePatchDivider) { + updateInfo.updateBundles = DexPatchDivider.getColdPatchList(updateInfo.updateBundles); + } + Iterator itemIterator = updateInfo.updateBundles.iterator(); while (itemIterator.hasNext()) { UpdateInfo.Item item = itemIterator.next(); diff --git a/atlas-update/src/main/java/com/taobao/atlas/update/DexPatchDivider.java b/atlas-update/src/main/java/com/taobao/atlas/update/DexPatchDivider.java new file mode 100644 index 000000000..0458c8341 --- /dev/null +++ b/atlas-update/src/main/java/com/taobao/atlas/update/DexPatchDivider.java @@ -0,0 +1,326 @@ +package com.taobao.atlas.update; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.taobao.atlas.patch.AtlasHotPatchManager; +import android.taobao.atlas.versionInfo.BaselineInfoManager; +import com.taobao.atlas.update.model.UpdateInfo; +import com.taobao.atlas.update.model.UpdateInfo.Item; + +/** + * Created by zhongcang on 2017/11/7. + */ + +public class DexPatchDivider { + + /** + * @param allItem 所有bundle patch数据 + * @return hotPatch的数据 + */ + public static List getHotPatchList(List allItem) { + List resultList = new ArrayList<>(allItem.size()); + Map installMap = AtlasHotPatchManager.getInstance().getAllInstallPatch(); + if (null == installMap) { + installMap = new HashMap<>(1); + } + for (Item item : allItem) { + if (item.patchType != Item.PATCH_DEX_HOT + && item.patchType != Item.PATCH_DEX_C_AND_H) { + continue; + } + Long version = installMap.get(item.name); + + if (item.hotPatchVersion == -1) { + //本地已经安装过,并且处于未回滚状态 + if (null != version && version != -1) { + resultList.add(Item.makeCopy(item)); + } + continue; + } + if (null == version || item.hotPatchVersion > version) { + resultList.add(Item.makeCopy(item)); + } + } + return resultList; + } + + /** + * @param allItem 所有bundle patch数据 + * @return 普通DexPatch (cold)的数据 + */ + public static List getColdPatchList(List allItem) { + List resultList = new ArrayList<>(allItem.size()); + Map installMap = BaselineInfoManager.instance().getDexPatchBundles(); + if (null == installMap) { + installMap = new HashMap<>(1); + } + for (Item item : allItem) { + if (item.patchType != Item.PATCH_DEX_COLD + && item.patchType != Item.PATCH_DEX_C_AND_H) { + continue; + } + Long version = installMap.get(item.name); + + if (item.dexpatchVersion == -1) { + //本地已经安装过,并且处于未回滚状态 + if (null != version && version != -1) { + resultList.add(Item.makeCopy(item)); + } + continue; + } + if (null == version || item.dexpatchVersion > version) { + resultList.add(Item.makeCopy(item)); + } + } + return resultList; + } + + //public boolean dividePatch(UpdateInfo info, File patchFile) { + // if (null == info || null == patchFile) { + // return false; + // } + // boolean success; + // ZipFile patchZip = null; + // try { + // patchZip = new ZipFile(patchFile); + // for (UpdateInfo.Item item : info.updateBundles) { + // if ("com.taobao.maindex".equals(item.name)) { + // ZipEntry entry = patchZip.getEntry("libcom_taobao_maindex.so"); + // if (null != entry) { + // mColdPatchList.add(Item.makeCopy(item)); + // } + // entry = patchZip.getEntry(mDexHotName); + // if (null != entry) { + // mHotPatchList.add(Item.makeCopy(item)); + // } + // } else { + // String entryName = String.format("%s%s", "lib", item.name.replace(".", "_")); + // ZipEntry entry = patchZip.getEntry(entryName + "/" + mDexColdName); + // if (null != entry) { + // mColdPatchList.add(UpdateInfo.Item.makeCopy(item)); + // } + // entry = patchZip.getEntry(entryName + "/" + mDexHotName); + // if (null != entry) { + // mHotPatchList.add(UpdateInfo.Item.makeCopy(item)); + // } + // } + // } + // success = true; + // } catch (IOException e) { + // e.printStackTrace(); + // success = false; + // } finally { + // IOUtil.quietClose(patchZip); + // } + // return success; + //} +} + +/** + * Created by zhongcang on 2017/11/7. + * + * 把搅在一起的tpatch,拆成两个独立的patch(hotPatch,coldPatch) + */ + +// +//package com.taobao.atlas.update; +// +// import java.io.File; +// import java.io.FileInputStream; +// import java.io.FileOutputStream; +// import java.io.IOException; +// import java.io.InputStream; +// import java.io.OutputStream; +// import java.util.HashMap; +// import java.util.LinkedList; +// import java.util.List; +// import java.util.Map; +// import java.util.zip.ZipEntry; +// import java.util.zip.ZipFile; +// import java.util.zip.ZipOutputStream; +// +// import android.taobao.atlas.util.IOUtil; +// import com.taobao.atlas.update.model.UpdateInfo; +// import com.taobao.atlas.update.model.UpdateInfo.Item; +// import com.taobao.dex.util.FileUtils; +// + +// +//public class PatchDivider { +// private final String mDexHotName = "hotfix.dex"; +// private final String mDexColdName = "class.dex"; +// private String mWorkDir; +// +// private List mHotPatchList = new LinkedList<>(); +// private List mColdPatchList = new LinkedList<>(); +// +// public List getHotPatchList() { +// return mHotPatchList; +// } +// +// public List getColdPatchList() { +// return mColdPatchList; +// } +// +// public boolean dividePatch(UpdateInfo info, File patchFile) { +// boolean success = false; +// if (null == info || null == patchFile) { +// return false; +// } +// mWorkDir = info.workDir.getAbsolutePath(); +// +// ZipFile patchZip = null; +// ZipOutputStream outHotPatch = null, outColdPatch = null; +// try { +// patchZip = new ZipFile(patchFile); +// outHotPatch = new ZipOutputStream(new FileOutputStream(FileUtils.makeNewFile( +// mWorkDir + "/" + info.updateVersion + "@" + info.baseVersion + "hot.tpatch" +// ))); +// outColdPatch = new ZipOutputStream(new FileOutputStream(FileUtils.makeNewFile( +// mWorkDir + "/" + info.updateVersion + "@" + info.baseVersion + "cold.tpatch" +// ))); +// for (UpdateInfo.Item item : info.updateBundles) { +// if ("com.taobao.maindex".equals(item.name)) { +// divideMainDex(item, patchZip, outColdPatch, outHotPatch); +// } else { +// String entryName = String.format("%s%s", "lib", item.name.replace(".", "_")); +// ZipEntry entry = patchZip.getEntry(entryName + "/" + mDexColdName); +// if (null != entry) { +// mColdPatchList.add(UpdateInfo.Item.makeCopy(item)); +// outColdPatch.putNextEntry(entry); +// IOUtil.copyStream(patchZip.getInputStream(entry), outColdPatch); +// } +// entry = patchZip.getEntry(entryName + "/" + mDexHotName); +// if (null != entry) { +// mHotPatchList.add(UpdateInfo.Item.makeCopy(item)); +// outHotPatch.putNextEntry(entry); +// IOUtil.copyStream(patchZip.getInputStream(entry), outHotPatch); +// } +// } +// } +// success = true; +// } catch (IOException e) { +// e.printStackTrace(); +// success = false; +// } finally { +// IOUtil.quietClose(outColdPatch); +// IOUtil.quietClose(outHotPatch); +// IOUtil.quietClose(patchZip); +// } +// return success; +// } +// +// private void divideMainDex(UpdateInfo.Item mainDexInfo, ZipFile patchZip, ZipOutputStream hotPatchOut, +// ZipOutputStream coldPatchOut) throws IOException { +// File originMainDexZip = releaseMainDex(patchZip, +// String.format("%s%s.so", "lib", mainDexInfo.name.replace(".", "_"))); +// if (null == originMainDexZip) { +// throw new IOException("release mainDex error !"); +// } +// ZipFile originZip = null; +// InputStream hotMainDexIn = null; +// InputStream coldMainDexIn = null; +// try { +// originZip = new ZipFile(originMainDexZip); +// ZipEntry entry = originZip.getEntry(mDexHotName); +// if (null != entry) { +// mHotPatchList.add(Item.makeCopy(mainDexInfo)); +// File hotMainDex = FileUtils.makeNewFile(mWorkDir + "/maindex_hot.zip"); +// zipEntry(originZip.getInputStream(entry), entry.getName(), hotMainDex); +// hotPatchOut.putNextEntry(new ZipEntry("libcom_taobao_maindex.so")); +// hotMainDexIn = new FileInputStream(hotMainDex); +// IOUtil.copyStream(hotMainDexIn, hotPatchOut); +// } +// entry = originZip.getEntry(mDexColdName); +// if (null != entry) { +// mColdPatchList.add(Item.makeCopy(mainDexInfo)); +// File coldMainDex = FileUtils.makeNewFile(mWorkDir + "/maindex_cold.zip"); +// zipEntry(originZip.getInputStream(entry), entry.getName(), coldMainDex); +// hotPatchOut.putNextEntry(new ZipEntry("libcom_taobao_maindex.so")); +// coldMainDexIn = new FileInputStream(coldMainDex); +// IOUtil.copyStream(coldMainDexIn, hotPatchOut); +// } +// } catch (IOException e) { +// e.printStackTrace(); +// } finally { +// IOUtil.quietClose(hotMainDexIn); +// IOUtil.quietClose(coldMainDexIn); +// IOUtil.quietClose(originZip); +// } +// } +// +// private File releaseMainDex(ZipFile patchZip, String entryName) { +// File tmpMainDex; +// OutputStream mainDexOut = null; +// try { +// tmpMainDex = FileUtils.makeNewFile(mWorkDir + "/dexpatch_maindex.zip"); +// mainDexOut = new FileOutputStream(tmpMainDex); +// IOUtil.copyStream(patchZip.getInputStream(patchZip.getEntry(entryName)), mainDexOut); +// } catch (IOException e) { +// e.printStackTrace(); +// tmpMainDex = null; +// } finally { +// IOUtil.quietClose(mainDexOut); +// } +// return tmpMainDex; +// } +// +// private void zipEntry(InputStream entryInput, String newEntryName, File newZip) { +// ZipOutputStream out = null; +// try { +// out = new ZipOutputStream(new FileOutputStream(newZip)); +// ZipEntry newEntry = new ZipEntry(newEntryName); +// out.putNextEntry(newEntry); +// IOUtil.copyStream(entryInput, out); +// } catch (IOException e) { +// e.printStackTrace(); +// } finally { +// IOUtil.quietClose(out); +// } +// } +// +// private Map divideMainDex(File originMainDex) { +// Map result = new HashMap<>(2); +// ZipFile zip = null; +// try { +// zip = new ZipFile(originMainDex); +// File targetHotMainDex = new File(mWorkDir + "/dexpatch_main_hot.zip"); +// File targetColdMainDex = new File(mWorkDir + "/dexpatch_main_cold.zip"); +// copyTo(zip, mDexHotName, targetHotMainDex); +// copyTo(zip, mDexColdName, targetColdMainDex); +// if (targetColdMainDex.exists()) { +// result.put(mDexColdName, targetColdMainDex); +// } +// if (targetHotMainDex.exists()) { +// result.put(mDexHotName, targetHotMainDex); +// } +// } catch (IOException e) { +// e.printStackTrace(); +// } finally { +// IOUtil.quietClose(zip); +// } +// return result; +// } +// +// private void copyTo(ZipFile zip, String entryName, File target) throws IOException { +// OutputStream out = null; +// try { +// if (target.exists()) { +// target.delete(); +// } +// ZipEntry entry = zip.getEntry(entryName); +// if (null != entry) { +// target.createNewFile(); +// out = new FileOutputStream(target); +// IOUtil.copyStream(zip.getInputStream(entry), out); +// } +// } catch (IOException e) { +// throw e; +// } finally { +// IOUtil.quietClose(out); +// } +// } +//} \ No newline at end of file diff --git a/atlas-update/src/main/java/com/taobao/atlas/update/model/UpdateInfo.java b/atlas-update/src/main/java/com/taobao/atlas/update/model/UpdateInfo.java index 13cb40dba..de9e029a0 100644 --- a/atlas-update/src/main/java/com/taobao/atlas/update/model/UpdateInfo.java +++ b/atlas-update/src/main/java/com/taobao/atlas/update/model/UpdateInfo.java @@ -4,13 +4,14 @@ import java.io.File; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; /** * Created by wuzhong on 2016/11/23. */ -public class UpdateInfo implements Serializable{ +public class UpdateInfo implements Serializable { /** * 当前的客户端版本 @@ -36,6 +37,10 @@ public class UpdateInfo implements Serializable{ * 更新的模块信息 */ public static class Item implements Serializable { + public static final int PATCH_DEX_COLD = 0; + public static final int PATCH_DEX_HOT = 1; + public static final int PATCH_DEX_C_AND_H = 2; + /** * 是不是主dex */ @@ -47,11 +52,11 @@ public static class Item implements Serializable { /** * bundle 版本信息 */ -// public String version; -// /** -// * bundle 的代码仓库对应的版本 -// */ -// public String srcVersion; + // public String version; + // /** + // * bundle 的代码仓库对应的版本 + // */ + // public String srcVersion; public String unitTag; public String srcUnitTag; @@ -65,9 +70,32 @@ public static class Item implements Serializable { */ public List dependency; + public int patchType; + public long dexpatchVersion = -1; + public long hotPatchVersion = -1; + public boolean reset = false; + + public static Item makeCopy(Item origin) { + Item item = new Item(); + item.isMainDex = origin.isMainDex; + item.name = origin.name; + item.unitTag = origin.unitTag; + item.srcUnitTag = origin.srcUnitTag; + item.inherit = origin.inherit; + item.patchType = origin.patchType; + item.dexpatchVersion = origin.dexpatchVersion; + item.hotPatchVersion = origin.hotPatchVersion; + item.reset = origin.reset; + if (null != origin.dependency) { + List copyDependency = new ArrayList<>(origin.dependency.size()); + copyDependency.addAll(origin.dependency); + item.dependency = copyDependency; + } + return item; + } } } diff --git a/atlas-update/src/main/java/com/taobao/atlas/update/util/PatchMerger.java b/atlas-update/src/main/java/com/taobao/atlas/update/util/PatchMerger.java index 6ed840f13..7159314f9 100644 --- a/atlas-update/src/main/java/com/taobao/atlas/update/util/PatchMerger.java +++ b/atlas-update/src/main/java/com/taobao/atlas/update/util/PatchMerger.java @@ -8,6 +8,7 @@ import android.taobao.atlas.framework.bundlestorage.BundleArchive; import android.taobao.atlas.runtime.RuntimeVariables; import android.taobao.atlas.util.ApkUtils; +import android.taobao.atlas.util.IOUtil; import android.taobao.atlas.util.WrapperUtil; import android.taobao.atlas.versionInfo.BaselineInfoManager; import android.text.TextUtils; @@ -94,7 +95,7 @@ public void merge() throws MergeException, IOException { File targetBundle = new File(outputDirectory, entryName); OutputStream outputStream = new FileOutputStream(targetBundle); InputStream inputStream = patchZip.getInputStream(entry); - copyStream(inputStream, outputStream); + IOUtil.copyStream(inputStream, outputStream); mergeOutputs.put(bundleName, new Pair<>(targetBundle.getAbsolutePath(), item)); } else { if(item.reset){ @@ -255,32 +256,4 @@ private boolean supportMerge(String bundleName) { return (lowDisk || supportMerge)&&bundleName.equals(MAIN_DEX); } - - private void copyStream(InputStream in, OutputStream out) throws IOException { - - try { - int c; - byte[] by = new byte[BUFFEREDSIZE]; - while ((c = in.read(by)) != -1) { - out.write(by, 0, c); - } - out.flush(); - } catch (IOException e) { - throw e; - } finally { - closeQuitely(out); - closeQuitely(in); - } - } - - - private void closeQuitely(Closeable stream) { - try { - if (stream != null) - stream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - -} +} \ No newline at end of file diff --git a/atlas-update/src/main/java/com/taobao/dex/util/FileUtils.java b/atlas-update/src/main/java/com/taobao/dex/util/FileUtils.java index caeaf2ab0..4350539bf 100644 --- a/atlas-update/src/main/java/com/taobao/dex/util/FileUtils.java +++ b/atlas-update/src/main/java/com/taobao/dex/util/FileUtils.java @@ -118,4 +118,42 @@ public static boolean hasArchiveSuffix(String fileName) { || fileName.endsWith(".jar") || fileName.endsWith(".apk"); } + + public static File makeNewFile(String filePath) throws IOException { + File file = new File(filePath); + if (file.exists()) { + if (file.isDirectory()) { + throw new IOException("file can,t be a directory"); + } + file.delete(); + } + file.getParentFile().mkdirs(); + file.createNewFile(); + return file; + } + + public static File makeNewDir(String dirPath) throws IOException { + File dir = new File(dirPath); + if (dir.exists()) { + if (dir.isFile()) { + throw new IOException("makeNewDir ,but find a file !"); + } + deleteDir(dir); + } + dir.mkdirs(); + return dir; + } + + public static boolean deleteDir(File dir) { + if (dir.isDirectory()) { + String[] children = dir.list(); + for (int i = 0; i < children.length; i++) { + boolean success = deleteDir(new File(dir, children[i])); + if (!success) { + return false; + } + } + } + return dir.delete(); + } }