bindService流程源码分析
bindService流程源码分析
一、简介
bindService是应用用来与service进行绑定的。该方式启动的service系统认为只有在调用者的context存在时service才有必要运行,比如在activity中调用该方法且该activity处于stopped状态,那么其绑定的服务在activity返回前台前不会运行。
还有就是不能在未注册的BroadcastReceiver调用该方法(只能通过startService来启动service),通过registerReceiver注册的广播可以调用因为此时BroadcastReceiver的生命周期已经和注册对象绑定了。
二、源码分析
bindService是在Context类中定义的具体实现则是在ContextImpl类中。
public abstract boolean bindService(@RequiresPermission Intent service,
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
ContextImpl类中的bindService调用了bindServiceCommon做进一步处理。注意下传入的mMainThread.getHandler()参数,mMainThread是一个ActivityThread实例,所以此处获取的是ActivityThread所在线程的Handler,后面我们就可以通过这个handler把消息分发到ActivityThread线程的消息队列中。
在bindServiceCommon中主要做了两件事一是获取一个IServiceConnection接口,二是调用AMS的远程接口bindService
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
//1、调用getServiceDispatcher来获取一个IServiceConnection接口
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
try {
//2、调用AMS的bindService
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
我们来分析下getServiceDispatcher获取IServiceConnection接口的过程。
getServiceDispatcher主要做了以下事情:
根据传入的context在mServices中查找是否已经存在对应的ServiceDispatcher实例,如果没有则创建并存入mServices,最后调用getIServiceConnection返回一个IServiceConnection,此处实际是一个InnerConnection实例,它是一个binder对象,后续AMS会用它和ServiceConnection通信
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
//1、根据传入的context在mServices中查找是否已经存在对应的ServiceDispatcher实例
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == null) {
//2、mServices中没有对应的ServiceDispatcher实例创建新实例
sd = new ServiceDispatcher(c, context, handler, flags);
if (DEBUG) Slog.d(TAG, “Creating new dispatcher “ + sd + “ for conn “ + c);
if (map == null) {
map = new ArrayMap<>();
//3、存入mServices
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
//4、getIServiceConnection返回一个IServiceConnection,此处实际是一个InnerConnection实例,它是一个binder对象后续AMS会用它和ServiceConnection通信
return sd.getIServiceConnection();
}
}
我们继续看下ServiceDispatcher的getIServiceConnection,他返回的是ServiceDispatcher.InnerConnection实例,这个是在ServiceDispatcher构造函数内创建的。
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
//….
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
mIServiceConnection = new InnerConnection(this);//创建InnerConnection实例
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
}
最后贴下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);
}
}
}
getServiceDispatcher之后就是调用AMS的bindService,如下所示:
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);
}
}
bindService做了一些检查后调用ActiveServices的bindServiceLocked。
bindServiceLocked比较长我们只看关键部分。它的主要操作可以分为4步具体可以看下面的注释。
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
//…
//1、首先会根据token找到其对应的ActivityRecord,我们之前说过ActivityRecord表示的是一个activity记录,此处指的是调用bindService的activity
ActivityRecord activity = null;
if (token != null) {
activity = ActivityRecord.isInStackLocked(token);
if (activity == null) {
Slog.w(TAG, “Binding with unknown activity: “ + token);
return 0;
}
}
//…
//2、调用retrieveServiceLocked解析传入的intent等参数获得一个ServiceRecord对象
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
ServiceRecord s = res.record;
//...
//3、把传入的connection封装成一个ConnectionRecord对象,connection就是步骤3获得的InnerConnection,
// 因为后续AMS需要使用它来告诉activity service已经启动起来了,所以要把它保存起来,这里保存在好几个地方
//AppBindRecord中存储了当前ServiceRecord, intent以及发起方的进程信息。
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
// clist是ServiceRecord.connections的成员变量
clist.add(c);
//b是指AppBindRecord
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);
//...
//4、最初绑定service时传入的flag是BIND_AUTO_CREATE,所以此处符合条件进而调用bringUpServiceLocked启动要绑定的service
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
//…
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
s.app.treatLikeActivity = true;
}
//5、更新service所在进程的优先级
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
|| s.app.treatLikeActivity, b.client);
mAm.updateOomAdjLocked(s.app);
}
if (s.app != null && b.intent.received) {
try {
//6、Service已经正在运行,则调用InnerConnection的代理对象
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
...
}
//7、当第一个app连接到该binding, 且之前已被bind过, 则回调onRebind()方法
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
//8、最终回调onBind()方法
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
return 1;
}
bindServiceLocked做的事情比较多,我们再来梳理一下,首先在注释1处查找请求绑定的Activity是否存在,之后在注释2处通过retrieveServiceLocked查找对应的service。在注释3处创建AppBindRecord和ConnectionRecord,AppBindRecord记录着当前ServiceRecord, intent以及发起方的进程信息,ConnectionRecord则是对connection进行封装。创建完成后会把ConnectionRecord存到ServiceRecord和AppBindRecord中。注释4处通过bringUpServiceLocked来启动service,之后在注释5处更新service所在进程的优先级,在注释6处Service已经正在运行,调用InnerConnection的代理对象。注释7处判断是否回调onRebind方法。注释8处requestServiceBindingLocked最终回调onBind()方法。
我们先来看下retrieveServiceLocked查找对应的service的过程,然后再看service绑定过程,至于service启动过程我们之前在startService的源码分析中已经说到过,具体可以参考startService过程源码分析.md
retrieveServiceLocked如下所示:
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
ServiceRecord r = null;
if (comp != null) {
//根据service名称查找ServiceRecord
r = smap.mServicesByName.get(comp);
if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
}
...
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
//根据Intent查找相应的ServiceRecord
r = smap.mServicesByIntent.get(filter);
if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
}
...
//通过PKMS来查询相应的service
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId, callingUid);
...
//创建ServiceRecord对象
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
...
//各种权限检查,不满足条件则返回为null的service
if (mAm.checkComponentPermission(r.permission,
callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
//当exported=false则不允许启动
if (!r.exported) {
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " that is not exported from uid " + r.appInfo.uid);
return new ServiceLookupResult(null, "not exported from uid "
+ r.appInfo.uid);
}
}
Service查找过程:
- 根据服务名从ServiceMap.mServicesByName中查找相应的ServiceRecord,如果没有找到,则往下执行;
- 根据Intent从ServiceMap.mServicesByIntent中查找相应的ServiceRecord,如果还是没有找到,则往下执行;
- 通过PKMS来查询相应的ServiceInfo,如果仍然没有找到,则不再往下执行。
接下来看下service的绑定:service的启动最终是在realStartServiceLocked里
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
//…
//1、创建service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
//...
//2、调用requestServiceBindingsLocked
requestServiceBindingsLocked(r, execInFg);
//...
}
requestServiceBindingsLocked调用requestServiceBindingLocked来进一步处理,通过bindService方式启动的服务, 那么该serviceRecord的bindings则一定不会空。requestServiceBindingLocked里依次调用requestServiceBindingLocked。
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int I=r.bindings.size()-1; I>=0; I—) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
requestServiceBindingLocked函数如下所示:
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
// If service is not currently running, can’t yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
//发送bind开始的消息
bumpServiceExecutingLocked(r, execInFg, "bind");
//调用ApplicationThread的scheduleBindService进入bind流程
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
} catch (TransactionTooLargeException e) {
//...
} catch (RemoteException e) {
//…
}
}
return true;
}
我们看到它先发送了bind消息然后调用了ApplicationThread的scheduleBindService进入bind流程。
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;
//发送BIND_SERVICE message
sendMessage(H.BIND_SERVICE, s);
}
public void handleMessage(Message msg) {
case BIND_SERVICE:
//BIND_SERVICE消息处理
handleBindService((BindServiceData) msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
在函数中发送了BIND_SERVICE消息,该消息的的处理是在handleBindService函数中,如下所示
private void handleBindService(BindServiceData data) {
//1、根据token获取要绑定的service
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
//2、回调service的onBind
IBinder binder = s.onBind(data.intent);
//3、把步骤2得到的binder(即onBind的返回值)传递给AMS
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();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
//…
}
}
}
在该函数中首先根据token获取要绑定的service,之后回调service的onBind拿到一个binder对象(这个binder就是onBind的返回值),最后传递给AMS。
AMS的publishService如下所示:
public void publishService(IBinder token, Intent intent, IBinder service) {
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 {
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;
for (int conni=r.connections.size()-1; conni>=0; conni—) {
//1、从ServiceRecord.connections中取出ConnectionRecord
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int I=0; I<clist.size(); I++) {
ConnectionRecord c = clist.get(i);
try {
//2、调用ConnectionRecord.conn.connected,此处的ConnectionRecord.conn是之前创建的LoadedApk.ServiceDispatcher.InnerConnection对象
c.conn.connected(r.name, service, false);
} catch (Exception e) {
//...
}
}
}
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
InnerConnection的connected函数如下所示:
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) {
//调用ServiceDispatcher的connected
sd.connected(name, service, dead);
}
}
}
它调用了ServiceDispatcher的connected,connected如下所示
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);
}
}
此处的mActivityThread就是主线程的Handler,通过该Handler post消息。
RunConnection的run如下
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进行绑定
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
doConnected函数如下:
public void doConnected(ComponentName name, IBinder service, boolean dead) {
if (service != null) {
// A new service is being connected... set it all up.
info = new ConnectionInfo();
info.binder = service;
//创建死亡监听对象
info.deathMonitor = new DeathMonitor(name, service);
try {
//建立死亡通知
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
// This service was dead before we got it... just
// don't do anything with it.
mActiveConnections.remove(name);
return;
}
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
// If there was an old service, it is now disconnected.
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
// If there is a new service, it is now connected.
if (service != null) {
//回调onServiceConnected,至此我们就在绑定端的onServiceConnected回调函数中拿到service返回的binder了
mConnection.onServiceConnected(name, service);
}
}
在doConnected函数中首先会创建死亡监听对象并建立死亡通知,之后会回调onServiceConnected。
至此bindService的过程就结束了,总结来整个过程大概分为以下几步:
1、首先调用bindService通知AMS绑定service,AMS会先启动service回调其onCreate函数。
2、AMS启动service完成之后继续调用service的onBind函数,获取service返回的binder。
3、AMS把上一步获得的Binder对象通过绑定时传入的ServiceConnection的onServiceConnected函数传给调用端,这样调用端就可以通过binder来调用service提供的相关方法。
- Client进程: 通过getServiceDispatcher获取Client进程的匿名Binder服务端,即LoadedApk.ServiceDispatcher.InnerConnection,该对象继承于IServiceConnection.Stub; 再通过bindService调用到system_server进程;
- system_server进程: 依次通过scheduleCreateService和scheduleBindService方法, 远程调用到target进程;
- target进程: 依次执行onCreate()和onBind()方法; 将onBind()方法的返回值IBinder(作为target进程的binder服务端)通过publishService传递到system_server进程;
- system_server进程: 利用IServiceConnection代理对象向Client进程发起connected()调用, 并把target进程的onBind返回Binder对象的代理端传递到Client进程;
- Client进程: 回调到onServiceConnection()方法, 该方法的第二个参数便是target进程的binder代理端. 到此便成功地拿到了target进程的代理, 可以畅通无阻地进行交互.
参考: