标签:
从DroidPlugin的官方文档中我们知道。
2 在AndroidManifest.xml中使用插件的com.morgoo.droidplugin.PluginApplication:
或者在自定义的Application的onCreate()函数中,调用PluginHelper.getInstance().applicationOnCreate(getBaseContext());
在Application的attachBaseContext()函数中,调用
PluginHelper.getInstance().applicationAttachBaseContext(base);
接下来就先分析PluginHelper.applicationOnCreate();
第一步PluginHelper.applicationOnCreate();
public void applicationOnCreate(final Context baseContext) {
mContext = baseContext;
initPlugin(baseContext);
}
这个函数比较简单,只是保存传入的Context对象,然后调用PluginHelper的initPlugin这个函数。
第二步PluginHelper. initPlugin()函数如下:
private void initPlugin(Context baseContext) {
fixMiUiLbeSecurity();
PluginPatchManager.getInstance().init(baseContext);
PluginProcessManager.installHook(baseContext);
if (PluginProcessManager.isPluginProcess(baseContext)) {
PluginProcessManager.setHookEnable(true);
} else {
PluginProcessManager.setHookEnable(false);
}
PluginManager.getInstance().addServiceConnection(PluginHelper.this);
PluginManager.getInstance().init(baseContext);
}
A 适配小米系统 fixMiUiLbeSecurity
首先调用fixMiUiLbeSecurity函数如下:
//解决小米JLB22.0 4.1.1系统自带的小米安全中心(lbe.security.miui)广告拦截组件导致的插件白屏问题
private void fixMiUiLbeSecurity(){
//卸载掉LBE安全的ApplicationLoaders.mLoaders钩子
Class ApplicationLoaders = Class.forName("android.app.ApplicationLoaders");
Object applicationLoaders = MethodUtils.invokeStaticMethod(ApplicationLoaders, "getDefault");
Object mLoaders = FieldUtils.readField(applicationLoaders, "mLoaders", true);
if (mLoaders instanceof HashMap) {
HashMap oldValue = ((HashMap) mLoaders);
if ("com.lbe.security.client.ClientContainer$MonitoredLoaderMap".equals(mLoaders.getClass().getName())) {
HashMap value = new HashMap();
value.putAll(oldValue);
FieldUtils.writeField(applicationLoaders, "mLoaders", value, true);
}
}
//卸载掉LBE安全的ActivityThread.mPackages钩子
Object currentActivityThread = ActivityThreadCompat.currentActivityThread();
Object mPackages = FieldUtils.readField(currentActivityThread, "mPackages", true);
if (mPackages instanceof HashMap) {
HashMap oldValue = ((HashMap) mPackages);
if ("com.lbe.security.client.ClientContainer$MonitoredPackageMap".equals(mPackages.getClass().getName())) {
HashMap value = new HashMap();
value.putAll(oldValue);
FieldUtils.writeField(currentActivityThread, "mPackages", value, true);
}
}
//当前已经处在主线程消息队列中的所有消息,找出lbe消息并remove之
if (Looper.getMainLooper() == Looper.myLooper()) {
final MessageQueue queue = Looper.myQueue();
Object mMessages = FieldUtils.readField(queue, "mMessages", true);
if (mMessages instanceof Message) {
findLbeMessageAndRemoveIt((Message) mMessages);
}
}
其实这个函数的作用注释已经说得非常清楚了,小米某一款手机自带了一款Lbe的安全软件,
而这个软件内部自定义MonitoredLoaderMap类应该是继承自Map类,替换了ApplicationLoaders类中的原本的成员变量mLoaders来管理Android系统中的应用程序的类加载器。LoadedApk内一个成员变量mClassLoader就是通过ApplicationLoaders来创建的。这里卸载掉钩子就是把mLoaders替换成原生的HashMap对象。
另外一个类MonitoredPackageMap替换了ActivityThread中原本的mPackages对象,mPackages是HashMap类对象以应用报名为key,LoadedApk对象实例为Value。这里卸掉钩子也就是把mPackages对象替换成原生的HashMap对象。
在Activity启动过程中,我们的插件Activity实例化,就是通过预先把插件Apk包名对应的LoadedApk对象保存到ActivityThread的成员变量mPackages中,顺便用PluginClassLoader 替换LoadedApk中的mClassLoader.这样PluginClassLoader就可以加载插件中的类了。(这里会在插件Activity启动中详细分析)
也许是因为影响到了插件Activity的启动过程,所以需要处理一下。
最后把主线程里面所有lbe的消息都删除。
B 插件异常处理PluginPatchManager.getInstance().init()
public void init(Context context){
mContext = context;
}
这个初始化就是把context保存到PluginPatchManager的成员变量mContext中,这里保存Context对象主要就是为了延迟启动插件Activity。这个类主要是在启动插件Activity过程中,会调用PluginPatchManager的函数canStartPluginActivity判断PluginManagerService这个插件管理服务是否已经启动,如果没有启动则会调用PluginPatchManager的函数startPluginActivity延迟启动插件Activity等待PluginManagerService启动完成。后面会在Activity相关文章中分析。
C 初始化Hook系统插件需要用到的相关服务
PluginProcessManager.installHook(baseContext);
这个函数主要是调用HookFactory.getInstance().installHook(hostContext, null); Hook系统相关服务。(Hook的过程稍后会详细分析)
D 宿主进程关闭hook开关等待PluginManagerService启动后在打开
if (PluginProcessManager.isPluginProcess(baseContext)) {
PluginProcessManager.setHookEnable(true);
} else {
PluginProcessManager.setHookEnable(false);
}
通过PluginProcessManager.isPluginProcess判断,如果是插件进程则打开Hook开关,如果是宿主进程暂时关闭Hook开关。它会等到PluginManagerService启动完成后,再打开Hook开关。
PluginProcessManager.isPluginProcess函数如下:
public static final boolean isPluginProcess(Context context) {
String currentProcessName = getCurrentProcessName(context);
if (TextUtils.equals(currentProcessName, context.getPackageName()))
return false;
initProcessList(context);
return !sProcessList.contains(currentProcessName);
}
首先获取当前进程的名字再判断是否和宿主进程包名相同,如果相同说明不是插件进程。如果不同还需要继续判断,是否是宿主应用开出的其他进程(除去DroidPlugin为插件预定义了N个进程)initProcessList就会把宿主应用开出的其他进程保存在sProcessList。
在这里为什么如果是宿主进程需要先关闭Hook?因为Hook主要是为了瞒过系统保证插件Apk在未安装的情况下也能正常运行, PluginManagerService还没有启动的时候,已经安装的插件Apk是还没有装载进来的。另外,如果是在插件进程中,那么Hook完成之后可以直接打开Hook开关,因为PluginManagerService是运行在宿主进程中的。
E 注册服务连接Callback启动PluginManagerService
PluginManager.getInstance().addServiceConnection(PluginHelper.this);
PluginManager.getInstance().init(baseContext);
首先注册服务连接,等待服务启动完成后,调用PluginProcessManager.setHookEnable(true)函数打开Hook开关。
然后调用PluginManager的init函数,这个函数主要就是启动PluginManagerService。
F 启动PluginManagerService初始化IPluginManagerImpl对象。
PluginManagerService的onCreate函数。
public void onCreate() {
keepAlive();
mPluginPackageManager = new IPluginManagerImpl(this);
mPluginPackageManager.onCreate();
}
首先提升service所在进程优先级。
创建IPluginManagerImpl对象, IPluginManagerImpl的构造函数比较简单,只是创建了一个MyActivityManagerService 对象,他主要是用于插件进程管理的。
接着调用IPluginManagerImpl的onCreate函数。
onCreate函数中主要是启动一个线程,运行onCreateInner函数。
G 加载已经安装的插件,获取宿主进程申明的权限
private void onCreateInner() {
loadAllPlugin(mContext);
loadHostRequestedPermission();
mHasLoadedOk.set(true);
synchronized (mLock) {
mLock.notifyAll();
}
}
函数loadAllPlugin()主要是从/data/data/com.HOST.PACKAGE/Plugin目录下面找到已经安装的插件包,创建PluginPackageParser对象并缓存,然后缓存签名。这些基本都在DroidPlugin源码分析安装和卸载中有分析。
函数loadHostRequestedPermission()主要是搜集宿主进程的申明的权限信息。
H 创建并保存IPluginManagerImpl Proxy对象,创建线程,等待IPluginManagerImpl初始化完成后,分发服务连接成功监听,注册服务死亡回调。
public void onServiceConnected(final ComponentName componentName, final IBinder iBinder) {
mPluginManager = IPluginManager.Stub.asInterface(iBinder);
new Thread() {
@Override
public void run() {
mPluginManager.waitForReady();
mPluginManager.registerApplicationCallback(new IApplicationCallback.Stub() {
@Override
public Bundle onCallback(Bundle extra) throws RemoteException {
return extra;
}
});
Iterator<WeakReference<ServiceConnection>> iterator = sServiceConnection.iterator();
while (iterator.hasNext()) {
WeakReference<ServiceConnection> wsc = iterator.next();
ServiceConnection sc = wsc != null ? wsc.get() : null;
if (sc != null) {
sc.onServiceConnected(componentName, iBinder);
} else {
iterator.remove();
}
}
mPluginManager.asBinder().linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
onServiceDisconnected(componentName);
}
}, 0);
}
}
}.start();
}
函数首先保存IPluginManagerImpl Proxy 对象到mPluginManger中,
然后调用mPluginManager.waitForReady()查询服务是否初始化完成,如果没有完成则等待。
完成后,则分发这服务连接成功监听。在E步中收到服务连接成功回调,设置hook开关为True。
最后注册Binder死亡毁掉,当IPluginManagerImpl本地binder对象销毁时,我们会收到Binder死亡通知,然后在通知中重新启动PluginManagerService。
第三步:在Application的attachBaseContext()函数中,调用
PluginHelper.getInstance().applicationAttachBaseContext(base)
public void applicationAttachBaseContext(Context baseContext) {
MyCrashHandler.getInstance().register(baseContext);
}
这个函数主要是注册一个UncaughtExceptionHandler在应用异常退出时,保存Crash异常信息。
到此插件运行环境初始化过程结束,总结一下:
由此我们可以知道PluginManagerService主要职责,装载已经安装的插件Apk,插件Apk的安装和卸载,插件Apk信息的查询,以及插件进程管理等。
下一篇博客我们再来分析,Hook初始化过程。
标签:
原文地址:http://blog.csdn.net/zhangyawen1i/article/details/52001803