• 0

  • 474

【再出发】Android11源码分析:Service启动流程分析

Mellon

大家好

2星期前

系列文章索引

新系列:Android11系统源码解析

  1. Android11源码分析:Mac环境如何下载Android源码?

  2. Android11源码分析:应用是如何启动的?

  3. Android11源码分析:Activity是怎么启动的?

  4. Android11源码分析:Service启动流程分析

  5. Android11源码分析:静态广播是如何收到通知的?(创作中...)

经典系列:Android10系统启动流程

  1. 源码下载及编译

  2. Android系统启动流程纵览

  3. init进程源码解析

  4. zygote进程源码解析

  5. systemServer源码解析

前言

针对四大组件的源码分析我们已经搞定了Activity,今天我们来看看Service是如何启动和绑定的

service启动分析

开启一个service有两种方式

  1. context.startService()

  2. context.bindService()

我们先来看看startService的启动方式

startService启动分析

我们已经知道startService是由context调用的,而context的实现类是ContextImpl,这里又调用了startServiceCommon()来开启service

/frameworks/base/core/java/android/app/ContextImpl.java

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
            UserHandle user) {
        //...
        ComponentName cn = ActivityManager.getService().startService( //AMS binder调用
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());
    }

复制代码

上面的源码中我们忽略了各种异常处理,来看核心逻辑,也就是通过binder调用执行到AMS中的startService()函数,其中有通过持有的mServices(即ActiveSerices对象)的startServiceLocked()函数

经过startServiceLocked()--> startServiceInnerLocked()-->bringUpService()这一系列调用流程,来执行开启service的逻辑

如果service已经被开启,则通过binder调用与ActivityThread通信,调用scheduleServiceArgs()函数,执行onStartCommand()生命周期回调

/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

private String bringUpServiceLocked(ServiceRecord r...){
	if (r.app != null && r.app.thread != null) { //判断service是否启动
            sendServiceArgsLocked(r, execInFg, false);//调用`scheduleServiceArgs()`函数进一步处理启动流程
            return null; 
         }
         
    

}
复制代码

如果service所在的已经启动,则调用realStartServiceLocked(),通过binder调用,去执行创建service的逻辑

private final void realStartServiceLocked(ServiceRecord r...) throws RemoteException {
       //...
       app.thread.scheduleCreateService(r, r.serviceInfo, //通过binder调用ActivityThread的方法
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            
}
复制代码

这里又调用到了ActivityThreadscheduleCreateService(),在binder线程通过Hander(mH)给主线程发送消息,让主线程来处理,mH接收到CREATE_SERVICE的消息,调用handleCreateService()来处理

函数中通过获取ClassLoader反射创建了Service对象(与Activity的创建方式一致),并绑定context,执行onCreate()的生命周期方法

/WORKING_DIRECTORY/frameworks/base/core/java/android/app/ActivityThread.java

private void handleCreateService(CreateServiceData data) { 
	Service service = packageInfo.getAppFactory()  //通过ClassLoader反射创建Service
                    .instantiateService(cl, data.info.name, data.intent);
                    
    service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService()); //与context绑定
            service.onCreate(); //调用service的oncreate() //执行onCreate生命周期

}

复制代码

ActivityThread创建完成后,又回到了realStartServiceLocked()函数中,将created置为true, 然后向AMS申请binder句柄,供bindService时使用,接着再通过binder调用与ActivityThread通信,执行onStartCommand()生命周期函数

/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

private final void realStartServiceLocked(ServiceRecord r, //启动servicce
	//...
       boolean created = false;
       app.thread.scheduleCreateService(r, r.serviceInfo, //通过binder调用ActivityThread的方法
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
    
       created = true;  
       
       if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                    null, null, 0));  //处理pendingStarts,添加StartItem
        }
       
       requestServiceBindingsLocked(r, execInFg); //请求service发送binder句柄到AMS注册
       
       sendServiceArgsLocked(r, execInFg, true); //触发service的onstartcommand()
         
}
复制代码

如果进程未启动,则需要通过AMS与Zygote通信先fork出对应的进程(mAm.startProcessLocked()),这里的进程启动逻辑我们在之前已经分析过,这里不再赘述

启动完成后,将ServiceRecord对象添加到mPendingServices的缓存中,待service创建完成后从缓存中取出,执行其onStartCommand()函数

至此,startService()的启动流程已全部分析完成

小结

startService()由Context发起调用,主要逻辑在AMS中完成

由于Service可以设置独立进程,所以当进程不存在时需要先启动进程;如果service已经启动,则执行onStartCommand()生命周期回调

如果service所在进程已经启动,则调用realStartServiceLocked()函数,通过与Client端(即Activity)的binder调用来创建Service对象,执行onCreate(),再回到AMS中继续处理mPendingServicesStartItem,向Client发起binder调用执行onStartCommand()

bindService启动分析

bindService()可以和startService()组合使用,也可以通过BIND_AUTO_CREATE来单独使用启动并绑定service

绑定服务主要用于activityservice之间的数据传递,远程调用通信,及生命周期的绑定

同一进程中bindService

startService在调用时只需要传递一个Intent参数,指定启动的Service即可,而bindService()ContextImpl中有多个public的重载函数,注意,声明为public即可以供开发者在正常使用中调用,我们先看其中一个函数,函数中有三个参数,Intent对象,ServiceConnection对象以及flag标志

/frameworks/base/core/java/android/app/ContextImpl.java

public boolean bindService(Intent service, ServiceConnection conn, int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, 
        			conn,  //ServiceConnection对象
                    flags, //启动service的flag参数
                    null, //instanceName字符串
                    mMainThread.getHandler(),  //主线程的handler对象
                    null, //Executor对象
                getUser());
    }
复制代码

内部又调用了bindServiceCommon(), 里面参数较多,比较重要的是handler对象和executor对象,这里的handler传递了ActivityThread的handler对象mH,executor参数为空

我们继续查看bindServiceCommon()的函数实现,代码如下

private boolean bindServiceCommon(Intent service, ServiceConnection conn,...) {
     //将ServiceConnection封装为IServiceConnection binder对象
     IServiceConnection sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); 
}
复制代码

这里通过调用mPackageInfo(ApkLoaded对象)的getServiceDispatcher(),创建了ServiceDispatcher对象

这里根据executor是否为空,调用了不同的函数来获取ServiceDispatcher,我们目前分析的函数调用中,executor被赋值为null,因此调用了mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags)这个函数

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
            if (executor != null) { 
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
            } else { //当前调用链中executor为null
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            }
            
}
复制代码

ServiceDispatcher在bindService中起到了沟通Client端和Server端,分发ServiceConnection的作用,因此ServiceDispatcher的实现对于如何分发是至关重要的

我们继续查看当前executor为空时,获取ServiceDispatcher时,使用new ServiceDispatcher(c, context, handler, flags),来创建ServiceDispatcher对象

/frameworks/base/core/java/android/app/LoadedApk.java

private IServiceConnection getServiceDispatcherCommon(ServiceConnection c,
            Context context, Handler handler, Executor executor, int flags) {
            
            LoadedApk.ServiceDispatcher sd = null;
            if (sd == null) {
                if (executor != null) {
                    sd = new ServiceDispatcher(c, context, executor, flags); 
                } else { //当前调用链executor为空,执行传递handler的构造
                    sd = new ServiceDispatcher(c, context, handler, flags);
                }
                //...
             }
             //...
            return sd.getIServiceConnection(); //返回IServiceConnection
}
复制代码

ServiceDispatcherLoadedApk的内部类,构造函数中对InnerConnection这个binderProxy对象进行了创建,当执行到connected()函数时,会调用ServiceDispatcherconnected()函数, 当前mActivityExecutor为空,mActivityThreadActivityThread的handler对象mH ,于是调用了mActivityThread.post(new RunConnection(name, service, 0, dead));`向handler发送消息,在mH的主线程中执行

public void connected(ComponentName name, IBinder service, boolean dead) {
            if (mActivityExecutor != null) { 
                mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
            } else if (mActivityThread != null) {//向ActivityThread的handler`mH`发送消息
                mActivityThread.post(new RunConnection(name, service, 0, dead)); 
            } else {
                doConnected(name, service, dead);
            }
        }
复制代码

RunConnection是一个Runnable对象,我们来看下其中执行了什么操作,重点来看下run函数

public void run() { //在主线程中执行
                if (mCommand == 0) { //此处mCommand值为0
                    doConnected(mName, mService, mDead); 
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }
复制代码

此处mCommand值为0,又执行了doConnected(mName, mService, mDead)函数,在这里创建了ConnectionInfo,并执行了ServiceConnectiononServiceConnected(name, service)

至此bindService的bind流程结束,可以看到,这个过程中除了与AMS的交互使用了binder调用,Client端和Server端都是跑在同一个进程的,因此并不涉及跨进程通信,因此使用了ActivityThread的handler作为connection分发的工具,将connection post到主线程执行

这样实现的好处是,避免了在不需要创建进程,自然也避免了跨进程通信时使用binder调用的额外开销,性能更好,速度更快

但作为四大组件之一,service是支持运行在独立进程中的,接下来我们来看下,当service运行在独立进程时的bind流程

单独进程中bindService

在上面的分析中,我们调用的ContextImp其中一个重载函数,在创建service时为其中一个参数instanceName赋值为null,所以在启动单独进程Service时,会发现它不是独立进程的Service,直接向上return

要绑定一个单独进程的Service,我们需要调用bindIsolatedService(),指定进程名(instanceName),同样是调用了bindServiceCommon()这个函数,关键代码如下

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
	//...
    service.prepareToLeaveProcess(this);
    int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());

}
复制代码

函数中通过binder调用执行到AMSbindIsolatedService()函数,去bind独立进程的service,函数中又调用了mServices(ActiveServices的实力对象)的bindServiceLocked函数,如果指定了BIND_AUTO_CREATE,则会调用bringUpServiceLocked()执行startService的相关逻辑,这里上面已经分析过

如果Service已经绑定过,则直接通过调用执行client端的connected()回调函数,将binder对象传递过去

如果Service是第一次绑定,则需要与AMS通信,调用requestServiceBindingLocked()申请binder句柄

关键代码如下:

/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

int bindServiceLocked(...){
            //...
            if ((flags&Context.BIND_AUTO_CREATE) != 0) { //BIND_AUTO_CREATE
            	//...
                if (bringUpServiceLocked(...) { //用于拉起service
                    return 0;
                }
            }
            
            mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
                    callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
                    s.instanceName, s.processName); //将Service放在独立的进程中
            
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); //记录是否绑定的数据结构
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent,
                    callerApp.uid, callerApp.processName, callingPackage);//记录连接状态的数据结构,持有connection的binder对象
            
            if (s.app != null && b.intent.received) { //如果service已经被绑定过
            	c.conn.connected(s.name, b.intent.binder, false);//通过binderProxy调用clien端的`onServiceConnected回调`
            }else if (!b.intent.requested) { //AMS还没有请求过binder对象
                requestServiceBindingLocked(s, b.intent, callerFg, false); //请求binder对象,rebind = false
            }
            
}            
复制代码

requestServiceBindingLocked()中使用r.app.thread.scheduleBindService()远程调用到ActivityThead中的scheduleBindService()函数, Activity中又调用到了handleBindService((BindServiceData)msg.obj)来处理

如果是rebind,则直接调用Service的onRebind生命周期回调

如果是第一次执行bind,则获取到AMS的binder对象调用publishService()将binder对象注册到AMS中

private void handleBindService(BindServiceData data) {
		   if (!data.rebind) { //不是rebind时调用onBind
                        IBinder binder = s.onBind(data.intent); //调用onBind返回一个binder对象
                        ActivityManager.getService().publishService( //将binder对象发布到AMS
                                data.token, data.intent, binder);
                    } else {
                        s.onRebind(data.intent);//是rebind时调用onRebind
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
}
复制代码

AMS中又调用到了ActiveServicespublishServiceLocked()函数,这里的主要逻辑是根据intent找到ServiceRecord中所有匹配的ConnectionRecord,并将binder对象(service)分发给ConnectionRecord

到此,独立进程的Service通过向AMS中注册binder句柄完成了bindService的整个流程

小结

bindServce()的调用流程较为复杂

简单来说,如果Service与调用端在一个进程中,则直接通过ActivityThread中mH作为发送端,将回调的runnable post到主线程去执行

如果不在一个进程,则需要通过向AMS中注册binder句柄的方式进行IPC调用,将ConnectionRecord封装为binder对象跨进程传递

后记

通过对Activity启动流程,Service启动和绑定流程的分析,我们发现:

在应用端,ActivityThread起到了与AMS系统服务通信,并执行相关业务逻辑的重要作用

在Server端(系统服务),AMS起到了沟通native层(如binder的调用,与zygote通信fork子进程等)与应用层的作用

在下一篇文章中,我们将继续对Broadcast的注册和启动进行分析,将会引出另一个重要的系统服务PackageManagerService, 我们也将彻底明白,为什么静态广播能够在进程未启动的情况下接收消息

最后的最后

如果我的文章对你有所启发,请多多点赞支持,我们下期文章再见!

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

android

474

相关文章推荐

未登录头像

暂无评论