上一篇文章分析过DroidPlugin对Activity的处理过程,不得不为对DroidPlugin的工程师们钦佩不已,那么是不是Service可以像Activity的处理过程一样来处理呢?前面讲过每一个代理进程只是预定义了一个Service,如果某一个插件中有多个Service,那岂不是某一个时刻只能有一个Service运行呢?由此可以判定可能Service的处理和Activity不一样。
一方面:平时使用Activity主要是用于展示界面和用户交互,Activity的生命周期可能受用户控制,当用户操作界面进入新界面或返回界面时。也可能受系统控制,进入锁屏界面时,或者来电话时。也就是说Activity生命周期与用户和系统都是强关系。而Service呢?启动或停止,完全由我们主动控制,也就是说Service与用户和系统都是弱关系。所以我们完全可以无需经过系统手动调用Service的生命周期来让他运行。
另一方面:我们一直说Service是运行在后台提供服务的。其实正在提供服务的并不是Service,而是在Service内实例化的Binder本地对象。包括Service的生命周期也是为Binder本地对象服务的。也就是说我们可以在一个Service里面实例化多个Binder提供服务,说白了我们可以在一个Service里面通过手动控制Service生命周期运行多个Service。前提是我们需要对这些Service管理起来。
有了上面的理解,接下来就以StartService为例分析DroidPlugin对Service的处理。
StartService和StartActivity一样都是通过调用AMS代理对象请求AMS服务的。那么不多说了直接看分发Hook AMS的类IActivityManagerHookHandle的内部类startService的beforeInvoke函数。
在beforeInvoke函数中只是调用了replaceFirstServiceIntentOfArgs函数:
private static ServiceInfo replaceFirstServiceIntentOfArgs(Object[] args) throws RemoteException {
int intentOfArgIndex = findFirstIntentIndexInArgs(args);
if (args != null && args.length > 1 && intentOfArgIndex >= 0) {
Intent intent = (Intent) args[intentOfArgIndex];
ServiceInfo serviceInfo = resolveService(intent);
if (serviceInfo != null && isPackagePlugin(serviceInfo.packageName)) {
ServiceInfo proxyService = selectProxyService(intent);
if (proxyService != null) {
Intent newIntent = new Intent();
newIntent.setAction(proxyService.name + new Random().nextInt());
newIntent.setClassName(proxyService.packageName, proxyService.name);
newIntent.putExtra(Env.EXTRA_TARGET_INTENT, intent);
newIntent.setFlags(intent.getFlags());
args[intentOfArgIndex] = newIntent;
return serviceInfo;
}
}
}
return null;
}
分析过Activity的流程,这个函数就不难分析了:
主要工作如下:
1 从参数中找到Intent的位置,然后取出Intent对象,然后通过Intent对象获得对应的ServiceInfo对象。
2 判断 当前service 的包名是不是已近安装的插件apk包名。
3 选择一个合适的代理服务,来替换要启动的目标服务。选择的过程之前分析过Activity,Service的基本类似这里不做过多分析,这里需要特别说一下的就是选择的Service必然是继承自AbstractServiceStub。分析完这个函数再说AbstractServiceStub隐藏的秘密。
4 创建一个Intent,设置启动服务为代理服务,将目标服务保存到代理服务intent中。
5 把新创建的代理Intent替换原来参数Intent的位置。由此可以骗过系统检查。
至此,目标服务已经被代理服务所替代,AMS启动完毕后,就会调用代理服务的onCreate, onStart。
前面提到所有预定义的代理服务都是继承自AbstractServiceStub。接下来看隐藏的秘密。
AbstractServiceStub的onCreate函数
这个函数没有做太多的事情,只是设置isRunning 为True。
AbstractServiceStub的onStart函数如下:
public void onStart(Intent intent, int startId) {
try {
if (intent != null) {
if (intent.getBooleanExtra("ActionKillSelf", false)) {
startKillSelf();
if (!ServcesManager.getDefault().hasServiceRunning()) {
stopSelf(startId);
boolean stopService = getApplication().stopService(intent);
}
} else {
mCreator.onStart(this, intent, 0, startId);
}
}
} catch (Throwable e) {
handleException(e);
}
super.onStart(intent, startId);
}
这个函数主要做了如下工作:
是否记得在分析进程管理的时候当一个进程中Activity数为零,且Service数不为零是就会发送一个Intent 设置ActionKillSelf为True,查看是否存在插件Service在运行,如果没有则关闭Service,同时kill进程。
1 判断Intent中是否存在ActionKillSelf参数,且为True。
如果为True,先启动一个线程,然后等待服务Destory之后,再调用杀掉运行该服务的预定义插件进程。
2 判断是否还有插件服务在该进程中运行,如果有返回,如果没有则停止当前服务。这样自然就会调用该服务的onDestory函数,这样第一步的线程就会继续执行,然后停止该进程。
3 在StartService中,ActionKillSelf是没有的,则为false,因此会执行
mCreator.onStart(this, intent, 0, startId);这行代码。
mCreator是一个ServcesManager类对象。
接下来看ServcesManager的onStart函数。
public int onStart(Context context, Intent intent, int flags, int startId) throws Exception {
Intent targetIntent = intent.getParcelableExtra(Env.EXTRA_TARGET_INTENT);
if (targetIntent != null) {
ServiceInfo targetInfo = PluginManager.getInstance().resolveServiceInfo(targetIntent, 0);
if (targetInfo != null) {
Service service = mNameService.get(targetInfo.name);
if (service == null) {
handleCreateServiceOne(context, intent, targetInfo);
}
handleOnStartOne(targetIntent, flags, startId);
}
}
return -1;
}
这个函数主要做了如下工作:
1 通过intent 找到要启动的目标Intent。然后通过目标Intent找到目标服务的serviceInfo.
2 以目标服务的名字从mNameService查找要启动的目标服务是否已经启动。
3 如果没有启动则调用handleCreateServiceOne 创建该服务。
4如果目标服务已经缓存,说明已经启动了,或者在创建目标服务完成后,调用handleOnStartOne调用服务的onStart函数
先分析handleCreateServiceOne函数具体创建服务的过程
private void handleCreateServiceOne(Context hostContext, Intent stubIntent, ServiceInfo info) throws Exception {
ResolveInfo resolveInfo = hostContext.getPackageManager().resolveService(stubIntent, 0);
ServiceInfo stubInfo = resolveInfo != null ? resolveInfo.serviceInfo : null;
PluginManager.getInstance().reportMyProcessName(stubInfo.processName, info.processName, info.packageName);
PluginProcessManager.preLoadApk(hostContext, info);
Object activityThread = ActivityThreadCompat.currentActivityThread();
IBinder fakeToken = new MyFakeIBinder();
Class CreateServiceData = Class.forName(ActivityThreadCompat.activityThreadClass().getName() + "$CreateServiceData");
Constructor init = CreateServiceData.getDeclaredConstructor();
if (!init.isAccessible()) {
init.setAccessible(true);
}
Object data = init.newInstance();
FieldUtils.writeField(data, "token", fakeToken);
FieldUtils.writeField(data, "info", info);
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB) {
FieldUtils.writeField(data, "compatInfo", CompatibilityInfoCompat.DEFAULT_COMPATIBILITY_INFO());
}
Method method = activityThread.getClass().getDeclaredMethod("handleCreateService", CreateServiceData);
if (!method.isAccessible()) {
method.setAccessible(true);
}
method.invoke(activityThread, data);
Object mService = FieldUtils.readField(activityThread, "mServices");
Service service = (Service) MethodUtils.invokeMethod(mService, "get", fakeToken);
MethodUtils.invokeMethod(mService, "remove", fakeToken);
mTokenServices.put(fakeToken, service);
mNameService.put(info.name, service);
if (stubInfo != null) {
PluginManager.getInstance().onServiceCreated(stubInfo, info);
}
}
这个函数基本的工作如下:
1 先找到代理服务的ServiceInfo, 然后调用PluginManager.getInstance().reportMyProcessName(stubInfo.processName, info.processName, info.packageName); 关联包名和目标进程和代理进程信息,方便管理。在进程管理一文中分析过的。
2 PluginProcessManager.preLoadApk(hostContext, info) 设置LoadedApk,以及ClassLoader, 这个在插件对Activity的处理中已有分析。
3 通过查看源码可以了解如下信息,当启动一个服务,回到服务运行的应用空间来的时候(其实就是运行服务的进程中),创建服务的过程,是通过ActivityThread 的handleCreateService函数来创建的,同时在调用这个函数的时候需要传入CreateServiceData 数据类,在这个数据类中有一个iBinder对象,这个对象其实在ActivityManagerService中是一个ServiceRecord,主要用来记录一个服务信息的。当调用ActivityThread的函数handleCreateService创建服务完成之后,
A:会调用该服务的OnCreate函数。
B: 服务会以ServiceRecord 这个iBinder对象为Key Service对象为Value保存在ActivityThread的mService成员变量中。
有了这些了解以后,下面的代码主要完成如下工作:
4 目标服务实际是没有在ActivityManager中启动的,所以没有ServiceRecord对象,所以会先伪造一个IBinder对象MyFakeIBinder。
5 创建一个CreateServiceData 类对象。并把伪造的IBinder对象和目标ServiceInfo保存到该数据对象中。
6 调用ActivityThread函数handleCreateService创建目标服务对象。
7 从ActivityThread的成员变量mService中以前面伪造的IBinder对象为Key从里面取出刚刚创建的服务。
8 以伪造的IBinder对象和以目标服务类名为key分别保存到ServiceManager的成员变量mTokenServices和mNameService中。
9 调用PluginManager.getInstance().onServiceCreated(stubInfo, info);对刚刚启动的服务,和运行服务的进程进行管理。前面的进程管理的文章中已经有对Activity分析,Service基本类似。
handleOnStartOne调用Service的onStart函数的过程。
private void handleOnStartOne(Intent intent, int flags, int startIds) throws Exception {
ServiceInfo info = PluginManager.getInstance().resolveServiceInfo(intent, 0);
if (info != null) {
Service service = mNameService.get(info.name);
if (service != null) {
ClassLoader classLoader = getClassLoader(info.applicationInfo);
intent.setExtrasClassLoader(classLoader);
Object token = findTokenByService(service);
Integer integer = mServiceTaskIds.get(token);
if (integer == null) {
integer = -1;
}
int startId = integer + 1;
mServiceTaskIds.put(token, startId);
int res = service.onStartCommand(intent, flags, startId);
QueuedWorkCompat.waitToFinish();
}
}
}
这个函数主要的工作如下:
1 通过Intent找到ServiceInfo,然后通过ServiceINfo的name从mNameService中找到service.
获取ClassLoader 设置Intent的ClassLoader。
2 通过service找到Token,然后通过Token在mServiceTaskIds查看是否设置startId.
3 如果为空则以token为key设置startId为Value保存到ServiceManger成员变量mServiceTaskIds中。
4 最后调用service,onstartCommend函数。
5 调用QueuedWork.waittoFinish等待完成。
至此插件对Service的处理分析完成。
DroidPlugin对静态广播的处理:
在DroidPlugin的文档中已经说过了,他们对静态广播的处理是通过动态注册的方式来实现的。也就是说DroidPlugin只是解析了插件Apk AndroidManifest文件中的静态广播,进行动态注册。
具体注册过程是在调用Application onCreate函数的时候。
当LoadedApk调用makeApplication函数的时候,会调用instrumentation.callApplicationOnCreate,而instrumentation已经被PluginInstrumentation篡改。就在PluginInstrumentation的callApplicationOnCreate函数中。会调用PluginProcessManager.registerStaticReceiver。具体函数就比较简单了,大家可以自行查看。