转载请标明出处:【顾林海的博客】 <http://blog.csdn.net/hai_qing_xu_kong?viewmode=list>
本篇文章已授权微信公众号 顾林海 独家发布


Service插件化的重点是保证它的优先级,需要一个真正的Service来实现,当启动插件Service时,就会先启动代理Service,当这个代理Service运行起来后,在它的onStartCommand等方法里面进行分发,执行插件Service的onCreate等方法,这种方案叫代理分发。




也就是在启动插件Service时替换为代理Service,什么时候替换?通过startService方法启动Service会调用ContextWrapper的startService方法,如下所示:
//路径:/frameworks/base/core/java/android/content/ContextWrapper.java public
class ContextWrapper extends Context { Context mBase; ... @Override public
ComponentNamestartService(Intent service) { return mBase.startService(service);
} ... }

在ContextWrapper的startService方法中调用mBase的startService方法,mBase的类型是Context,而Context是一个抽象类,内部定义了很多方法以及静态常量,它的具体实现类是ContextImpl,进入ContextImpl的startService方法:
//路径:/frameworks/base/core/java/android/app/ContextImpl.java @Override public
ComponentNamestartService(Intent service) { warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser); }
ContextImpl的startService方法中又调用了startServiceCommon方法:
//路径:/frameworks/base/core/java/android/app/ContextImpl.java private
ComponentNamestartServiceCommon(Intent service, boolean requireForeground,
UserHandle user) { try { validateServiceIntent(service); service.
prepareToLeaveProcess(this); //注释1 ComponentName cn = ActivityManager.getService
().startService( mMainThread.getApplicationThread(), service, service.
resolveTypeIfNeeded( getContentResolver()), requireForeground, getOpPackageName(
), user.getIdentifier()); ... return cn; } catch (RemoteException e) { throw e.
rethrowFromSystemServer(); } }

注释1处通过ActivityManager的getService方法获取ActivityManagerService的代理类IActivityManager,进入ActivityManager的getService方法:
//路径:/frameworks/base/core/java/android/app/ActivityManager.java public static
IActivityManagergetService() { return IActivityManagerSingleton.get(); } private
static final Singleton<IActivityManager> IActivityManagerSingleton = new
Singleton<IActivityManager>() { @Override protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final
IActivityManager am= IActivityManager.Stub.asInterface(b); return am; } };

getService方法通过IActivityManagerSingleton的get方法获取IActivityManager对象,IActivityManagerSingleton是一个单例类,在create方法中从ServiceManager中获取一个名叫“activity”的Service引用,同时也是IBinder类型的ActivityManagerService的引用,最后通过IActivityManager.Stub.asInterface方法将它转换成IActivityManager,看到IActivityManager.Stub.asInterface这段代码时可以知道这里采用的是AIDL方式来实现进程间通信,也就是说服务端ActivityManagerService会实现IActivityManager.Stub类并实现相应的方法。

继续回到ContextImpl的startServiceCommon方法:
//路径:/frameworks/base/core/java/android/app/ContextImpl.java private
ComponentNamestartServiceCommon(Intent service, boolean requireForeground,
UserHandle user) { try { validateServiceIntent(service); service.
prepareToLeaveProcess(this); //注释1 ComponentName cn = ActivityManager.getService
().startService( mMainThread.getApplicationThread(), service, service.
resolveTypeIfNeeded( getContentResolver()), requireForeground, getOpPackageName(
), user.getIdentifier()); ... return cn; } catch (RemoteException e) { throw e.
rethrowFromSystemServer(); } }

在注释1处获取到ActivityManagerService的代理类IActivityManager,接着通过这个代理类向ActivityManagerService发送startService的消息。

将上面的知识点进行总结,如下图所示:



替换代理Service可以通过Hook IActivityManager生成动态代理类来实现。

Service插件化需要一个真正的Service来实现,先在AndroidManifest.xml中注册代理ProxyService:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="
com.book.demo"> ... <application ...> ... <service android:name=".ProxyService"
/> </application> </manifest>
接着启动插件Service:
public class MainActivity extends AppCompatActivity { private Button mBtnNormal
; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(
savedInstanceState); setContentView(R.layout.activity_main); initViews();
initEvent(); } private void initViews(){ mBtnNormal=findViewById(R.id.btn_normal
); } private void initEvent(){ mBtnNormal.setOnClickListener(new View.
OnClickListener() { @Override public void onClick(View v) { Intent intent=new
Intent(MainActivity.this,TargetService.class); startService(intent); } }); } }
这个TargetService用来模拟插件Service,不能够直接启动,因此需要Hook
IActivityManager,定义替换IActivityManager的代理类IActivityManagerProxy,代码如下:
public class IActivityManagerProxy implements InvocationHandler { private
Object mActivityManager; public IActivityManagerProxy(Object activityManager){
this.mActivityManager=activityManager; } @Override public Object invoke(Object
proxy, Method method, Object[] args) throws Throwable { if("startService".equals
(method.getName())){ Intent intent=null; int index=0; for(int i=0,length=args.
length;i<length;i++){ if(args[i] instanceof Intent){ index=i; break; } } intent=
(Intent) args[index]; Intent proxyIntent=new Intent(); String packageName=
"com.book.demo"; proxyIntent.setClassName(packageName,packageName+
".ProxyService"); //将插件Service的ClassName保存起来 proxyIntent.putExtra(
"TARGET_SERVICE",intent.getComponent().getClassName()); //替换为新建的proxyIntent args
[index]=proxyIntent; } return method.invoke(mActivityManager,args); } }

上述代码中通过拦截startService方法,获取启动TargetService的Intent,再创建代理Service的Intent,将TargetService的Intent的相关信息保存在代理Service的Intent中,最后将启动的Intent替换成代理Service的Intent,也就是说最后启动的是ProxyService。

接着用IActivityManagerProxy替换系统的IActivityManager,代码如下:
public class HookUtil { public static void hookAMS() { Object defaultSingleton
= null; try { if (Build.VERSION.SDK_INT >= 26) { Class<?> activityManagerClass =
Class.forName("android.app.ActivityManager"); Field field=activityManagerClass.
getDeclaredField("IActivityManagerSingleton"); field.setAccessible(true);
defaultSingleton=field.get(null); } else { Class<?> activityManagerNativeClass=
Class.forName("android.app.ActivityManagerNative"); Field field=
activityManagerNativeClass.getDeclaredField("gDefault"); field.setAccessible(
true); defaultSingleton=field.get(null); } Class<?> singletonClass=Class.forName
("android.util.Singleton"); Field mInstanceField=singletonClass.getDeclaredField
("mInstance"); mInstanceField.setAccessible(true); //获取IActivityManager Object
iActivityManager=mInstanceField.get(defaultSingleton); Class<?>
iActivityManagerClazz=Class.forName("android.app.IActivityManager"); Object
proxy=Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new
Class<?>[]{iActivityManagerClazz},new IActivityManagerProxy(iActivityManager));
mInstanceField.set(defaultSingleton,proxy); } catch (ClassNotFoundException e) {
e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); }
catch (IllegalAccessException e) { e.printStackTrace(); } } }
上述代码中主要做了这些事:

* 对版本进行区分,最终获取的是Singleton类型的IActivityManagerSingleton或者gDefault字段。
* 获取Singleton类中的mInstance字段并获取系统的IActivityManager。
* 创建代理类IActivityManagerProxy,来替换系统的IActivityManager。
接着在Application中调用这个方法:
public class MyApplication extends Application { @Override protected void
attachBaseContext(Context base) { super.attachBaseContext(base); HookUtil.
hookAMS(); } }
到这里启动的Service不是插件的Service,而是代理的Service,接下来需要在ProxyService中进行代理分发。
public class ProxyService extends Service { @Override public IBinder onBind(
Intent intent) { return null; } @Override public int onStartCommand(Intent
intent, int flags, int startId) { if (null == intent || !intent.hasExtra(
"TARGET_SERVICE")) { return START_STICKY; } String serviceName = intent.
getStringExtra("TARGET_SERVICE"); if (TextUtils.isEmpty(serviceName)) { return
START_STICKY; } //=============反射调用插件Service的attach方法===========================
try { //获取attach方法需要的ActivityThread Class activityThreadClazz = Class.forName(
"android.app.ActivityThread"); Field sCurrentActivityThread =
activityThreadClazz.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThread.setAccessible(true); Object activityThread =
sCurrentActivityThread.get(null); //获取attach方法需要的token Method
getActivityThreadMethod= activityThreadClazz.getDeclaredMethod(
"getApplicationThread"); getActivityThreadMethod.setAccessible(true); Object
applicationThread= getActivityThreadMethod.invoke(activityThread); Class
iInterfaceClazz = Class.forName("android.os.IInterface"); Method asBinderMethod
= iInterfaceClazz.getDeclaredMethod("asBinder"); asBinderMethod.setAccessible(
true); Object token = asBinderMethod.invoke(applicationThread); //反射获取attach方法
ClassserviceClazz = Class.forName("android.app.Service"); Method attachMethod =
serviceClazz.getDeclaredMethod("attach", Context.class, activityThreadClazz,
String.class, IBinder.class, Application.class, Object.class); attachMethod.
setAccessible(true); //获取IActivityManager Object defaultSingleton = null; if (
Build.VERSION.SDK_INT >= 26) { Class<?> activityManagerClass = Class.forName(
"android.app.ActivityManager"); Field field = activityManagerClass.
getDeclaredField("IActivityManagerSingleton"); field.setAccessible(true);
defaultSingleton= field.get(null); } else { Class<?> activityManagerNativeClass
= Class.forName("android.app.ActivityManagerNative"); Field field =
activityManagerNativeClass.getDeclaredField("gDefault"); field.setAccessible(
true); defaultSingleton = field.get(null); } Class<?> singletonClass = Class.
forName("android.util.Singleton"); Field mInstanceField = singletonClass.
getDeclaredField("mInstance"); mInstanceField.setAccessible(true); Object
iActivityManager= mInstanceField.get(defaultSingleton); //反射执行插件Service Service
targetService= (Service) Class.forName(serviceName).newInstance(); attachMethod.
invoke(targetService, this, activityThread, intent.getComponent().getClassName()
, token, getApplication(), iActivityManager);
//执行插件Service的onCreate、onStartCommand方法 targetService.onCreate(); targetService.
onStartCommand(intent,flags,startId); } catch (ClassNotFoundException e) { e.
printStackTrace(); return START_STICKY; } catch (NoSuchMethodException e) { e.
printStackTrace(); return START_STICKY; } catch (NoSuchFieldException e) { e.
printStackTrace(); return START_STICKY; } catch (IllegalAccessException e) { e.
printStackTrace(); return START_STICKY; } catch (InvocationTargetException e) {
e.printStackTrace(); return START_STICKY; } catch (InstantiationException e) { e
.printStackTrace(); return START_STICKY; } return START_STICKY; } }
上诉代码主要做了以下几件事:

* 判断参数条件不满足、出现异常和代码执行完毕返回START_STICKY,这样ProxyService会重新创建并执行onStartCommand方法。
* 创建插件Service,并反射调用attach方法。
* 进行代理分发,执行插件Service的onCreate和onStartCommand方法。
插件TargetService如下所示:
public class TargetService extends Service { @Override public IBinder onBind(
Intent intent) { return null; } @Override public void onCreate() { super.
onCreate(); Log.e("TargetService","----onCreate-----"); } @Override public int
onStartCommand(Intent intent, int flags, int startId) { Log.e("TargetService",
"----onStartCommand-----"); return super.onStartCommand(intent, flags, startId);
} }
运行看是否会在onCreate和onStartCommand方法中打印Log:


友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信