很惋惜,Small
不支持Service
的插件化,可是在项目中咱们确实有这样的需求,那么就须要研究一下如何本身来实现Service
的插件化。在讨论如何实现Service
的插件化以前,必须有三点准备:android
Service
的基本知识,包括Service
的生命周期、如何启动和结束Service
,bindService
和startService
之间的区别和联系,这一部分就不过多介绍了,你们能够看一下 Carson_Ho 大神这篇文章,介绍的很全面 Android四大组件:Service服务史上最全面解析。Service
启动的内部原理,对源码进行一次简单的走读,主要是对Service
调用者、全部者以及AMS
之间的三方通讯有一个清晰的认识,你们能够看一下我以前写的这篇文章 Framework 源码解析知识梳理(5) - startService 源码分析。Retrofit
的时候也有介绍过,Retrofit 知识梳理(2) - Retrofit 动态代理内部实现。在 插件化知识梳理(6) - Small 源码分析之 Hook 原理 这篇文章中,咱们一块儿学习了如何实现Activity
的插件化,简单地来讲,实现原理就是:git
startActivity
启动插件Activity
后,经过替换mInstrumentation
成员变量,拦截这一启动过程,在后台偷偷地把startActivity
时传入的intent
中的component
替换成为在AndroidManifest.xml
中预先注册的占坑Activity
,再通知ActivityManagerService
。ActivityManagerService
完成调度后,有替换客户端中的ActivityThread
中的mH
中的mCallback
,将占坑的Activity
从新恢复成插件的Activity
。而Service
的插件化也能够采用相似的方式,大致的思路以下:github
startService
启动插件Service
时,经过拦截ActivityManagerProxy
的对应方法,将Intent
中的插件Service
类型替换成预先在AndroidManifest.xml
中预先注册好的占坑Service
。AMS
经过ApplicationThreadProxy
回调占坑Service
对应的生命周期时,咱们再在占坑Service
中的onStartCommand
中,去建立插件Service
的实例,若是是第一次建立,那么先调用它的onCreate
方法,再调用它的onStartCommand
方法,不然,就只调用onStartCommand
方法就能够了。stopService
中止插件Service
时,一样经过拦截ActivityManagerProxy
的对应方法,去调用插件Service
的onDestroy
,若是此时发现没有任何一个与占坑Service
关联的插件Service
运行时,那么就能够中止插件Service
了。传了一个简单的例子到仓库,你们能够简单地对照着看一下,下面,咱们开始分析具体的实现。bash
初始化的过程以下所示:app
public void setup(Context context) {
try {
//1.经过反射获取到ActivityManagerNative类。
Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(activityManagerNativeClass);
//2.获取mInstance变量。
Class<?> singleton = Class.forName("android.util.Singleton");
Field instanceField = singleton.getDeclaredField("mInstance");
instanceField.setAccessible(true);
//3.获取原始的对象。
Object original = instanceField.get(gDefault);
//4.动态代理,用于拦截Intent。
Class<?> iActivityManager = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(context.getClassLoader(), new Class[]{ iActivityManager }, new IActivityManagerInvocationHandler(original));
instanceField.set(gDefault, proxy);
//5.读取插件当中的Service。
loadService();
//6.占坑的Component。
mStubComponentName = new ComponentName(ServiceManagerApp.getAppContext().getPackageName(), StubService.class.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
这里最主要的就是作了两件事:框架
这里应用到了动态代理的知识,咱们用Proxy.newProxyInstance
所建立的proxy
对象,替代了ActivityManagerNative
中的gDefault
静态变量。在 Framework 源码解析知识梳理(1) - 应用程序与 AMS 的通讯实现 中,咱们分析过,它实际上是一个AMS
在应用程序进程中的代理类。经过这一替换过程,那么当调用ActivityManagerNative.getDefault()
方法时,就会先通过IActivityManagerInvocationHandler
类,咱们就能够根据invoke
所传入的方法名,在方法真正被调用以前插入一些本身的逻辑(也就是前文所说的,将启动插件Service
的Intent
替换成启动占坑Service
的Intent
),最后才会经过Binder
调用到达AMS
端,以此达到了“欺骗系统”的目的。ide
下面是InvocationHandler
的具体实现,构造函数中传入的是原始的ActivityManagerProxy
对象。函数
private class IActivityManagerInvocationHandler implements InvocationHandler {
private Object mOriginal;
public IActivityManagerInvocationHandler(Object original) {
mOriginal = original;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
switch (methodName) {
case "startService":
Intent matchIntent = null;
int matchIndex = 0;
for (Object object : args) {
if (object instanceof Intent) {
matchIntent = (Intent) object;
break;
}
matchIndex++;
}
if (matchIntent != null && ServiceManager.getInstance().isPlugService(matchIntent.getComponent())) {
Intent stubIntent = new Intent(matchIntent);
stubIntent.setComponent(getStubComponentName());
stubIntent.putExtra(KEY_ORIGINAL_INTENT, matchIntent);
//将插件的Service替换成占坑的Service。
args[matchIndex] = stubIntent;
}
break;
case "stopService":
Intent stubIntent = null;
int stubIndex = 0;
for (Object object : args) {
if (object instanceof Intent) {
stubIntent = (Intent) object;
break;
}
stubIndex++;
}
if (stubIntent != null) {
boolean destroy = onStopService(stubIntent);
if (destroy) {
//若是须要销毁占坑的Service,那么就替换掉Intent进行处理。
Intent destroyIntent = new Intent(stubIntent);
destroyIntent.setComponent(getStubComponentName());
args[stubIndex] = destroyIntent;
} else {
//因为在onStopService中已经手动调用了onDestroy,所以这里什么也不须要作,直接返回就能够。
return null;
}
}
break;
default:
break;
}
Log.d("ServiceManager", "call invoke, methodName=" + method.getName());
return method.invoke(mOriginal, args);
}
}
复制代码
先看startService
,args
参数中保存了startService
所传入的实参,这里面就包含了启动插件Service
的Intent
,咱们将目标Intent
的Component
替换成为占坑的Component
,而后将原始的Intent
保存在KEY_ORIGINAL_INTENT
字段当中,最后,经过原始的对象调用到ActivityManagerService
端。源码分析
这里其实就是用到了前面介绍的DexClassLoader
的知识,详细的能够看一下前面的这两篇文章 插件化知识梳理(7) - 类的动态加载入门,插件化知识梳理(8) - 类的动态加载源码分析。 最终,咱们会将插件Service
的Class
对象保存在一个mLoadServices
的Map
当中,它的Key
就是插件Service
的包名和类名。学习
private void loadService() {
try {
//从插件中加载Service类。
File dexOutputDir = ServiceManagerApp.getAppContext().getDir("dex2", 0);
String dexPath = Environment.getExternalStorageDirectory().toString() + PLUG_SERVICE_PATH;
DexClassLoader loader = new DexClassLoader(dexPath, dexOutputDir.getAbsolutePath(), null, ServiceManagerApp.getAppContext().getClassLoader());
try {
Class clz = loader.loadClass(PLUG_SERVICE_NAME);
mLoadedServices.put(new ComponentName(PLUG_SERVICE_PKG, PLUG_SERVICE_NAME), clz);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
接下来,在宿主中经过下面的方式启动插件Service
类:
public void startService(View view) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(ServiceManager.PLUG_SERVICE_PKG, ServiceManager.PLUG_SERVICE_NAME));
startService(intent);
}
复制代码
按照前面的分析,首先会走到咱们预设的“陷阱”当中,能够看到,这里面的Intent
仍是插件Service
的Component
名字:
Intent
就变成了占坑的
Service
。
Service
就会启动,依次调用它的
onCreate
和
onStartCommand
方法,咱们在
onStartCommand
中,再去回调插件
Service
对应的生命周期:
public class StubService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.d("StubService", "onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("StubService", "onStartCommand");
ServiceManager.getInstance().onStartCommand(intent, flags, startId);
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
ServiceManager.getInstance().onDestroy();
Log.d("StubService", "onDestroy");
}
}
复制代码
这里,咱们取出以前保存在KEY_ORIGINAL_INTENT
中原始的Intent
,经过它找到对应插件Service
的包名和类名,以此为key
,在mLoadedServices
中找到前面从插件apk
中加载的Service
类,并经过反射实例化该对象,若是是第一次建立,那么先执行它的onCreate
方法,并将它保存在mAliveServices
中,以后再执行它的onStartCommand
方法。
当咱们经过stopService
方法,中止插件Service
时,也会和前面相似,先走到拦截的逻辑当中:
onStop
方法中,咱们判断它是不是须要中止插件
Service
,若是是那么就调用插件
Service
的
onDestory()
方法,而且判断与占坑
Service
相关联的插件
Service
是否都已经结束了,若是是,那么就返回
true
,让占坑
Service
也销毁。
Service
的
Intent
替换成占坑
Service
:
以上,就是实现插件化Service
的核心思路,实现起来并不简单,须要涉及到不少的知识,这已是插件化学习的第十篇文章了。若是你们能一路看下来,能够发现,其实插件化并无什么神秘的地方,若是咱们但愿实现任意一个组件的插件化,无非就是如下几点:
ActivityManagerService
的交互过程,这也是最难的地方,要花不少的时间去看源码,并且各个版本的API
也可能有所差别。Hook
,动态代理之类的知识。掌握了以上几点,对于市面上大厂的插件框架基本可以看懂个六七成,可是对于大多数人而言,并无这么多的时间和条件,去分析一些细节问题。我写的这些文章,也只能算是入门水平,和你们一块儿学习基本的思想。真正核心的东西,仍是须要有机会能应用到生产环境中才能真正掌握。
很惋惜,我也没有这样的机会,感受天天工做的时间都是在调UI
、解Bug
、浪费时间,只能靠着晚上的时间,一点点摸索,写Demo
,哎,说出来都是泪,还有半年,继续加油吧!