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進程的代理, 可以暢通無阻地進行交互.
參考: