本片文章主要是来介绍Service组件的工作过程的,主要分成Service的启动和Service的绑定两个部分来讲。上一篇文章我们已经介绍了Activity的工作工程,而Service的工作过程也与Activity有一定的相关之处,也会涉及到AMS(ActivityManagerService)
上篇文章:
Service的启动过程可以分为三个个过程,实际上也和Activity的工作过程相类似了。可以分为从ContextImpl到AMS的调用过程,从AMS到ActivityThread以及ActivityThread启动Service。
我们先来看第一个部分,从ContextImpl到AMS的调用过程。如果要启动Service,我们首先会通过ContextWrapper的startService来开启流程。这个ContextWrapper是Context的子类,它实现了Context中的方法,我们就来看ContextWrapper的startService方法:
.......
Context mBase;
.......
public @Nullable ComponentName startService(Intent service) {
return mBase.startService(service);
}
它会调用类型为Context类的startService,Context类是一个抽象类,所以我们需要找到它的实现类,这个具体的实现类实际上我们在根Activity的创建过程中已经提到过了,可以回顾一下:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
ContextImpl appContext = createBaseContextForActivity(r);//1-----1
........
}
我们直接看performLaunchActivity中的注释一处,这里就创建出了Context的实现类,并且在之后的attach方法中将其与Activity进行了绑定,可以看一下createBaseContextForActivity方法:
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方法:
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();
}
}
看重点,这里的重点显然就是注释一处的 ActivityManager.getService().startService()方法,看起来它会调用到AMS的startService方法,实际上也正是这样,和Activity的创建一样,是通过远程调用了AMS的方法。
到此为止,就正式进入到了AMS的处理和方法调用过程了,所以接下来让我们看第二部分。
上面提到远程调用到了AMS的startService方法,所以我们继续来看AMS的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;
}
}
startService的重头就是继续调用到了注释一处的startServiceLocked方法,接下来会进行一系列的跳转:
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方法中,我们直接看这个方法:
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方法。
若需要的进程不存在的话,就会进入到注释四处的分支处,紧接着会运行到注释五处的分支来启动一个新的进程。不过这不是我们的重点,我们继续回到注释三处的方法处。让我们看这个方法:
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启动的最后一部分。
接下来进入到了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);
}
这个方法具体就是触发了自身Handler的方法,我们来看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;
继续看中间的handleCreateService方法:
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的实例。接着在注释二处通过attach方法将service自身的context进行了绑定。
注释三处,调用了Service的onCreate回调;最后注释四处将当前Service添加入ActivityThread的service列表中便于后续管理。一切都完毕后,调用注释五处的方法通知AMS当前Service创建完毕了,这个方法用于标记服务执行完成,并根据不同的类型和结果执行相应的操作。
到这里为止,Service的启动过程就介绍完毕了。接下来我们来探讨Service的绑定过程。
我们知道Service除了可以用Start启动外,还可以通过Bind方法进行客户端的绑定,接下来我们就来看Service的绑定过程。
Service的绑定过程我们也可以分成两个过程:ContextImpl到AMS的调用过程和Service的绑定过程。
先来看第一个阶段,这个阶段和之前start过程很像,具体来说就是通过ContextWrapper的bindService方法跳转到ContextImpe的bindService方法,所以这里我们就直接看ContextImpl的bindService方法了:
public boolean bindService(
Intent service, int flags, Executor executor, ServiceConnection conn) {
return bindServiceCommon(service, conn, flags, null, null, executor, getUser());
}
这实际上还是老过程,我们继续看它的bindServiceCommon方法:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser and
// ActivityManagerLocal.bindSdkSandboxService
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (handler != null && executor != null) {
throw new IllegalArgumentException("Handler and Executor both supplied");
}
if (mPackageInfo != null) {
if (executor != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
} else {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
}
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().bindServiceInstance( //1------1
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里我们看注释一处,其实这个过程真的是非常类似,接下来就会开始进入到AMS中调用AMS的方法了,接下来我们来看AMS中的调用。
上面说到了bindServiceInstance方法,接下来就看这个方法:
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:
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()
+ " flags=0x" + 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;
}
这里我们先介绍一下相关的类代表什么:
首先在注释一处获得了Service的AppBindRecord信息和ConnectionRecord信息;接着,如果创建的标注为BIND_AUTO_CREATE的话就会进入到注释二处的bringUpServiceLocked方法中,这个方法中又会调用到我们在启动流程中提到的realStartServiceLocked方法,也就是说会自动地创建和启动Service;注释三处的条件代表service已经运行,这样就会紧接着调用到注释四处的connected方法,具体来说是会调用到InnerConncetion的connected方法,并且最终调用到LoadedApk的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);
}
}
这会调用H(ActivityThread的Handler)的post方法向主线程发送消息,并且解决当前应用程序进程和Service跨进程通信的问题。接下来我们来看注释五到八的内容,其实他们最终调用到的都是requestServiceBindingLocked方法,唯一的差别就是最后一个参数的差别。具体来说这两个分支分别代表当前应用程序是不是第一个和Service绑定的。接下来再看requestServiceBindingLocked方法:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.getThread() == null) {
// If service is not currently running, can't yet bind.
return false;
}
if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
+ " rebind=" + rebind);
if ((!i.requested || rebind) && i.apps.size() > 0) {//1------1
try {
bumpServiceExecutingLocked(r, execInFg, "bind",
OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
r.app.getThread().scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.mState.getReportedProcState()); //2-----------2
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
// Keep the executeNesting count accurate.
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying, false);
throw e;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying, false);
return false;
}
}
return true;
}
我们先看注释一处的判断条件,i.requested表示当前Intent是否发送过绑定Service的请求。接下来我们还需要稍微分析一下IntentBindRecord。AMS会为每个绑定Service的Intent分配一个IntentBindRecord类型的对象。IntentBindRecord类中又有一个apps列表来存储当前Intent绑定Service的应用程序进程。所以i.apps.size() > 0代表当前Intent绑定Service的应用程序进程大于0。
看注释二处的代码,接下来就和之前一样,跳转到了ActivityThread之中了。
为了帮助我们更好地理解,我觉得还是有必要来详细地解析一下AppBindRecord的结构和它与其他辅助类的关系,我们先来看AppBindRecord的源码:
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。具体差不多就这样如图所述:
直接看ActivityThread的scheduleBindService方法:
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);
}
实际上还是老一套,会向自身的Handler发送消息,我们还是看Handler是如何处理这个标志位的:
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
显然是会接着调用handleBindService:
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);
}
}
}
}
在注释一处获得了要进行绑定的Service对象,如果已经Service已经调用过unbind方法就会进入到注释三处的分支,触发onRebind的回调;不然就会进入到注释二的分支处,先触发onBind回调之后又会调用AMS的publicService方法。我们来看publishServiceLocked方法:
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方法:
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);
}
}
}
上面的RunConnection实际上是LoadedApk的内部类,最后也是会执行doConnected方法。我们看上面的注释一处,这就是执行了我们bindService是传入的ServiceConnection对象的回调方法,这样就完成了整个Service的绑定过程了。
下面是我总结的一张关于Service工作过程的总结,其中省略了一些细节,主要是帮助理解大致的过程。相信大家也可以发现无论是绑定还是启动,其中都有很多的重合处,无非就是从AMS到ActiviyThread,并且都是通过远程调用的方式。如果要抠细节的话可以看一下AppBindRecord和其他辅助类的关系,这样可以帮助我们更好地理解这整个设计。