FrameWork源码解析-插件化框架VirtualApk之Service管理

框架地址:VirtualApk
在线源码查看:AndroidXRef

关于滴滴插件化框架VirtualApk我们已经讲了有几篇了:
1)插件化框架VirtualApk之初始化
2)插件化框架VirtualApk之插件加载
3)插件化框架VirtualApk之Activity启动
这篇我们紧接着前面开始讲,我们知道启动服务有两种方式startService和bindService两种方式,我们前面已经讲过startService的流程分析和bindService方式的从framework分析AIDL生成文件,而且我们知道,Service的生命周期是我们可以手动控制的,我们可以不像Activity生命周期的控制一样交给系统管理,我们可以更简单地控制Service的生命周期。

FrameWork源码解析-插件化框架VirtualApk之Service管理

Service生命周期

 

我们看到Service的生命周期是比较简单的,而且图中已经说明了startService的时候,会调用onCreate(),onSstartCommand()方法,然后停止服务的时候我们可以调用stopService()或者stopSelf()方法;如果是bindService的时候,则会调用onCreate(),onBind()方法返回binder对象,然后会回调ServiceConnection对象,解除绑定的时候可以调用unBindService()来回调onUnbind()方法。和上一篇一样,我们这里就贴一下startService的启动过程概图:

FrameWork源码解析-插件化框架VirtualApk之Service管理

startService流程图


我们看到和Activity启动不一样的是,这里并不是通过Instrumentation来进行管理创建过程的,而是直接通过ActivityManagerProxyAMS通讯进行创建的。

 

一.Service管理过程分析

插件化框架VirtualApk在Service的管理上采用了一种称为代理分发的方式。首先会在AndroidManifest.xml中注册两种代理Service,这样要启动插件Service的时候,我们都会启动这个代理Srevice,然后在onStartCommand()方法中进行分发执行插件的onStartCommand()方法。所以我们先来看看这两个代理Service的注册情况:

  <!-- 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>

我们看到这里注册了两个代理服务,一个是在主进程中的,一个是在非主进程中的,根据插件服务在的进程进行分别地启动。而且在前面的初始化我们已经看到,一个是hook 了Instrumentation类还有一个是hook了IActivityManager,我们来看看:

   private void hookSystemServices() {
        try {
            Singleton<IActivityManager> defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManagerNative.class, null, "gDefault");
            IActivityManager activityManagerProxy = ActivityManagerProxy.newInstance(this, defaultSingleton.get());

            // Hook IActivityManager from ActivityManagerNative
            ReflectUtil.setField(defaultSingleton.getClass().getSuperclass(), defaultSingleton, "mInstance", activityManagerProxy);

            if (defaultSingleton.get() == activityManagerProxy) {
                this.mActivityManager = activityManagerProxy;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 private void hookAMSForO() {
        try {
            Singleton<IActivityManager> defaultSingleton = (Singleton<IActivityManager>) ReflectUtil.getField(ActivityManager.class, null, "IActivityManagerSingleton");
            IActivityManager activityManagerProxy = ActivityManagerProxy.newInstance(this, defaultSingleton.get());
            ReflectUtil.setField(defaultSingleton.getClass().getSuperclass(), defaultSingleton, "mInstance", activityManagerProxy);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

我们看到根据不同android版本分别采用了不同的方式,但是最终都是通过动态代理的方式将ActivityManagerProxy代理成我们自己的ActivityManagerProxy对象。这样在调用AMS的时候,我们会走到自己的ActivityManagerProxy对象的invoke()方法来。我们来看看invoke()方法:

  @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("startService".equals(method.getName())) {
            try {
                return startService(proxy, method, args);
            } catch (Throwable e) {
                Log.e(TAG, "Start service error", e);
            }
        } else if ("stopService".equals(method.getName())) {
            try {
                return stopService(proxy, method, args);
            } catch (Throwable e) {
                Log.e(TAG, "Stop Service error", e);
            }
        } else if ("stopServiceToken".equals(method.getName())) {
            try {
                return stopServiceToken(proxy, method, args);
            } catch (Throwable e) {
                Log.e(TAG, "Stop service token error", e);
            }
        } else if ("bindService".equals(method.getName())) {
            try {
                return bindService(proxy, method, args);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        } else if ("unbindService".equals(method.getName())) {
            try {
                return unbindService(proxy, method, args);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        } else if ("getIntentSender".equals(method.getName())) {
            try {
                getIntentSender(method, args);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if ("overridePendingTransition".equals(method.getName())){
            try {
                overridePendingTransition(method, args);
            } catch (Exception e){
                e.printStackTrace();
            }
        }

        try {
            // sometimes system binder has problems.
            return method.invoke(this.mActivityManager, args);
        } catch (Throwable th) {
            Throwable c = th.getCause();
            if (c != null && c instanceof DeadObjectException) {
                // retry connect to system binder
                IBinder ams = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                if (ams != null) {
                    IActivityManager am = ActivityManagerNative.asInterface(ams);
                    mActivityManager = am;
                }
            }

            Throwable cause = th;
            do {
                if (cause instanceof RemoteException) {
                    throw cause;
                }
            } while ((cause = cause.getCause()) != null);

            throw c != null ? c : th;
        }
    }

这个方法很简单,我们看到关于Service的所有操作都被拦截了,我们这里一个一个方法来讲,首先我们看看startService()方法。

1.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);
    }

我们看到这里的resolveService()方法跟Activity启动管理里面的resolveActivity()方法类似,是根据intent的信息然后查找出来匹配的ServiceResolveInfo信息来,然后判断ResolveInfo如果为空则说明是宿主程序中的服务,否则会调用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()进行将要启动插件的服务替换成前面提前注册好的服务,然后启动。我们看看这里的替换代码:

 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的Component为插件中服务的Component,然后获取插件的位置,而且判断是不是要启动的插件服务是在独立的进程中,接着就设置intent的class等等一些信息。最后将提前注册好的Service启动。到这里我们的LocalServiceRemoteService就已经启动了,这里的RemoteService是继承LocalService的,多了一步创建Application的操作。我们看前面的Service的生命周期可以知道,启动Service的过程中,会回调onStartCommand()方法,所以我们在这里面做相应的操作即可,首先我们来看启动服务的回调:

    case EXTRA_COMMAND_START_SERVICE: {
                ActivityThread mainThread = (ActivityThread)ReflectUtil.getActivityThread(getBaseContext());
                IApplicationThread appThread = mainThread.getApplicationThread();
                Service service;

                if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
                    service = this.mPluginManager.getComponentsHandler().getService(component);
                } else {
                    try {
                        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();
                        this.mPluginManager.getComponentsHandler().rememberService(component, service);
                    } catch (Throwable t) {
                        return START_STICKY;
                    }
                }

                service.onStartCommand(target, 0, this.mPluginManager.getComponentsHandler().getServiceCounter(service).getAndIncrement());
                break;
            }

这个方法就是启动Service的方法,首先会调用isServiceAvailable()方法判断服务是否已经创建好缓存在mServices中了,如果有则不用重新创建直接获取到Service然后调用它的onStartCommand方法,否则就重新反射创建Service,调用attach()方法,然后手动调用Service的onCreate()方法,并将创建好的Service添加到缓存中。如果这块代码有点不懂的话那么可以认真看framework层的代码。

2.stopService

      case EXTRA_COMMAND_STOP_SERVICE: {
                Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
                if (null != service) {
                    try {
                        service.onDestroy();
                    } catch (Exception e) {
                        Log.e(TAG, "Unable to stop service " + service + ": " + e.toString());
                    }
                } else {
                    Log.i(TAG, component + " not found");
                }
                break;
            }

我们看到停止服务比较简单,即时移除缓存中的Service,然后执行他的onDestroy()方法即可。

3.bindService

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

        Bundle bundle = new Bundle();
        PluginUtil.putBinder(bundle, "sc", (IBinder) args[4]);
        startDelegateServiceForTarget(target, resolveInfo.serviceInfo, bundle, RemoteService.EXTRA_COMMAND_BIND_SERVICE);
        mPluginManager.getComponentsHandler().remberIServiceConnection((IBinder) args[4], target);
        return 1;
    }

我们看到绑定服务这里将IBinder存入了一个Bundle中,这个IBinder就是我们前面分析源码时候提及的IServiceConnection类,然后通过startDelegateServiceForTarget()启动代理的Service,同样地,最终会来到LocalServiceonStartCommand()方法中。

   case EXTRA_COMMAND_BIND_SERVICE: {
                ActivityThread mainThread = (ActivityThread)ReflectUtil.getActivityThread(getBaseContext());
                IApplicationThread appThread = mainThread.getApplicationThread();
                Service service = null;

                if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
                    service = this.mPluginManager.getComponentsHandler().getService(component);
                } else {
                    try {
                        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();
                        this.mPluginManager.getComponentsHandler().rememberService(component, service);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
                try {
                    IBinder binder = service.onBind(target);
                    IBinder serviceConnection = PluginUtil.getBinder(intent.getExtras(), "sc");
                    IServiceConnection iServiceConnection = IServiceConnection.Stub.asInterface(serviceConnection);
                    if (Build.VERSION.SDK_INT >= 26) {
                        ReflectUtil.invokeNoException(IServiceConnection.class, iServiceConnection, "connected",
                                new Class[]{ComponentName.class, IBinder.class, boolean.class},
                                new Object[]{component, binder, false});
                    } else {
                        iServiceConnection.connected(component, binder);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            }

这里的代码也并不复杂,主要做了几件事,首先也是判断缓存中有没有创建好的Service,如果没有则创建调用他的attach()方法和onCreate()方法,这里还有一个不同的地方是调用Service的onBind()方法,然后会调ServiceConnectionconnected()方法。

4.unbindService

  case EXTRA_COMMAND_UNBIND_SERVICE: {
                Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
                if (null != service) {
                    try {
                        service.onUnbind(target);
                        service.onDestroy();
                    } catch (Exception e) {
                        Log.e(TAG, "Unable to unbind service " + service + ": " + e.toString());
                    }
                } else {
                    Log.i(TAG, component + " not found");
                }
                break;
            }

这个跟stopService差不多,就是多了一个在onDestroy前面调用了onUnbind()方法,这样的话,Service的整个启动,停止,绑定,解绑等都已经完成了。

还有在invoke()方法里面有一个stopServiceToken方法,这个方法的调用主要是在IntentService中的stopSelf()方法中会调用到,最终会调用mActivityManager.stopServiceToken方法,同样的中转到STOP操作即可.

总结:到这里Service的管理我们也已经讲完了,整理来说代码逻辑不难,细节倒是非常多的,如果想要更深入了解,建议还是要认真看一下FrameWork的源码,希望大家能有所收获。

FrameWork源码解析-插件化框架VirtualApk之Service管理

 

 

FrameWork源码解析-插件化框架VirtualApk之Service管理

+qq群:853967238。获取以上高清技术思维图,以及相关技术的免费视频学习资料。