大家好,又见面了,我是你们的朋友全栈君。
bindService的流程,入口同样在ContextImpl中。
ContextImpl.java
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), Process.myUserHandle());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) {
IServiceConnection sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
validateServiceIntent(service);
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, getOpPackageName(), user.getIdentifier());
return res != 0;
}
类似startService,bindService也是经由bindServiceCommon交由AMS处理。
要注意的是bind连接回调ServiceConnection是引用类型,因为bindService可能是跨进程的,需要先将其转换为bind接口IServiceConnection,具体实现为ServiceDispatcher的内部类InnerConnection,充当了Binder的角色。
ActivityManagerService.java
public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String callingPackage, int userId) throws TransactionTooLargeException {
......
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, callingPackage, userId);
}
}
AMS中同样直接交给了ActiveService.bindServiceLocked处理。
这个方法的处理步骤如下:
- 从ServiceMap中查找ServiceRecord,并且在查的时进行了exported属性、权限等校验。
- 将Service调用方和被调用方的信息保存到AMS中;
- 创建连接信息;
- 将连接信息保存到mServiceConnections中;
- 如bind的flag包含BIND_AUTO_CREATE,则先尝试启动Service;
- 如此intent未被连接过,直接建立连接,回调onServiceConnected;
- Service未被bind过,需先调用onBind后,再回调onServiceConnected。
连接的过程分为2种场景:已经bind过 和 未被bind过,这2种场景如何区分呢?
s.app != null && b.intent.received,回到前面创建AppBindRecord的代码:
// 3.创建连接信息
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent);
具体看ServiceRecord的retrieveAppBindingLocked方法实现:
public AppBindRecord retrieveAppBindingLocked(Intent intent, ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
// bindings是一个map
IntentBindRecord i = bindings.get(filter);
if (i == null) {
i = new IntentBindRecord(this, filter);
bindings.put(filter, i);
}
AppBindRecord a = i.apps.get(app);
if (a != null) {
return a;
}
a = new AppBindRecord(this, i, app);
i.apps.put(app, a);
return a;
}
从这个方法中可以看出,如果fileter不同,即intent数据不同,将返回一个新的AppBindRecord对象。再去看Intent.FilterComparison equals()的实现,其比较的是Intent的数据。即,同一个app bind同一个Service,如果bind时传递的Intent数据一致,将共享同一个AppBindRecord。也就是说,bindServiceLocked中认为Service已经连接,需要满足2个条件:
- Service已启动
- 调用bindServce时传递的Intent没有被连接过,即intent数据不一样,会再次触发onBind。
这个设计给我们提供了一种新的思路:在一个Service中,可以根据需要为不同的启动参数,提供不同的binder服务,从而使Service内部逻辑更加清晰。
继续看bind的过程:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if ((!i.requested || rebind) && i.apps.size() > 0) {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
}
return true;
}
调用ActivityThread进行bind,这里不关注ActivityThread内部消息派发过程,直接看bind的实现。
ActivityThread.java
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
......
}
调用Service.onBind后,继续调用AMS.publishService发布Service。
public void publishService(IBinder token, Intent intent, IBinder service) {
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
继续看ActiveServices.publishServiceLocked。
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
// 1.将IntentBindRecord.binder赋值为onBinder返回的Binder对象
b.binder = service;
b.requested = true;
// 2.将IntentBindRecord.binder置为true,表示已调用onBind
b.received = true;
// 3.遍历此Service的所有连接记录
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
continue;
}
// 找到匹配的intent进行连接
c.conn.connected(r.name, service, false);
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
publish过程主要做了3件事:
- 将IntentBindRecord.binder赋值为Service.onBinder返回的Binder对象;
- 将IntentBindRecord.binder置为true,表示已调用onBind;
这一步骤后,其他client再通过相同的intent数据进行bind,将直接进行连接,不会再进行onBind的过程。 - 遍历此Service的所有连接记录,找到匹配的intent进行连接。
接下看connect的具体过程:
在前面ContextImp.bindServiceCommon中已经知道,传递到AMS中的ServiceConnection是经过包装的IServiceConnectionBinder对象,所以connect的过程实际上是在启动方进程中进行的。此IServiceConnection是LoadedApk的静态内部类InnerConnection。
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(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);
}
}
}
InnerConnection直接将连接的处理逻辑交给了ServiceDispatcher。
static final class ServiceDispatcher {
public void connected(ComponentName name, IBinder service, boolean dead) {
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) {
// 已经unbind,不做处理
if (mForgotten) {
return;
}
// old不为null,表示此ServiceConnection进行了其他连接
old = mActiveConnections.get(name);
// 同一个Connection已进行过连接,不做处理
if (old != null && old.binder == service) {
return;
}
// IBinder对象不为null,表示建立新连接
if (service != null) {
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
// linkToDeath
service.linkToDeath(info.deathMonitor, 0);
// 保存连接信息
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return;
}
} else {
// IBinder对象为null,表示断开连接
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// 先移除旧连接
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// 新连接,回调onServiceConnected
if (service != null) {
mConnection.onServiceConnected(name, service);
}
}
private final class DeathMonitor implements IBinder.DeathRecipient {
DeathMonitor(ComponentName name, IBinder service) {
mName = name;
mService = service;
}
public void binderDied() {
death(mName, mService);
}
final ComponentName mName;
final IBinder mService;
}
public void doDeath(ComponentName name, IBinder service) {
synchronized (this) {
ConnectionInfo old = mActiveConnections.get(name);
if (old == null || old.binder != service) {
return;
}
// 移除ConnectionInfo
mActiveConnections.remove(name);
// 调用unlinkToDeath
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
// 调用ServiceConnection.onServiceDisconnected
mConnection.onServiceDisconnected(name);
}
}
ServiceDispatcher.connected继续调用doConnected,doConnected中做了以下几件事情:
-
判断是否为重复bind,如是则直接return;
-
如IBinder对象不为null,表示新建连接,保存连接信息,linkToDeath;为null,表示断开连接;
linkToDeath的目的是在Service被异常kill后,移除连接信息,并且回调ServiceConnection.onServiceDisconnected。 -
如此ServiceConnection已进行了其他连接,则先断开原有连接;
此场景出现在:
1)unbindService,具体过程下面分析;
2)用同一个ServiceConnection去bind同一个Service,onBind触发了多次的情况,即bind时intent参数有变化。 -
新连接建立完成,回调ServiceConnection.onServiceConnected
至此,一次bind连接已经完成,之后启动方就可以通过连接成功后返回的IBinder对象与Service进行交互了。
一次bind连接的完整流程如下:
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143803.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...