天天看点

Android 插件化开发——基础底层知识(Service)

上一篇我们讲了Context和Activity的相关知识,

Android 插件化开发——基础底层知识(Context家族史,Activity启动流程)

本篇我们讲述Service的工作流程

关于Service的创建启动流程,其实和Activity的创建启动流程是相似的。都是和AMS交互,通信介质是:Binder

Service工作流程

关于Service的启动方式,我们分为两种:startService和bindService, 关于这两个启动方式的区别以及使用方法,在此不再赘述。

启动创建Service,我们分为两种:同一进程,不同进程。

新进程启动Service

假设要在新进程启动一个Service,可分为5个阶段:

  • APP给AMS发送消息,附带Manifest定义的相关信息。
  • AMS检查新的进程是否存在,如果不存在,就创建一个新的进程,并且把Service信息保存起来。
  • 启动新进程,然后通知AMS,:新的进程已经存在
  • 此时AMS发送刚才存储的Service信息给新进程
  • 新进程启动Service

1: APP给AMS发送消息,附带Manifest定义的相关信息。

以startService为例,该方法最终调用的是ContextWrapper中的startService方法。

@Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }
           

我们知道mBase实际上就是ContextImp, 进入ContextImp,最终调用的是:startServiceCommon方法,可以看到这么一句话:

ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), requireForeground,
                            getOpPackageName(), user.getIdentifier());
           

发送消息给AMS。

2.AMS检查新的进程是否存在,如果不存在,就创建一个新的进程,并且把Service信息保存起来。

AMS会首先检查Manifest中是否生命了Service,如果没有直接报错。有的话,就创建进程,并且把Service的相关信息封装成ServiceRecord对象保存。

3.启动新进程,然后通知AMS,:新的进程已经存在

Service在启动的新进程的过程中和上一篇博客讲的APP的启动流程相似。

此时会创建一个ActivityThread。然后ActivityThread会告诉AMS:新进程启动成功。

4.此时AMS发送刚才存储的Service信息给新进程

AMS收到消息时候,会把之前存储的ServiceRecord通过ApplicationThread发送给新进程。这个ServiceRecord就是将要启动的Service的相关信息。

5:新进程启动Service

还是以startService为例,AMS发送消息给APT(ApplicationThread),执行:scheduleCreateService, 再给H 执行handleCreateService方法,其中可以看到这个代码块:

LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
           

可以看出通过classloader反射出(新建)了一个新的Service,这里用的是反射。

注意:实际上可以回顾一下,创建Activity的时候,用到的也是反射,可以在Instrumentation中看到,在此不赘述。

至此,新进程的Service就创建启动完成了。

同一进程绑定Service

在同一进程绑定Service,大致分为五个步骤:

  • APP发送消息给AMS,附带要启动的Service信息。
  • AMS接收到信息之后,会注册Service在AMS这边,会通知APP启动Service
  • APP收到消息1, 启动Service,启动完成之后,会发送一个消息给AMS:启动完成
  • APP在收到消息2, 绑定Service,把Binder对象传递给AMS。
  • AMS再把接收到的Binder对象返回给APP。

最后两把绕了一圈 Binder又给了APP,考虑的因素可能是:不在同一个进程。所以这样代码公用。

调用bindService还是走的ContextWrapper,

@Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        return mBase.bindService(service, conn, flags);
    }
           

接着走了ContextImp的bindServiceCommon方法

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
       .....
        ActivityManager.getService().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier());
    }
           

最终传递给AMS。

AMS收到信息之后,检查Manifest,并且会查看新的进程是否存在。

最终发送消息给APP(假设同一进程),然后回调给APP的APT的scheduleCreateService方法, 在传递给H,

private void handleCreateService(CreateServiceData data) {
       service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
    }
           

创建完了Service, 最后调用了serviceDoneExecuting方法,是告诉AMS:我创建完毕了,是否有下一步操作。

然后AMS收到消息之后,最终间接会调用APP的handleBindService方法,这是开始了绑定操作。

private void handleBindService(BindServiceData data) {
					....
      				 if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ......
   		 }
           

执行了Service的onBind方法,并且告诉调用AMS的publishService方法告诉它:绑定完毕。

其中传递了Binder对象,这个Binder对象是ServiceDispatcher内部类的InnerConnection。 InnerConnection实现了IServiceConnection.Stub。

重新回到ContextImp:

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        .....
       sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
       ......
    }
           

进入到LoadedApk.java中可自行查看ServiceDispatcher类, 把Binder包装成了ServiceDispatcher对象发送给了AMS。最终调用:connected方法 --> doConnected方法:

// If there is a new viable service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            } else {
                // The binding machinery worked, but the remote returned null from onBind().
                mConnection.onNullBinding(name);
            }
           

看到了熟悉的onServiceConnected回调。 如果不在同一个进程,Service 通信的流程是:Service -->AMS -->Activity, 中间是Binder驱动。

附上网上的一张流程图,个人觉得bindService流程跟这幅图完全比配:

Android 插件化开发——基础底层知识(Service)

至此绑定流程讲述完了。整体的流程和Activity的启动流程是相似的。

继续阅读