1.前情回顾
我们讲Service的工作流程之前我们先回顾一下上次我们讲的Activity的工作流程,先是launcher打开一个app的图标,判断是否有该活动的进程,没有的话则让AMS通知zygote新开一个进程。之后通过AIDL创建ATMS。再将你要启动的那个活动放在栈顶并移动至前台,通过mservice创建一个客户端,让它通过binder与applicationThread进行通信,把你要启动activity的信息传递给它,在handler中进行处理这些消息,先通过Instrumentation创建Activity的实例,再通过attach将属性与Activity绑定,最后通过Instrumentation.callActivityOnCreate调用到activity的performCreate方法将在这个方法中,让Activity的onCreate()被启动,至此Activity的启动完毕
Activity的启动结束我们就来看Service的启动,本篇博客主要讲两个知识点,一个是Service的启动,一个是Service的绑定
2.Service的启动
我们可以把Service的启动分为3个阶段,可以分为从ContextImpl到AMS的调用过程,从AMS到ActivityThread以及ActivityThread启动Service。
你会发现后2步和Activity的启动如此相似
2.1ContextImpl到AMS的调用过程
从ContextImpl到AMS的调用过程。如果要启动Service,
在之前我们就是调用startService
方法,这里也不意外
我们首先会通过ContextWrapper的startService来开启流程。这个ContextWrapper是Context的子类,它实现了Context中的方法,我们就来看ContextWrapper的startService方法:
.......
Context mBase;
.......
public @Nullable ComponentName startService(Intent service) {
return mBase.startService(service);
}
它会调用类型为Context类的startService,Context类是一个抽象类,所以我们需要找到它的实现类,这个具体的实现类实际上我们在根Activity的创建过程中已经提到过了,
在ActivityThread启动performLaunchActivity的时候其实我们第一步骤是通过createBaseContextForActivity
来创建一个Context,第二个步骤才是通过Instrumentation创建了一个Activity的实例。
那Context什么时候才与Activity关联上的呢?就是后面我们调用的那个attach方法
所以其实我们看
mBase.startService(service)
其实看的不是startService的源码,而是看mBase是来自哪儿的,mBase是一个Context类的,它是从Activity的performLaunchActivity的createBaseContextForActivity
方法创建的一个Context,在attach中与Activity绑定起来
我们可以看看createBaseContextForActivity的源码,看看它是怎么创建的Context
private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
final int displayId = ActivityClient.getInstance().getDisplayId(r.token);
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);
........
return appContext;
}
我们会发现它是调用的ContextImpl的createActivityContext
方法
这个方法里会调用到ContextImpl
的构造方法。总之我们最后调用的就是这个ContextImpl的startService
方法,这个startService方法又会调用到startServiceCommon
方法,我们就直接看这个startServiceCommon
方法:
2.1.1startServiceCommon的源码
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService( //1--------1
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
..........
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
从这里我们就会发现,调用ContextImpl的startService方法其实最后会调用到AMS的getService().startService(),实际上也正是这样,和Activity的创建一样,是通过远程调用了AMS的方法。
到此为止,就正式进入到了AMS的处理和方法调用过程了
2.1.2总结操作
所以Service的启动,第一步骤其实就是调用Context 的 startService() 方法,但是我们通过Activity的创建会发现,Context的创建会调用createBaseContextForActivity,即会调用ContextImpl的构造方法,在 ContextImpl 的构造方法中,会调用 attachBaseContext()
方法将 ContextImpl
实例与 Application
实例关联起来。接着,在 Activity 的 onCreate() 方法中调用 startService() 方法时,会调用 ContextImpl 的 startService() 方法,从而触发启动 Service 的流程。
在 ContextImpl 的 startService() 方法中,会获取 AMS 的 Binder 接口,并调用其 startService()
方法,将启动 Service 的请求发送给 AMS 进程。
2.2从AMS到ActivityThread
我们第一个步骤的结束是以最后Activity进入到oncreate()
阶段,ContextImpl调用自己的startService()
方法并且获取AMS的Binder接口,调用AMS的startService()结束的
所以现在我们看看AMS的startService()的源码
2.2.1AMS的startService()源码
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
...........
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service, //1-------1
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
我们会发现,这段代码主要是在synchronized的锁里面执行的,保证了多线程访问这个方法时的原子性,有序性,可见性
刚才不是说了嘛,ContextImpl会获得的AMS的Binder接口然后调用AMS的startService()方法,所以在这个Synchronized锁中,我们第一个干的事情就是通过Binder来获得的这个callingPid,callingUid,还有origId
ComponentName 是 Android 中一个用于标识组件的类,它包含两个重要的信息:组件所在的应用包名和组件的类名。
我们通过调用mServices.startServiceLocked
来获得这个标识类
来看看这个方法
2.2.2startServiceLocked的源码
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired,
String callingPackage, @Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
throws TransactionTooLargeException {
.........
ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false); //1-----1
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record; //2-------2
........
final ComponentName realResult =
startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
allowBackgroundActivityStarts, backgroundActivityStartsToken);//3-------3
}
在注释一处,会通过retrieveServiceLocked
方法查找是否有与参数service对应的ServiceRecord(这个ServiceRecord和ActivityRecord类似,是描述Service的一个类),如果没有找到,接下来就会在注释二处会去到res的record参数并将其赋值给ServiceRecord变量,最后将其传入startServiceInnerLocked
继续Service的启动。这个startServiceInnerLocked
方法接下来又会进行跳转,具体最后会跳转到bringUpServiceLocked
方法中,我们直接看这个方法:
2.2.3bringUpServiceLocked的源码
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
boolean enqueueOomAdj)
throws TransactionTooLargeException {
...........
// Service is now being launched, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord(
HostingRecord.HOSTING_TYPE_SERVICE, r.instanceName,
r.definingPackageName, r.definingUid, r.serviceInfo.processName);
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid); //1------1
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null) {//2-----2
final IApplicationThread thread = app.getThread();
final int pid = app.getPid();
final UidRecord uidRecord = app.getUidRecord();
if (thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,
mAm.mProcessStats);
realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
enqueueOomAdj);//3-------3
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
}
}
..............
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null && !permissionsReviewRequired && !packageFrozen) {//4---------4
// TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
// was initiated from a notification tap or not.
if (r.isSdkSandbox) {
final int uid = Process.toSdkSandboxUid(r.sdkSandboxClientAppUid);
app = mAm.startSdkSandboxProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, uid, r.sdkSandboxClientAppPackage);
r.isolationHostProc = app;
} else {
app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,//5---------5
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated);
}
if (app == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
if (isolated) {
r.isolationHostProc = app;
}
}
.........
return null;
}
在注释一处会获取到Service要在哪个进程里启动,这个属性默认是会在当前进程中运行,我们也可以通过修改Service的process属性来进行修改,这个内容具体是在IPC中提到过。如果这个进程存在,那么接下来就会进入到注释二处的分支处,如果这个进程有线程那么就会执行注释三处的realStartServiceLocked方法。
若需要的进程不存在的话,就会进入到注释四处的分支处,紧接着会运行到注释五处的分支来启动一个新的进程。不过这不是我们的重点,我们继续回到注释三处的方法处。让我们看这个方法:
2.2.4realStartServiceLocked的源码
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
boolean enqueueOomAdj) throws RemoteException {
.........
thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.mState.getReportedProcState());
........
}
实际上就是通过上面的一句来推进了Service的启动,这个thread点开来的话我们可以发现是一个IApplicationThread接口,这个接口在哪里实现呢?我们可以看ActivityThread的内部类ApplicationThread:
private class ApplicationThread extends IApplicationThread.Stub {
............
}
这显然是通过AIDL实现的,ApplicationThread类就是这个thread的实现类,具体最后还是调用到了ActivityThread的方法。所以说,到此为止又由AMS进入到了ActivityThread中了。接下来是Service启动的最后一部分。
2.2.5总结
我们会发现这个Service从AMS到ActivityThread与Activity的从AMS到ActivityThread还是有不少相似的地方
比如先说Service的
它是我们在ContextImpl获得了AMS得Binder接口后调用了AMS的startService之后,AMS 在启动 Service 之前会先检查 Service 是否已经存在,如果存在则不再启动新的 Service,而是将已存在的 Service 返回给应用程序。如果 Service 不存在,则 AMS 会创建一个 ServiceRecord
对象来表示将要启动的 Service,ServiceRecord
中包含了 Service 的各种属性信息。AMS 会调用 bringUpServiceLocked() 方法来启动 Service,在该方法中,AMS 会根据 ServiceRecord 中的信息来决定将 Service 启动在哪个进程中。如果 Service 所在的应用程序进程存在,则 AMS 会启动该进程,并在进程中启动 Service。启动 Service 的具体操作是通过 ActivityThread 来完成的。AMS 会调用 realStartServiceLocked() 方法,该方法会通过 AIDL 调用方式进入到 ActivityThread 中,由 ActivityThread 来完成 Service 的启动操作。
简单的来说就是会检查启动的service存不存在,不存在就获得一个serviceRecord然后检查service所处在哪个进程中,然后通过AIDL进入ActivityThread
而Activity的
我们是在AMS中判断它的进程存不存在,不存在则让AMS通知Zygote来fork一个新进程,然后将要启动的Activity放在栈顶之后设置为前台,最后创建一个客户端,通过Binder与ActivityThread通信
2.3ActivityThread启动Service
2.3.1scheduleCreateService的源码
接下来进入到了ActivityThread中,让我们来看他的scheduleCreateService方法:
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
这个和刚才的Activity的那块一样都是在ActivityThread中进行处理,这里我们明显看到了
sendMessage();
这个方法具体就是触发了自身Handler的方法,
在Activity中,是对CREATE_ONCREATE标志位进行的处理,但是现在是对CREATE_SERVICE进行的处理
我们来看Handler对CREATE_SERVICE标志位的处理
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
所以会发现,处理Service主要是用的是
handleCreateService()
我们看看handleCreateService()的源码
2.3.2handleCreateService()的源码
private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
Application app = packageInfo.makeApplicationInner(false, mInstrumentation);
final java.lang.ClassLoader cl;
if (data.info.splitName != null) {
cl = packageInfo.getSplitClassLoader(data.info.splitName);
} else {
cl = packageInfo.getClassLoader();
}
service = packageInfo.getAppFactory() //1------1
.instantiateService(cl, data.info.name, data.intent);
ContextImpl context = ContextImpl.getImpl(service
.createServiceBaseContext(this, packageInfo));
.............
service.attach(context, this, data.info.name, data.token, app,//2--------2
ActivityManager.getService());
service.onCreate();//3----------3
mServicesData.put(data.token, data);
mServices.put(data.token, service);//4--------4
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); //5-----5
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
这里我们还是从上往下看首先是通过packageInfo获取到了ClassLoader,这个ClassLoader是用于生成Service实例的。在注释一处就用这个ClassLoader获取到了Service的实例。
service = packageInfo.getAppFactory();
接着在注释二处通过attach方法将service自身的context进行了绑定。
service.attach(context, this, data.info.name, data.token, app,//2--------2
ActivityManager.getService());
注释三处,调用了Service的onCreate回调;
service.onCreate();
最后注释四处将当前Service添加入ActivityThread的service列表中便于后续管理。
mServices.put(data.token, service);
一切都完毕后,调用注释五处的方法通知AMS当前Service创建完毕了,这个方法用于标记服务执行完成,并根据不同的类型和结果执行相应的操作。
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
到这里为止,Service的启动过程就介绍完毕了。
我们会发现,其实ActivityThread启动Service前面的步骤与ActivityThread启动Activity的步骤很相似
第一步都是通过Handle来进行处理AMS发送过来的请求,然后都是先通过ClassLoader来创建一个Activity或者Service的实例,但是Activity得先通过createBaseContextForActivity创建一个Context,然后都要通过attach将属性与Service或者Activity进行绑定,绑定完后Activity就直接把现在的状态设置为onCreate()了,但是Service却不是,它要先把Service先调用它的onCreate回调然后添加到ActivityThread的service列表中进行后续的管理最后再通过之AMS当前的service已经创建完毕
2.4总结Service的启动的流程
Service的启动可以分成3个流程,第一个是ContextImpl到AMS的调用,第二个是AMS到ActivityThread,第三个是ActivityThread的启动Service
首先我们是通过Context调用startService来开始Service的启动流程,在Activity的performLaunchActivity的源码中我们可以发现,Context是通过调用createBaseContextForActivity
这个方法才创建的,但是在调用这个方法的时候同时会调用起ContextImpl的构造方法,当Activity进行onCreate的时候,会调用ContextImpl的startService方法,在 ContextImpl 的 startService() 方法中,会获取 AMS 的 Binder 接口,并调用其 startService()
方法,将启动 Service 的请求发送给 AMS 进程。这就是第一个操作
在调用startService之后会调用startServiceLocked
方法,如果Service不存在的话它会创建一个ServiceRecord
对象,这个对象包含了Service的全部属性,之后会继续调用bringUpServicceLocked方法继续启动Service,与此同时它会寻找该Service所在的进程,如果该进程存在,那么AMS则会启动该进程,然后调用realStartServiceLocked方法通过AIDL进入ActivityThread,这是第二个操作
最后在ActivityThread,我们通过Hanlder来处理AMS发送过来的启动Service的请求,会先通过ClassLoader来获得一个Service的实例,然后将context之类的attach到Service,之后就调用service的oncreate()方法进行回调再把它添加到ActivityThread的service列表中,最后通知AMS,service已经创建好了
service的启动结束
3.Service的绑定
我们知道Service除了可以用Start启动外,还可以通过Bind方法进行客户端的绑定,接下来我们就来看Service的绑定过程。 Service的绑定过程我们也可以分成三个过程:ContextImpl到AMS的调用过程,AMS到ActivityThread的调用与ActivityThread到Service得到绑定过程。
3.1ContextImpl到AMS的调用过程
这里和Service的start方法前面一样的,同样都是context.bind()然后Activity中performLaunchActivity
中调用createBaseContextForActivity
创建了一个Context,同时调用了contextImpl的构造方法,在Activity调用onCreate之后会调用ContextImpl的bindService
,在 ContextImpl 的bindService() 方法中,会获取 AMS 的 Binder 接口,并调用其 bindServiceInstance()
方法,将绑定 Service 的请求发送给 AMS 进程。之后就是第二个过程了
3.2AMS到ActivityThread的过程
从AMS的bindServiceInstance方法开始
3.2.1bindServiceInstance源码
private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
boolean isSdkSandboxService, int sdkSandboxClientAppUid,
String sdkSandboxClientAppPackage, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
enforceAllowedToStartOrBindServiceIfSdkSandbox(service);
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
if (isSdkSandboxService && instanceName == null) {
throw new IllegalArgumentException("No instance name provided for isolated process");
}
// Ensure that instanceName, which is caller provided, does not contain
// unusual characters.
if (instanceName != null) {
for (int i = 0; i < instanceName.length(); ++i) {
char c = instanceName.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9') || c == '_' || c == '.')) {
throw new IllegalArgumentException("Illegal instanceName");
}
}
}
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
final ComponentName cn = service.getComponent();
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindService:"
+ (cn != null ? cn.toShortString() : service.getAction()));
}
synchronized (this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,
sdkSandboxClientAppPackage, callingPackage, userId); //1---1
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
其实我们就是调用了bindServiceLocked方法
3.2.2bindServiceLocked源码
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String instanceName, boolean isSdkSandboxService, int sdkSandboxClientAppUid,
String sdkSandboxClientAppPackage, String callingPackage, final int userId)
throws TransactionTooLargeException {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
" + Integer.toHexString(flags));
.........
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); //1-------1
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent,
callerApp.uid, callerApp.processName, callingPackage, res.aliasComponent);
.........
ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
boolean needOomAdj = false;
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
needOomAdj = true;
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,//2-------2
permissionsReviewRequired, packageFrozen, true) != null) {
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
return 0;
}
}
.........
if (s.app != null && b.intent.received) {//3------3
// Service is already running, so we can immediately
// publish the connection.
// If what the client try to start/connect was an alias, then we need to
// pass the alias component name instead to the client.
final ComponentName clientSideComponentName =
res.aliasComponent != null ? res.aliasComponent : s.name;
try {
c.conn.connected(clientSideComponentName, b.intent.binder, false);//4-------4
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortInstanceName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// If this is the first app connected back to this binding,
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {//5--------5
requestServiceBindingLocked(s, b.intent, callerFg, true);//6------6
}
} else if (!b.intent.requested) {//7-----7
requestServiceBindingLocked(s, b.intent, callerFg, false);//8------8
}
maybeLogBindCrossProfileService(userId, callingPackage, callerApp.info.uid);
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
notifyBindingServiceEventLocked(callerApp, callingPackage);
return 1;
}
在上面我们的startServiceLocked
方法主要是用来找Service对应的那个ServiceRecord存不存在
但是bindServiceLocked
却不一样
我们先介绍一下相关的类代表什么:
- AppBindRecord代表应用程序与服务之间的绑定关系。它记录了应用程序与服务之间的连接信息,包括应用程序的UID、进程名称、包名,以及与服务建立的连接对象。
- ConnectionRecord:这是一个代表应用程序与服务之间连接的类。它包含了连接对象的相关信息,例如连接的应用程序、连接的服务、连接的标志等。
- IntentBindRecord 类表示服务(ServiceRecord)与绑定的 Intent 之间的关联关系记录。
首先在注释一处
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
获得了Service的AppBindRecord信息和ConnectionRecord信息;
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,//2-------2
permissionsReviewRequired, packageFrozen, true) != null) {
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
return 0;
}
接着,如果创建的标注为BIND_AUTO_CREATE的话就会进入到注释二处的bringUpServiceLocked方法中,这个方法中又会调用到我们在启动流程中提到的realStartServiceLocked方法,也就是说会自动地创建和启动Service;
realStartServiceLocked方法就是我们上面启动Service的通过AIDL方法到ActivityThread中
if (s.app != null && b.intent.received)
注释三处的条件代表service已经运行,这样就会紧接着调用到注释四处的connected方法,
c.conn.connected(clientSideComponentName, b.intent.binder, false);
具体来说是会调用到InnerConncetion的connected方法,并且最终调用到LoadedApk的connected方法:
3.2.3LoadedApk.connected源码
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
学了线程池之后再看这个应该就很好理解了
如果这个mActivityExecutor的线程池不为null的话
我们就会通过execute方法来启动这个线程池
如果那个线程池为空但是线程不为空的话,那么我们通过post方法来向主线程发送消息,并且解决当前应用程序进程和Service跨进程通信的问题。
其实第二步骤已经结束了,但我们之前说了比如说AppBindRecord
呀,ConnectionRecord
呀,IntentBindRecord
呀
所以我们来看看这个AppBindRecord的一个结构
3.2.4AppBindRecord结构
final class AppBindRecord {
final ServiceRecord service; // The running service.
final IntentBindRecord intent; // The intent we are bound to.
final ProcessRecord client; // Who has started/bound the service.
final ArraySet<ConnectionRecord> connections = new ArraySet<>();
// All ConnectionRecord for this client.
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "service=" + service);
pw.println(prefix + "client=" + client);
dumpInIntentBind(pw, prefix);
}
void dumpInIntentBind(PrintWriter pw, String prefix) {
final int N = connections.size();
if (N > 0) {
pw.println(prefix + "Per-process Connections:");
for (int i=0; i<N; i++) {
ConnectionRecord c = connections.valueAt(i);
pw.println(prefix + " " + c);
}
}
}
AppBindRecord(ServiceRecord _service, IntentBindRecord _intent,
ProcessRecord _client) {
service = _service;
intent = _intent;
client = _client;
}
public String toString() {
return "AppBindRecord{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + service.shortInstanceName + ":" + client.processName + "}";
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(AppBindRecordProto.SERVICE_NAME, service.shortInstanceName);
proto.write(AppBindRecordProto.CLIENT_PROC_NAME, client.processName);
final int N = connections.size();
for (int i=0; i<N; i++) {
ConnectionRecord conn = connections.valueAt(i);
proto.write(AppBindRecordProto.CONNECTIONS,
Integer.toHexString(System.identityHashCode(conn)));
}
proto.end(token);
}
}
可以看到,它的内部有四个成员变量,分别是ServiceRecord类型,IntentBindRecord类型,ProcessRecord类型和一个ConnectionRecord的集合。
而IntentBindRecord中存储有一个ServiceRecord,这是用来描述被绑定的Service的;还有一个Key为ProcessRecord,Value为AppBindRecord的Map。
3.3ActivityThread到Service的绑定
ActivityThread到Service的启动调用的是scheduleCreateService,但是ActivityThread到Service的绑定却是scheduleBindService
方法,所以我们看看scheduleBindService的源码
3.3.1scheduleBindService源码
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false);
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
if (DEBUG_SERVICE)
Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
sendMessage(H.BIND_SERVICE, s);
}
它和scheduleCreateService差不多,最后都是通过sendMessage在handle中进行处理
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
会发现它调用了handleBindeService方法
我们看看它的源码
3.3.2handleBindService源码
private void handleBindService(BindServiceData data) {
CreateServiceData createData = mServicesData.get(data.token);
Service s = mServices.get(data.token);//1---------1
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess(isProtectedComponent(createData.info),
s.getAttributionSource());
try {
if (!data.rebind) {//2--------2
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {//3---------3
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
一样,又不太一样,我们在handleCreateService的源码中是先通过classLoader创建一个Service对象,然后绑定context给service但是
它是通过
Service s = mServices.get(data.token);
获得一个service的绑定对象
然后当service不为空的话,如果Service已经调用过unbind方法就会进入到注释三处的分支,触发onRebind的回调;不然就会进入到注释二的分支处,先触发onBind回调之后又会调用AMS的publicService方法。
3.3.3AMS的publishService方法
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
for (int conni = connections.size() - 1; conni >= 0; conni--) {
ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
........
try {
c.conn.connected(clientSideComponentName, service, false);//1-----1
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.shortInstanceName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
这里就是遍历了Service中的所有ConnectionRecord对象,然后调用conncted方法,这个我们在之前也提到过,最后是会调用到LoadedApk的connected方法
3.3.4LoadedAPK的connected方法
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityExecutor != null) {
mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
} else if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
..........
if (dead) {
mConnection.onBindingDied(name);
} else {
// If there is a new viable service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);//1------1
} else {
// The binding machinery worked, but the remote returned null from onBind().
mConnection.onNullBinding(name);
}
}
}
这就是执行了我们bindService是传入的ServiceConnection对象的回调方法,这样就完成了整个Service的绑定过程了
Comments | NOTHING