Service Hook解析

来源:互联网 发布:镇江网络广播电视 编辑:程序博客网 时间:2024/06/05 20:49

4,Service Hook解析

Service/ContentProvider由于没有Activity那么复杂的启动过程,并且Activity的生命周期是由用户交互决定的,

而Service的声明周期是主动通过代码调用的。因此虽然也有替换/还原过程,但是有点不同,是采用代理分发技术。

就是启动宿主的Service/ContentProvider对象,然后管理插件的Service/ContentProvider对象。

Service 的Hook 是通过ActivityManagerProxy完成的。

ActivityManagerProxy类Hook了ActivityManager的7个方法,其中和service相关的有5个,分别是startService/ stopService/ 

stopServiceToken/bindService/ unbindService,这5个方法主要和service的生命周期有关。并且所有方法的调用流程

完全相同,因此,以startService方法为例来论述。

在AndroidManifest中注册了两类service,一类LocalService,多进程时为RemoteService,

<!-- Local Service running in main process --><service android:name="com.didi.virtualapk.delegate.LocalService" /><!-- Daemon Service running in child process --><service android:name="com.didi.virtualapk.delegate.RemoteService" android:process=":daemon">    <intent-filter>       <action android:name="${applicationId}.intent.ACTION_DAEMON_SERVICE" />    </intent-filter></service>

ActivityManagerProxy的invoke方法中有关startService处理的代码如下,

if ("startService".equals(method.getName())) {    try {        return startService(proxy, method, args);

startService方法如下,

private Object startService(Object proxy, Method method, Object[] args) throws Throwable {        IApplicationThread appThread = (IApplicationThread) args[0];        Intent target = (Intent) args[1];        ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);        if (null == resolveInfo || null == resolveInfo.serviceInfo) {            // is host service            return method.invoke(this.mActivityManager, args);        }        return startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);    }

首先调用PluginManager的resolveService方法匹配出目标intent的相关信息,然后调用startDelegateServiceForTarget方法进行替换.

4.1 匹配

PluginManager的resolveService方法流程图如下,


其实,和Activity的匹配过程完全相同。

PluginManager的resolveService方法如下,

public ResolveInfo resolveService(Intent intent, int flags) {     for (LoadedPlugin plugin : this.mPlugins.values()) {         ResolveInfo resolveInfo = plugin.resolveService(intent, flags);         if (null != resolveInfo) {            return resolveInfo;         }      }    return null;}

从mPlugins变量中逐个取出所有插件对应的LoadedPlugin对象,然后逐个进行intent匹配,

LoadedPlugin 的resolveService方法如下,

public ResolveInfo resolveService(Intent intent, int flags) {        List<ResolveInfo> query = this.queryIntentServices(intent, flags);        if (null == query || query.isEmpty()) {            return null;        }        ContentResolver resolver = this.mPluginContext.getContentResolver();        return chooseBestActivity(intent, intent.resolveTypeIfNeeded(resolver), flags, query);    }

首先调用queryIntentActivities方法匹配intent,完成之后调用chooseBestActivity选择最符合条件的那个对象。

LoadedPlugin的queryIntentServices方法如下,

ComponentName component = intent.getComponent();List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();ContentResolver resolver = this.mPluginContext.getContentResolver();for (PackageParser.Service service : this.mPackage.services) {    if (service.getComponentName().equals(component)) {        ResolveInfo resolveInfo = new ResolveInfo();        resolveInfo.serviceInfo = service.info;        resolveInfos.add(resolveInfo);    } else if (component == null) {        // only match implicit intent       for (PackageParser.ServiceIntentInfo intentInfo : service.intents) {            if (intentInfo.match(resolver, intent, true, TAG) >= 0) {                ResolveInfo resolveInfo = new ResolveInfo();                resolveInfo.serviceInfo = service.info;                resolveInfos.add(resolveInfo);                break;            }       }    }}

4.2 替换

ActivityManagerProxy的startDelegateServiceForTarget方法如下,

private ComponentName startDelegateServiceForTarget(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {    Intent wrapperIntent = wrapperTargetIntent(target, serviceInfo, extras, command);    return mPluginManager.getHostContext().startService(wrapperIntent);}

首先调用wrapperTargetIntent替换intent,然后调用startService启动替换后的intent。

wrapperTargetIntent方法如下,

private Intent wrapperTargetIntent(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {    // fill in service with ComponentName    target.setComponent(new ComponentName(serviceInfo.packageName, serviceInfo.name));    String pluginLocation = mPluginManager.getLoadedPlugin(target.getComponent()).getLocation();    // start delegate service to run plugin service inside    boolean local = PluginUtil.isLocalService(serviceInfo);    Class<? extends Service> delegate = local ? LocalService.class : RemoteService.class;    Intent intent = new Intent();    intent.setClass(mPluginManager.getHostContext(), delegate);    intent.putExtra(RemoteService.EXTRA_TARGET, target);    intent.putExtra(RemoteService.EXTRA_COMMAND, command);    intent.putExtra(RemoteService.EXTRA_PLUGIN_LOCATION, pluginLocation);    if (extras != null) {        intent.putExtras(extras);    }return intent;}

重新初始化了Intent,设置了目标类为LocalService(多进程时设置为RemoteService),

然后将原本的Intent存储到EXTRA_TARGET,携带command为EXTRA_COMMAND_START_SERVICE,以及插件apk路径。

4.3 代理分发

实际上启动的是LocalService和RemoteService, 并且RemoteService继承于LocalService, LocalService的

onStartCommand方法主要逻辑如下,

1,获取目标intent,

Intent target = intent.getParcelableExtra(EXTRA_TARGET);

2,判断intent所在的插件是否加载,如果没有加载,就加载该插件。

String pluginLocation = intent.getStringExtra(EXTRA_PLUGIN_LOCATION);ComponentName component = target.getComponent();LoadedPlugin plugin = PluginManager.getInstance(this).getLoadedPlugin(component);if (plugin == null && pluginLocation != null) {    try {        PluginManager.getInstance(this).loadPlugin(new File(pluginLocation));        •••

3,调用父类LocalService的onStartCommand方法,

return super.onStartCommand(intent, flags, startId);

其实代理分发的整个精华部分就在于LocalService的onStartCommand方法,该方法主要逻辑如下,

1,获取intent以及相关信息,

Intent target = intent.getParcelableExtra(EXTRA_TARGET);•••ComponentName component = target.getComponent();LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);

2,获取service生命周期的相关信息,

int command = intent.getIntExtra(EXTRA_COMMAND, 0);

3,根据intent以及周期的相关信息控制目标service。

switch (command) {   case EXTRA_COMMAND_START_SERVICE: {

那么,service周期信息是如何放入的呢?

在ActivityManagerProxy的这5个方法startService/ stopService/ stopServiceToken/bindService/ unbindService中,

都会调用startDelegateServiceForTarget方法将信息塞入intent中,

startService方法中调用startDelegateServiceForTarget方法如下,

startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);

stopService方法中调用startDelegateServiceForTarget方法如下,

startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_STOP_SERVICE);

stopServiceToken方法中调用startDelegateServiceForTarget方法如下,

startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_STOP_SERVICE);

bindService方法中调用startDelegateServiceForTarget方法如下,

startDelegateServiceForTarget(target, resolveInfo.serviceInfo, bundle, RemoteService.EXTRA_COMMAND_BIND_SERVICE);

unbindService方法中调用startDelegateServiceForTarget方法如下,

startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_UNBIND_SERVICE);

LocalService的onStartCommond方法中对这4类消息的处理流程和方法完全相同,

以EXTRA_COMMAND_START_SERVICE方法为例论述,主要逻辑如下,

1,利用反射获取进程的ActivityThread等信息,

ActivityThread mainThread = (ActivityThread)ReflectUtil.getActivityThread(getBaseContext());IApplicationThread appThread = mainThread.getApplicationThread();

2,判断目标service是否已启动,

if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {     service = this.mPluginManager.getComponentsHandler().getService(component);

如果已启动就直接获取目标service。

3,如果目标service未启动,首先加载并构造service组件,然后利用反射设置相关信息,最后调用service的onCreate方法,

service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();Application app = plugin.getApplication();IBinder token = appThread.asBinder();Method attach = service.getClass().getMethod("attach", Context.class, ActivityThread.class, String.class, IBinder.class, Application.class, Object.class);IActivityManager am = mPluginManager.getActivityManager();attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClassName(), token, app, am);service.onCreate();

当然,启动的service会进行统一管理,

this.mPluginManager.getComponentsHandler().rememberService(component, service);

ComponentsHandler中有三个ArrayMap保存service信息,

private ArrayMap<ComponentName, Service> mServices = new ArrayMap<ComponentName, Service>();private ArrayMap<IBinder, Intent> mBoundServices = new ArrayMap<IBinder, Intent>();private ArrayMap<Service, AtomicInteger> mServiceCounters = new ArrayMap<Service, AtomicInteger>();

mServices保存通过startservice方法启动的服务,

mBoundServices保存通过bindservice方法绑定的服务,

mServiceCounters保存服务的相关信息。

原创粉丝点击