系列文章索引
并发系列:线程锁事
新系列:Android11系统源码解析
-
Android11源码分析:binder是如何实现跨进程的?(创作中)
-
Android11源码分析:SurfaceFlinger是如何对vsync信号进行分发的?(创作中)
经典系列:Android10系统启动流程
前言
针对四大组件的源码分析我们已经搞定了Activity,今天我们来看看Service是如何启动和绑定的
service启动分析
开启一个service有两种方式
-
context.startService()
-
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());
}
这里又调用到了ActivityThread
的scheduleCreateService()
,在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中继续处理mPendingServices
的StartItem
,向Client
发起binder调用执行onStartCommand()
bindService
启动分析
bindService()可以和startService()组合使用,也可以通过BIND_AUTO_CREATE
来单独使用启动并绑定service
绑定服务主要用于activity
和service
之间的数据传递,远程调用通信,及生命周期的绑定
同一进程中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
}
ServiceDispatcher
是LoadedApk
的内部类,构造函数中对InnerConnection
这个binderProxy对象进行了创建,当执行到connected()
函数时,会调用ServiceDispatcher
的connected()
函数, 当前mActivityExecutor
为空,mActivityThread
为ActivityThread
的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
,并执行了ServiceConnection
的onServiceConnected(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调用执行到AMS
的bindIsolatedService()
函数,去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
中又调用到了ActiveServices
的publishServiceLocked()
函数,这里的主要逻辑是根据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
, 我们也将彻底明白,为什么静态广播能够在进程未启动的情况下接收消息
最后的最后
如果我的文章对你有所启发,请多多点赞支持,我们下期文章再见!