从AILD与bindService谈Binder进程间通信原理(下)
上文回顾
从AILD与bindService谈Binder进程间通信原理(上)
上一篇文章主要讲述了,在Client进程向AMS所在进程发起bindService操作的服务请求的过程中,Binder是如何跨进程通信的。实际上,Java层的Binder进程间通信都是同样的流程。主要有以下2点:
1,A进程持有B进程的IBinder对象(BinderProxy对象,对应原生层的BpBinder对象),通过这个Binder代理A进程即可与B进程进程间通信。
2,Binder代理的获取有两种方式,一种是通过查询ServiceManager获取,一种是通过一个中间进程(例如AMS进程)互相交换各自binder代理(实质上ServiceManager也是一个中间进程,不过他把服务进程的binder代理给保存下来)。
正文
接下来,我们将分析剩余的bindService所涉及的操作步骤:
上篇文章讲述到在第22-27步中, 在AMS的Binder对象ActivityManagerNative中解包Parcel,获取Client进程传递过来的参数,主要包括Client进程的2个BinderProxy,Client创建的用于bindeService操作的ServiceConnection对象的BinderProxy,以及Intent对象。最后调用ActivityManagerService类中的bindeService方法。
28,AMS会执行自身的成员变量mServices的bindServiceLocked方法。mServices是一个ActiveServices对象。ActiveServices才是AMS中真正管理Service的实现类。
int bindServiceLocked(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
…………………………………………………………………………………………………………
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);
ServiceRecord s = res.record;
…………………………………………………………………………………………………………
try {
…………………………………………………………………………………………………………
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);//yyt
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);//yyt
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);
}
b.client.connections.add(c);
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.hasAboveClient = true;
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {
return 0;
}
}
………………………………………………………………………………………………………………………………………………………………
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
在bindServiceLocked方法中,首先调用retrieveServiceLocked方法检索将要启动的Service所在,是否是在本应用中的Service,通过Service的name和filter来进行检索,找到目标Service后,查看权限(permission是否满足),如果该Service是第一次被检索,则会创建一个新的ServiceRecord对象保存这个Service的信息,这个ServiceRecord会在bringUpServiceLocked方法中被保存到一个mPendingServices数组集合中。
然后会把刚才的ServiceConnection对象封装成一个ConnectionRecord对象,并存入ServiceRecord的相关成员列表中。接着再调用bringUpServiceLocked方法
29,在bringUpServiceLocked方法中,判断目标Service所在的app进程是否已经启动,如果已经启动则直接调用realStartServiceLocked方法启动Service;如果app进程没启动,即为null,则调用startProcessLocked启动目标Service所在的目标app进程。
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
…………………………………………………………………………………………
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
// If a dead object exception was thrown -- fall through to