From f2d71d5c68c68c2379b44b4998eb7ba2f70dc970 Mon Sep 17 00:00:00 2001 From: liuzhiwei-ms Date: Thu, 13 Jul 2017 17:53:20 +0800 Subject: [PATCH] Supports plugin installation with the same version --- .../java/com/qihoo360/loader2/Constant.java | 6 ++ .../qihoo360/replugin/model/PluginInfo.java | 82 +++++++++++++++++++ .../packages/PluginManagerServer.java | 69 +++++++++++++--- 3 files changed, 147 insertions(+), 10 deletions(-) diff --git a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Constant.java b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Constant.java index b86e5da..45a88c3 100644 --- a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Constant.java +++ b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/loader2/Constant.java @@ -72,6 +72,12 @@ public class Constant { */ public static final String LOCAL_PLUGIN_APK_LIB_DIR = "p_n"; + /** + * "纯APK"插件同版本升级时插件、Odex、Native(SO库)的用于覆盖的存放目录 + * Added by Zhiwei Liu + */ + public static final String LOCAL_PLUGIN_APK_COVER_DIR = "p_c"; + /** * 插件文件名,name-low-high-current.jar * 插件文件名规范:barcode-1-10-2.jar diff --git a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/model/PluginInfo.java b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/model/PluginInfo.java index 44d4acb..a665873 100644 --- a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/model/PluginInfo.java +++ b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/model/PluginInfo.java @@ -108,6 +108,10 @@ public class PluginInfo implements Parcelable, Cloneable { // 若插件需要卸载,则会有此值 private PluginInfo mPendingDelete; + // 若插件需要同版本覆盖安装更新,则会有此值 + private PluginInfo mPendingCover; + private boolean mIsPendingCover; + private PluginInfo(JSONObject jo) { initPluginInfo(jo); } @@ -155,6 +159,10 @@ public class PluginInfo implements Parcelable, Cloneable { if (pi.mPendingDelete != null) { this.mPendingDelete = new PluginInfo(pi.mPendingDelete); } + this.mIsPendingCover = pi.mIsPendingCover; + if (pi.mPendingCover != null) { + this.mPendingCover = new PluginInfo(pi.mPendingCover); + } } private void initPluginInfo(JSONObject jo) { @@ -171,6 +179,15 @@ public class PluginInfo implements Parcelable, Cloneable { if (djo != null) { mPendingDelete = new PluginInfo(djo); } + + // 缓存"待覆盖安装"的插件信息 + JSONObject cjo = jo.optJSONObject("coverinfo"); + if (cjo != null) { + mPendingCover = new PluginInfo(cjo); + } + + // 缓存"待覆盖安装"的插件覆盖字段 + mIsPendingCover = jo.optBoolean("cover"); } // 通过别名和包名来最终确认插件名 @@ -347,6 +364,7 @@ public class PluginInfo implements Parcelable, Cloneable { /** * 获取APK存放的文件信息

* 若为"纯APK"插件,则会位于app_p_a中;若为"p-n"插件,则会位于"app_plugins_v3"中

+ * 注意:若支持同版本覆盖安装的话,则会位于app_p_c中;

* * @return Apk所在的File对象 */ @@ -356,6 +374,8 @@ public class PluginInfo implements Parcelable, Cloneable { File dir; if (isPnPlugin()) { dir = context.getDir(Constant.LOCAL_PLUGIN_SUB_DIR, 0); + } else if (getIsPendingCover()) { + dir = context.getDir(Constant.LOCAL_PLUGIN_APK_COVER_DIR, 0); } else { dir = context.getDir(Constant.LOCAL_PLUGIN_APK_SUB_DIR, 0); } @@ -365,6 +385,7 @@ public class PluginInfo implements Parcelable, Cloneable { /** * 获取Dex(优化后)生成时所在的目录

* 若为"纯APK"插件,则会位于app_p_od中;若为"p-n"插件,则会位于"app_plugins_v3_odex"中

+ * 若支持同版本覆盖安装的话,则会位于app_p_c中;

* 注意:仅供框架内部使用 * * @return 优化后Dex所在目录的File对象 @@ -374,6 +395,8 @@ public class PluginInfo implements Parcelable, Cloneable { Context context = RePluginInternal.getAppContext(); if (isPnPlugin()) { return context.getDir(Constant.LOCAL_PLUGIN_ODEX_SUB_DIR, 0); + } else if (getIsPendingCover()) { + return context.getDir(Constant.LOCAL_PLUGIN_APK_COVER_DIR, 0); } else { return context.getDir(Constant.LOCAL_PLUGIN_APK_ODEX_SUB_DIR, 0); } @@ -394,6 +417,7 @@ public class PluginInfo implements Parcelable, Cloneable { /** * 根据类型来获取SO释放的路径

* 若为"纯APK"插件,则会位于app_p_n中;若为"p-n"插件,则会位于"app_plugins_v3_libs"中

+ * 若支持同版本覆盖安装的话,则会位于app_p_c中;

* 注意:仅供框架内部使用 * * @return SO释放路径所在的File对象 @@ -404,6 +428,8 @@ public class PluginInfo implements Parcelable, Cloneable { File dir; if (isPnPlugin()) { dir = context.getDir(Constant.LOCAL_PLUGIN_DATA_LIB_DIR, 0); + } else if (getIsPendingCover()) { + dir = context.getDir(Constant.LOCAL_PLUGIN_APK_COVER_DIR, 0); } else { dir = context.getDir(Constant.LOCAL_PLUGIN_APK_LIB_DIR, 0); } @@ -491,6 +517,62 @@ public class PluginInfo implements Parcelable, Cloneable { } } + /** + * 是否已准备好了新待覆盖的版本? + * + * @return 是否已准备好 + */ + public boolean isNeedCover() { + return mPendingCover != null; + } + + /** + * 获取将来要覆盖更新的插件的信息,将会在下次启动时才能被使用 + * + * @return 插件覆盖安装信息 + */ + public PluginInfo getPendingCover() { + return mPendingCover; + } + + /** + * 设置插件的覆盖更新信息。此信息有可能等到下次才能被使用

+ * 注意:若为“纯APK”方案所用,则修改后需调用PluginInfoList.save来保存,否则会无效 + * + * @param info 插件覆盖安装信息 + */ + public void setPendingCover(PluginInfo info) { + mPendingCover = info; + if (info != null) { + JSONHelper.putNoThrows(mJson, "coverinfo", info.getJSON()); + } else { + mJson.remove("coverinfo"); + } + } + + /** + * 此PluginInfo是否包含同版本覆盖的字段?只在调用RePlugin.install方法才能看到

+ * 注意:仅框架内部使用 + * + * @return 是否包含同版本覆盖字段 + */ + public boolean getIsPendingCover() { + return mIsPendingCover; + } + + /** + * 设置PluginInfo的同版本覆盖的字段

+ * 注意:仅框架内部使用 + */ + public void setIsPendingCover(boolean coverInfo) { + mIsPendingCover = coverInfo; + if (mIsPendingCover) { + JSONHelper.putNoThrows(mJson, "cover", mIsPendingCover); + } else { + mJson.remove("cover"); + } + } + /** * 获取最小支持宿主API的版本 */ diff --git a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/packages/PluginManagerServer.java b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/packages/PluginManagerServer.java index e25312c..a2f0f44 100644 --- a/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/packages/PluginManagerServer.java +++ b/replugin-host-library/replugin-host-lib/src/main/java/com/qihoo360/replugin/packages/PluginManagerServer.java @@ -201,7 +201,19 @@ public class PluginManagerServer { } private boolean checkVersion(PluginInfo instPli, PluginInfo curPli) { - if (instPli.getVersion() <= curPli.getVersion()) { + // 支持插件同版本覆盖安装? + // 若现在要安装的,与之前的版本相同,则覆盖掉之前的版本; + if (instPli.getVersion() == curPli.getVersion()) { + if (LogDebug.LOG) { + LogDebug.d(TAG, "isSameVersion: same version. " + + "inst_ver=" + instPli.getVersion() + "; cur_ver=" + curPli.getVersion()); + } + instPli.setIsPendingCover(true); + return true; + } + + // 若现在要安装的,比之前的版本还要旧,则忽略更新; + if (instPli.getVersion() < curPli.getVersion()) { if (LogDebug.LOG) { LogDebug.e(TAG, "checkVersion: Older than current, install fail. pn=" + curPli.getName() + "; inst_ver=" + instPli.getVersion() + "; cur_ver=" + curPli.getVersion()); @@ -210,9 +222,9 @@ public class PluginManagerServer { } // 已有“待更新版本”? - // 若现在要安装的,比“待更新版本”还要旧(或相同),则也可以忽略 + // 若现在要安装的,比“待更新版本”还要旧,则也可以忽略 PluginInfo curUpdatePli = curPli.getPendingUpdate(); - if (curUpdatePli != null && instPli.getVersion() <= curUpdatePli.getVersion()) { + if (curUpdatePli != null && instPli.getVersion() < curUpdatePli.getVersion()) { if (LogDebug.LOG) { LogDebug.e(TAG, "checkVersion: Older than updating plugin. Ignore. pn=" + curPli.getName() + "; " + "cur_ver=" + curPli.getVersion() + "; old_ver=" + curUpdatePli.getVersion() + "; new_ver=" + instPli.getVersion()); @@ -273,8 +285,14 @@ public class PluginManagerServer { if (LogDebug.LOG) { LogDebug.w(TAG, "updateOrLater: Plugin is running. Later. pn=" + curPli.getName()); } - instPli.setIsThisPendingUpdateInfo(true); - curPli.setPendingUpdate(instPli); + if (instPli.getVersion() > curPli.getVersion()) { + // 高版本升级 + instPli.setIsThisPendingUpdateInfo(true); + curPli.setPendingUpdate(instPli); + } else if (instPli.getVersion() == curPli.getVersion()){ + // 同版本覆盖 + curPli.setPendingCover(instPli); + } } else { if (LogDebug.LOG) { LogDebug.i(TAG, "updateOrLater: Not running. Update now! pn=" + curPli.getName()); @@ -348,7 +366,9 @@ public class PluginManagerServer { // 需要更新插件?那就直接来 updateNow(curInfo, curInfo.getPendingUpdate()); return true; - + } else if (curInfo.isNeedCover()) { + updateNow(curInfo, curInfo.getPendingCover()); + return true; } else { // 既不需要删除也不需要更新 if (LogDebug.LOG) { @@ -359,8 +379,13 @@ public class PluginManagerServer { } private void updateNow(PluginInfo curInfo, PluginInfo newInfo) { - // 删除旧版本插件,不管是不是p-n的,且清掉Dex和Native目录 - delete(curInfo); + final boolean covered = newInfo.getIsPendingCover(); + if (covered) { + move(curInfo, newInfo); + } else { + // 删除旧版本插件,不管是不是p-n的,且清掉Dex和Native目录 + delete(curInfo); + } newInfo.setType(PluginInfo.TYPE_EXTRACTED); if (LogDebug.LOG) { @@ -368,8 +393,32 @@ public class PluginManagerServer { "; cur_ver=" + curInfo.getVersion() + "; update_ver=" + newInfo.getVersion()); } - curInfo.update(newInfo); - curInfo.setPendingUpdate(null); + if (covered) { + curInfo.setPendingCover(null); + } else { + curInfo.update(newInfo); + curInfo.setPendingUpdate(null); + } + } + + private void move(@NonNull PluginInfo curPi, @NonNull PluginInfo newPi) { + try { + FileUtils.copyFile(newPi.getApkFile(), curPi.getApkFile()); + FileUtils.copyFile(newPi.getDexFile(), curPi.getDexFile()); + FileUtils.copyFile(newPi.getNativeLibsDir(), curPi.getNativeLibsDir()); + } catch (IOException e) { + if (LogRelease.LOGR) { + e.printStackTrace(); + } + } finally { + try { + FileUtils.forceDelete(newPi.getApkFile().getParentFile()); + } catch (IOException e) { + if (LogRelease.LOGR) { + e.printStackTrace(); + } + } + } } private void delete(@NonNull PluginInfo pi) {