Skip to content

Commit

Permalink
Merge pull request #633 from Qihoo360/dev
Browse files Browse the repository at this point in the history
merge dev to master
  • Loading branch information
bnotebook authored Aug 9, 2018
2 parents eb3ebba + 9867a55 commit a980368
Show file tree
Hide file tree
Showing 18 changed files with 200 additions and 118 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
</p>

[![license](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/Qihoo360/RePlugin/blob/master/LICENSE)
[![Release Version](https://img.shields.io/badge/release-2.2.4-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/wiki/%E5%8F%91%E8%A1%8C%E6%B3%A8%E8%AE%B0)
[![Release Version](https://img.shields.io/badge/release-2.2.4-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/releases)



## RePlugin —— A flexible, stable, easy-to-use Android Plug-in Framework
Expand Down
26 changes: 24 additions & 2 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
</p>

[![license](http://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/Qihoo360/RePlugin/blob/master/LICENSE)
[![Release Version](https://img.shields.io/badge/release-2.2.4-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/wiki/%E5%8F%91%E8%A1%8C%E6%B3%A8%E8%AE%B0)

[![Release Version](https://img.shields.io/badge/release-2.2.4-brightgreen.svg)](https://github.com/Qihoo360/RePlugin/releases)



## RePlugin —— 历经三年多考验,数亿设备使用的,稳定占坑类插件化方案
Expand Down Expand Up @@ -81,6 +83,26 @@ RePlugin的使用方法非常简单,大部分情况下和“单品”开发无

若您在接入RePlugin中**遇到了任何问题,则[请点击这里阅读《FAQ》](https://github.com/Qihoo360/RePlugin/wiki/FAQ)**,相信会有您想要的答案。

## 插件管理服务—与RePlugin配套的插件管理、下发、统计服务

至今为止有数不清的用户联系我们让做配套的插件管理功能,所以 RePlugin 团队联合 360 Web 平台部,合力推出 RePlugin 插件管理服务,再次大幅降低了用户使用RePlugin的门槛,插件管理服务功能介绍如下:

* **插件版本管理**:对APK插件包名、别名和版本号的交集限制,防止下发出错。

* **打点统计**:上报即显示下发量、下载量、安装量和错误量数据。

* **升版管理**:严格要求用户新建下发任务为面向虚拟用户或部分真实用户的“测试版”下发任务(适用于内测、AB和灰度),测试没问题以后才能切换到面对所有真实用户的“线上版”下发任务,防止出错。

* **下发限速**:开发者可自定义自己想要的插件下发速度。

* **运营商和厂商限制**:开发者可自定义自己想下发的运营商和目标终端厂商。

* **灵活的下发条件设置**:根据用户群体对下发条件的要求程度,我们提供了4种条件设置功能,对下发条件要求不高的用户可直接使用便捷条件下发(包括按人数和指定设备下发);对下发条件要求高的用户可使用自定义条件下发(包括文字条件编辑器和代码条件编辑器)。

**PS**:我们原创的文字版条件编辑器很有意思哦,它能将复杂繁琐的条件代码还原成有语法有逻辑的中国话,真的是能让非技术人员第一次使用就看得懂会操作的优秀功能,目前为止我们应该是第一个将体验做到如此细腻的产品。

使用地址:[360移动开发者-RePlugin插件管理](https://dc.360.cn/)

## 已接入RePlugin的应用

我们诚挚期待您成为咱们RePlugin应用大家庭中的一员!
Expand Down Expand Up @@ -158,7 +180,7 @@ RePlugin的使用方法非常简单,大部分情况下和“单品”开发无

微信群已超过上限,请进入我们的QQ群

QQ群:**653205923**
QQ群 1**653205923** QQ群 2:**589652294**

## License

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ package com.qihoo360.replugin.gradle.host
class AppConstant {

/** 版本号 */
def static final VER = "2.2.4"
def static final VER = "2.3.0"

/** 打印信息时候的前缀 */
def static final TAG = "< replugin-host-v${VER} >"
Expand Down
4 changes: 3 additions & 1 deletion replugin-host-library/replugin-host-lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
*/
apply plugin: 'com.android.library'

version = "2.2.4"

version = "2.3.0"

group = 'com.qihoo360.replugin' // 组名

android {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,81 +18,20 @@

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Build;
import android.util.DisplayMetrics;

import com.qihoo360.replugin.helper.LogDebug;
import com.qihoo360.replugin.utils.ReflectUtils;

import java.io.File;

import static com.qihoo360.replugin.helper.LogDebug.LOG;
import static com.qihoo360.replugin.helper.LogDebug.MISC_TAG;

/**
* @author RePlugin Team
*/
public class PackageUtils {

/**
* @param archiveFilePath
* @return
*/
private static final Signature[] getPackageArchiveSignaturesInfoAndroid2x(String archiveFilePath) {
//
try {
// 1. 新建PackageParser的实例
Object packageParser = ReflectUtils.invokeConstructor(ReflectUtils.getClass("android.content.pm.PackageParser"),
new Class[]{String.class}, archiveFilePath);

// 2. 调用PackageParser.parsePackage()方法,返回值为Package对象
DisplayMetrics metrics = new DisplayMetrics();
metrics.setToDefaults();

Object pkg = ReflectUtils.invokeMethod(packageParser, "parsePackage", new Class[]{File.class, String.class, DisplayMetrics.class, int.class},
new File(archiveFilePath), archiveFilePath, metrics, 0);
if (pkg == null) {
if (LOG) {
LogDebug.d(MISC_TAG, "failed to parsePackage: f=" + archiveFilePath);
}
return null;
}

// 3. 调用PackageParser.collectCertificates方法
boolean rc = (Boolean) ReflectUtils.invokeMethod(packageParser, "collectCertificates", new Class[]{pkg.getClass(), int.class},
pkg, 0);
if (!rc) {
return null;
}

// 4. 获取Package.mSignatures
Object signatures[] = (Object[]) ReflectUtils.readField(pkg, "mSignatures");
int n = signatures.length;
if (n <= 0) {
if (LOG) {
LogDebug.d(MISC_TAG, "not found signatures: f=" + archiveFilePath);
}
}
if (n > 0) {
if (LOG) {
LogDebug.d(MISC_TAG, "found signatures for android 2.x: length=" + signatures.length);
}
Signature[] a = new Signature[n];
System.arraycopy(signatures, 0, a, 0, n);
return a;
}
} catch (Throwable e) {
if (LOG) {
LogDebug.d(MISC_TAG, e.getMessage(), e);
}
}
return null;
}

/**
* 获取PackageInfo对象
* 该方法解决了Android 2.x环境不能获取签名的系统问题,故可以“全面使用”
* <p>
* 注:getPackageArchiveInfo Android 2.x上,可能拿不到signatures,本可以通过反射去获取,但是考虑到会触发Android 的灰/黑名单,这个方法就不再继续适配2.X了
*
* @return
*/
public static PackageInfo getPackageArchiveInfo(PackageManager pm, String pkgFilePath, int flags) {
PackageInfo info = null;
Expand All @@ -104,20 +43,6 @@ public static PackageInfo getPackageArchiveInfo(PackageManager pm, String pkgFil
}
}

if (info == null) {
return null;
}

// Android 2.x的系统通过常规手段(pm.getPackageArchiveInfo)时会返回null,只能通过底层实现
// 判断依据:1、想要签名;2、没拿到签名;3、Android 4.0以前
if ((flags & PackageManager.GET_SIGNATURES) != 0) {
if (info.signatures == null) {
if (Build.VERSION.SDK_INT < 14) {
info.signatures = getPackageArchiveSignaturesInfoAndroid2x(pkgFilePath);
}
}
}

return info;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import com.qihoo360.replugin.helper.LogDebug;
import com.qihoo360.replugin.model.PluginInfo;

import com.qihoo360.replugin.utils.FileUtils;

import java.io.File;
Expand Down Expand Up @@ -275,6 +274,10 @@ private static void deleteUnknownDexs(Context context, PxAll all) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "can't delete unknown dex=" + f.getAbsolutePath(), e);
}
} catch (IllegalArgumentException e2) {
if (LOG) {
e2.printStackTrace();
}
}
}
}
Expand Down Expand Up @@ -302,6 +305,10 @@ private static void deleteUnknownLibs(Context context, PxAll all) {
if (LOG) {
LogDebug.d(PLUGIN_TAG, "can't delete unknown libs=" + f.getAbsolutePath(), e);
}
} catch (IllegalArgumentException e2) {
if (LOG) {
e2.printStackTrace();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@
import com.qihoo360.replugin.helper.LogDebug;
import com.qihoo360.replugin.helper.LogRelease;
import com.qihoo360.replugin.model.PluginInfo;
import com.qihoo360.replugin.packages.PluginManagerProxy;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.qihoo360.replugin.helper.LogDebug.LOG;
import static com.qihoo360.replugin.helper.LogDebug.MAIN_TAG;
Expand Down Expand Up @@ -313,21 +314,29 @@ public static final boolean pluginExtracted(String path) {

/**
* 获取当前所有插件信息快照。内部框架使用
*
* @param clone true:深拷贝 false:浅拷贝
* @return
*/
public static final List<PluginInfo> getPlugins(boolean clone) {
ArrayList<PluginInfo> array = new ArrayList<PluginInfo>();
ArrayList<PluginInfo> array = new ArrayList<>();
Set<String> pathSet = new HashSet<>();

synchronized (PluginTable.PLUGINS) {
for (PluginInfo info : PluginTable.PLUGINS.values()) {
PluginInfo addTo;
if (clone) {
addTo = (PluginInfo) info.clone();
} else {
addTo = info;
}
String path = info.getPath();

// 避免加了两次,毕竟包名和别名都会加进来
if (!array.contains(addTo)) {
if (!pathSet.contains(path)) {
pathSet.add(path);

PluginInfo addTo;
if (clone) {
addTo = (PluginInfo) info.clone();
} else {
addTo = info;
}

array.add(addTo);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import com.qihoo360.i.IModule;
import com.qihoo360.i.IPlugin;
import com.qihoo360.replugin.utils.AssetsUtils;
import com.qihoo360.loader.utils.ProcessLocker;
import com.qihoo360.mobilesafe.api.Tasks;
import com.qihoo360.replugin.RePlugin;
Expand All @@ -38,6 +37,7 @@
import com.qihoo360.replugin.helper.LogRelease;
import com.qihoo360.replugin.model.PluginInfo;
import com.qihoo360.replugin.packages.PluginManagerProxy;
import com.qihoo360.replugin.utils.AssetsUtils;
import com.qihoo360.replugin.utils.FileUtils;

import java.io.File;
Expand Down Expand Up @@ -664,8 +664,7 @@ private boolean loadLocked(int load, boolean useCache) {
LogRelease.w(PLUGIN_TAG, logTag + ": failed to lock: can't wait plugin ready");
}
}
// 清空数据对象
mLoader = null;

// 删除优化dex文件
File odex = mInfo.getDexFile();
if (odex.exists()) {
Expand All @@ -682,11 +681,14 @@ private boolean loadLocked(int load, boolean useCache) {
FileUtils.forceDelete(mInfo.getExtraOdexDir());
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e2) {
e2.printStackTrace();
}
}

t1 = System.currentTimeMillis();
rc = doLoad(logTag, context, parent, manager, load);
// 尝试再次加载该插件
rc = tryLoadAgain(logTag, context, parent, manager, load);
if (LOG) {
LogDebug.i(PLUGIN_TAG, "load2 " + mInfo.getPath() + " " + hashCode() + " c=" + load + " rc=" + rc + " delta=" + (System.currentTimeMillis() - t1));
}
Expand Down Expand Up @@ -735,6 +737,14 @@ final IBinder query(String binder) {
return null;
}

/**
* 抽出方法,将mLoader设置为null与doload中mLoader的使用添加同步锁,解决在多线程下导致mLoader为空指针的问题。
*/
private synchronized boolean tryLoadAgain(String tag, Context context, ClassLoader parent, PluginCommImpl manager, int load) {
mLoader = null;
return doLoad(tag, context, parent, manager, load);
}

private final boolean doLoad(String tag, Context context, ClassLoader parent, PluginCommImpl manager, int load) {
if (mLoader == null) {
// 试图释放文件
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.text.TextUtils;
import android.util.Log;

import com.qihoo360.replugin.helper.LogRelease;
import com.qihoo360.replugin.utils.CloseableUtils;
import com.qihoo360.mobilesafe.core.BuildConfig;
import com.qihoo360.replugin.helper.LogDebug;
Expand Down Expand Up @@ -112,6 +113,10 @@ public static void clear(File nativeDir) {
} catch (IOException e) {
// IOException:有可能是IO,如权限出现问题等,打出日志
e.printStackTrace();
} catch (IllegalArgumentException e2) {
if (LogRelease.LOGR) {
e2.printStackTrace();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public class PluginDexClassLoader extends DexClassLoader {

private static Method sLoadClassMethod;

private String mPluginName;

/**
* 初始化插件的DexClassLoader的构造函数。插件化框架会调用此函数。
*
Expand All @@ -70,6 +72,8 @@ public class PluginDexClassLoader extends DexClassLoader {
public PluginDexClassLoader(PluginInfo pi, String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) {
super(dexPath, optimizedDirectory, librarySearchPath, parent);

mPluginName = pi.getName();

installMultiDexesBeforeLollipop(pi, dexPath, parent);

mHostClassLoader = RePluginInternal.getAppClassLoader();
Expand Down Expand Up @@ -104,6 +108,23 @@ protected Class<?> loadClass(String className, boolean resolve) throws ClassNotF
} catch (ClassNotFoundException e) {
// Do not throw "e" now
cnfException = e;

if (PluginDexClassLoaderPatch.need2LoadFromHost(className)) {
try {
return loadClassFromHost(className, resolve);
} catch (ClassNotFoundException e1) {
// Do not throw "e1" now
cnfException = e1;

if (LogDebug.LOG) {
LogDebug.e(TAG, "loadClass ClassNotFoundException, from HostClassLoader&&PluginClassLoader, cn=" + className + ", pluginName=" + mPluginName);
}
}
} else {
if (LogDebug.LOG) {
LogDebug.e(TAG, "loadClass ClassNotFoundException, from PluginClassLoader, cn=" + className + ", pluginName=" + mPluginName);
}
}
}

// 若插件里没有此类,则会从宿主ClassLoader中找,找到了则直接返回
Expand Down
Loading

0 comments on commit a980368

Please sign in to comment.