本文内容多是出自《Android进阶解密》一书。所以,可能不会为大家提供多少帮助,我写本文的目的只是为了自己再学习的时候能够有个印象,为自己提供一个方便。
Service的绑定过程分为两个部分,分别是ContextImpl到AMS的调用过程和Service的绑定过程。
在开始学习之前,先将几个相关的类介绍一下。
ServiceRecord:跟ActivityRecord功能类似,ActivityRecord用来描述一个Activity,相应的ServiceRecord就是用来描述一个Service。
ProcessRecord:描述一个进程的信息。
ConnectionRecord:描述应用程序进程和Service建立的一次通信。
IntentBindRecord:用于描述绑定Service的Intent。
AppBindRecord:应用程序进程通过Intent绑定Service时,会通过AppBindRecord来维护Service与应用程序进程之间的关联。
这一过程跟在学习Service的启动过程中的ContextImpl到AMS的调用过程是极其相似的。首先我们在其他组件中通过bindService来绑定Service时会调用到ContextWrapper类的bindService方法。其代码实现如下:
@Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { return mBase.bindService(service, conn, flags); }
在Android Service的启动过程一文中我们分析过mBase指的就是ContextImpl,接着查看ContextImpl的bindService方法。代码如下:
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
在bindService方法中,返回了bindServiceCommon方法。现在看一下此方法中做了些什么重要的操作。其代码如下:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
// 注释1
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
// 注释2
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
// 注释3
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, 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();
}
}
注释1处,对ServiceConnection对象做了非空的判断,当其为空时抛出了一个“connection is null”的异常。所以,在调用bindService方法时,传入的ServiceConnection对象一定为非空的。注释2处,调用了LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,它的主要作用是将ServiceConnection封装为IServiceConnection类型的对象sd。注释3处的代码我们并不陌生,最终会调用到AMS的bindService方法。至此ContextImpl到AMS的调用过程就结束了。这一过程的时序图如下:
此时代码已经执行到AMS的bindService方法,该方法中返回了ActiveServices类的bindServiceLocked方法。现在看一下bindServiceLocked方法中做了什么处理。关键代码如下:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
// 代码省略。。。。
try {
// 代码省略。。。
// 注释1
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
//。。。。
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
// 注释2
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
// 。。。。
// 注释3
if (s.app != null && b.intent.received) {
// Service is already running, so we can immediately
// publish the connection.
try {
// 注释4
c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")", e);
}
// 注释5
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
// 注释6
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {// 注释7
// 注释8
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
bindServiceLocked方法中,关键性的代码比较多。其中,注释1处:调用了ServiceRecord的retriveAppBindingLocked方法来获得AppBindRecord。注释2处的判断条件表明此时Service还没有启动,调用bringUpServiceLocked方法启动Service。Service启动的过程在上篇文章已经学习过了此处不再赘述。注释3处s.app!=null表示Service已经启动。s表示ServiceRecord,app表示ProcessRecord类型的对象。b.intent.received表示当前应用程序进程已经接收到绑定Service时返回的Binder。注释4,调用c.conn的connected方法,c.conn指代IServiceConnection,具体实现是ServiceDispatcher.InnerConnection。注释5表示如果当前应用程序进程是第一个与Service进行绑定的,并且Service已经调用了onUnBind方法。看一下b.intent.doRebind为true为什么表明Service调用了onUnBind方法。跟进b.intent代码,进入到IntentBindRecord类找到变量doRebind。注释为:
/** Set when the service's onUnbind() has asked to be told about new clients. */
boolean doRebind;
注释的意思是:当Service的onUnBind方法被调用并且通知到新的客户端的时候被设置。
注释6和注释8调用的方法是一致的,只不过最后一个参数boolean类型的rebind的值不一样。注释6传入true表示是重新绑定,需要回调onRebind;而注释8传入的false表明不是重新绑定,不需要回调onRebind。注释7,"!b.intent.requested"表明Client端没有发送过绑定Service的请求。接下来看一下requestServiceBindingLocked方法做了什么处理。代码如下:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
// 。。。
// 注释1
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
// 注释2
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
//。。。
}
}
return true;
}
有两处需要注意的。注释1:"!i.requested"表示没有发送过绑定Service的请求,而rebind表示是否需要重新绑定Service。上面分析bindServiceLocked方法中注释5和注释7的时候提到过,注释5b.intent.app.size() == 1表明是第一个与Service绑定的,所以通过注释6调用到的requestServiceBindingLocked方法注释1中"!i.requested"不成立,但是rebind为true是成立的;如果在注释7的判断条件下通过注释8调用到的requestServiceBindingLocked方法注释1中"!i.requested"是成立的,但是rebind为true是不成立的。所以,此处(!i.requested || rebind)总会得到满足,而后面的i.apps.size() > 0 表示所有用当前Intent绑定Service的应用程序进程个数大于0。跟进i.apps的代码。如下:
final class IntentBindRecord {
// 。。。。
/** All apps that have bound to this Intent. */
final ArrayMap apps
= new ArrayMap();
}
此时,我们回到bindServiceLocked方法的注释1处,ServiceRecord的retrieveAppBindingLocked方法。代码如下:
public AppBindRecord retrieveAppBindingLocked(Intent intent,
ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
// 注释1
i = new IntentBindRecord(this, filter);
bindings.put(filter, i);
}
// 注释2
AppBindRecord a = i.apps.get(app);
if (a != null) {
return a;
}
// 注释3
a = new AppBindRecord(this, i, app);
i.apps.put(app, a);
return a;
}
注释1处创建了IntentBindRecord,注释2处,根据ProcessRecord获得IntentBindRecord中存储的AppBindRecord,如果AppBindRecord不为null就直接返回,如果为null就在注释3处创建AppBindRecord,并将ProcessRecord作为key,AppBindRecord作为value保存在IntentBindRecord的apps(i.apps)中。因此,requestServiceBindingLocked方法注释1中i.apps.size()>0成立。所以该方法中注释2处的代码:r.app.thread.scheduleBindService方法就会得到调用。之前分析过r.app.thread指代的是IApplicationThread,而ApplicationThread是ActivityThread的内部类,这样代码就执行到了ApplicationThread的scheduleBindService方法。该方法的最后通过sendMessage方法向H类发送了一条BIND_SERVICE类型的消息。之前就已经提到过,H是ActivityThread类的内部类继承了Handler。我们接着看H的handleMessage方法中对BIND_SERVICE类型消息的处理。代码如下:
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
// 代码省略。。。。
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
// 关键代码
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
// 代码省略。。。。
}
//。。。。
}
handleMessage方法中关键代码就是调用了handleBindService方法。现在看一下其中做了什么操作,代码如下:
private void handleBindService(BindServiceData data) {
// 注释1
Service s = mServices.get(data.token);
// 代码省略。。。
try {
// 注释2
if (!data.rebind) {
// 注释3
IBinder binder = s.onBind(data.intent);
// 注释4
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
// 注释5
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
注释1处,从Map集合中获取要绑定的Service。注释2处,如果传递进来的BindServiceData.rebind为false(对应bindServiceLocked方法中注释8处的调用),就会调用注释3中的代码来调用Service的onBind方法,并且将IBinder对象返回到onBind方法,至此Service就处于绑定状态了。相反,如果传递进来的BindServiceData.rebind为true时(对应bindServiceLocked方法中注释6处的调用)就会调用Service的onRebind方法。此处结合bindServiceLocked方法的注释5处得出的结论就是:如果当前应用程序进程第一个与Service进行绑定,并且Service已经调用过onUnBind方法,则会调用Sservice的onRebind方法。在ActivityThread的handleBindService方法的注释5这种情况是之前已经进行过绑定,不做分析。只分析之前没有绑定过Service的情况,此时看注释4处的代码,调用了AMS的publishService方法。
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
// 关键代码。。。
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
调用了ActiveServices的publishServiceLocked方法。代码如下:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
// 关键代码。。。
c.conn.connected(r.name, service, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
}
在ActiveServices.publishServiceLocked方法中,关键代码就是调用了
c.conn.connected(r.name, service, false);
c.conn指的是IServiceConnection它是ServiceConnection在本地的代理,用于解决当前应用程序进程和Service跨进程通信的问题,具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,ServiceDispatcher.InnerConnection的connected方法代码如下:
static final class ServiceDispatcher {
.....
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference(sd);
}
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
// 关键代码。。。
sd.connected(name, service, dead);
}
}
}
.....
}
关键代码调用了ServiceDispatcher的connected方法。代码:
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
// 注释1:指代的是向Handler发送消息
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
// 注释2
doConnected(name, service, dead);
}
}
注释1处,调用Handler类型的对象mActivityThread的post方法,将RunConnection对象的内容运行在主线程中。RunConnection的定义如下:
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
// 关键代码
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
RunConnection实现了Runnable接口,其run方法中调用了doConnected方法。这和connected方法注释2中调用的方法是一致的。这就说明代码执行到此处无论什么情况都会调用doConnected方法。其代码如下:
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
......
// If there was an old service, it is now disconnected.
if (old != null) {
// 注释1.。。
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// If there is a new service, it is now connected.
if (service != null) {
// 注释2.。。
mConnection.onServiceConnected(name, service);
}
}
根据代码中的注释我们也能明白,如果此时有之前的service,就会调用ServiceConnection的onServiceDisConnected方法。如果此时传递进来的IBinder类型的service不为空就会调用ServiceConnection的onServiceConnected回调方法。至此,Service的绑定过程就学习完了。最后附上绑定过程的时序图。如下:
至此,Service的整个绑定过程就学习完成了。本文到此也就结束了。感谢《Android进阶解密》一书的作者,刘望舒先生。