1.Service生命周期
上篇講到了startService的生命周期特姐,這篇的話,講第二種Service的啟動方式呆盖,bindService呢灶。
2.BindService時(shí)序圖
老規(guī)矩曾雕,看代碼前先放圖和措。相較startService庄呈,bindService的過程稍微復(fù)雜些。這里先介紹一下新增的幾個類派阱。
ServiceDispatcher 應(yīng)用端的Service連接的管理類诬留。管理連接的binder的狀態(tài)。
InnerConnection IServiceConnection.Stub的子類贫母。連接狀態(tài)控制Client和Service傳輸?shù)腷inder媒介文兑。
ActiveServices system_server端Service行為的管理類。
ServiceConnection 重寫它的兩個回調(diào)方法onServiceConnected()和onServiceDisconnected()腺劣,能在Service綁定和解綁時(shí)得到回調(diào)绿贞。
3.源碼分析
虛擬框架公司在國內(nèi)搭了一個AOSP源碼查詢的網(wǎng)站,更新的代碼已經(jīng)到Android Q橘原。所以之后的話可以直接看Q的代碼籍铁。
和startService類似,bindService
事實(shí)上通過mBase
調(diào)用到ContextImpl的bindService
趾断。一路調(diào)用到ActivityManager.getService().startService
拒名。前篇已經(jīng)說過,這個通過IPC調(diào)用到System_service進(jìn)程的ActivityManagerService芋酌。
ContextImpl
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());
}
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
// Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
//這里通過將傳入的ServiceConnection進(jìn)行緩存封裝增显,得到一個IServiceConnection對象。
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
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();
}
}
這里先看一下getServiceDispatcher的操作脐帝。這里以context
為key值同云,保存了連接類ServiceConnection
和傳輸類IServiceConnection
的值。
LoadedApk
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
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) {
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<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
ActivityManagerService還是直接調(diào)用ActiveServices的bindServiceLocked
方法腮恩。
ActivityManagerService
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws TransactionTooLargeException {
return bindIsolatedService(caller, token, service, resolvedType, connection, flags,
null, callingPackage, userId);
}
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String instanceName,
String callingPackage, int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
// Ensure that instanceName, which is caller provided, does not contain
// unusual characters.
if (instanceName != null) {
for (int i = 0; i < instanceName.length(); ++i) {
char c = instanceName.charAt(i);
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9') || c == '_' || c == '.')) {
throw new IllegalArgumentException("Illegal instanceName");
}
}
}
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, instanceName, callingPackage, userId);
}
}
public void updateServiceGroup(IServiceConnection connection, int group, int importance) {
synchronized (this) {
mServices.updateServiceGroupLocked(connection, group, importance);
}
}
bindServiceLocked
的過程梢杭,創(chuàng)建了一個bindings不為空的ServiceRecord對象,往下傳遞秸滴。我們啟動Service的時(shí)候武契,需要傳遞標(biāo)志位Context.BIND_AUTO_CREATE
。所以這里可以看到荡含,如果Service不在運(yùn)行狀態(tài)咒唆,又跑入了上一篇描述的bringUpServiceLocked
流程。這里不再此描述此流程释液∪停可以回看上一篇。
ActiveServices
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
...
try {
...
mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
callerApp.getCurProcState(), s.appInfo.uid, s.appInfo.longVersionCode,
s.instanceName, s.processName);
// Once the apps have become associated, if one of them is caller is ephemeral
// the target app should now be able to see the calling app
mAm.grantEphemeralAccessLocked(callerApp.userId, service,
UserHandle.getAppId(s.appInfo.uid), UserHandle.getAppId(callerApp.uid));
//這里對ServiceRecord的bindings做了賦值
//上一篇realStartServiceLocked方法沒有觸發(fā)requestServiceBindingsLocked
//但是這里就會不一樣了.
//需要注意的是误债,這里pendingStarts會為空浸船,所以后面的sendServiceArgsLocked不觸發(fā)
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent,
callerApp.uid, callerApp.processName, callingPackage);
IBinder binder = connection.asBinder();
s.addConnection(binder, c);
b.connections.add(c);
if (activity != null) {
activity.addConnection(c);
}
b.client.connections.add(c);
c.startAssociationIfNeeded();
...
//我們知道妄迁,如果需要Service不在運(yùn)行狀態(tài)的時(shí)候觸發(fā),需要設(shè)置標(biāo)志Context.BIND_AUTO_CREATE
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
...
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
和上一篇的realStartServiceLocked
行為不同的是李命,因?yàn)樯厦尜x值了bindings
登淘,所以在Service的onCreate
后,會觸發(fā)scheduleBindService
而不再是上篇的scheduleServiceArgs
封字。
ActiveServices
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
//Service的進(jìn)程拉起和onCreate觸發(fā)不再復(fù)述
//請看上一篇
...
//這里由于上面對bindings做了賦值黔州,所以能觸發(fā)
requestServiceBindingsLocked(r, execInFg);
//pendingStarts會為空,所以什么都沒做
sendServiceArgsLocked(r, execInFg, true);
...
}
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;
}
}
}
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
...
try {
...
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.getReportedProcState());
}
...
}
熟悉的ApplicationThread->H->ActivityThread
三連招阔籽。
ApplicationThread
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;
if (DEBUG_SERVICE)
Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
sendMessage(H.BIND_SERVICE, s);
}
H
case BIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
ActvityThread
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
//與StartService不同的是流妻,這里會調(diào)用
//AMS的publishService
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();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
AMS
的publishService
行為被觸發(fā)。
上面可以看到笆制,Service
已經(jīng)創(chuàng)建并且調(diào)用onCreate
方法绅这。下面我們看下scheduleServiceArgs
做了什么。
ActivityManagerService
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
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
...
try {
//這里是之前傳入的IServiceConnection對象
//所以我們直接往回找就好
c.conn.connected(r.name, service, false);
}
...
}
在LoadedApk里项贺,可以找到類InnerConnection君躺,看它的connected
行為峭判。
InnerConnection
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
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) {
...
// If there is a new viable service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
// The binding machinery worked, but the remote returned null from onBind().
mConnection.onNullBinding(name);
}
}
一路找下來开缎,其實(shí)就是把之前緩存的ServiceConnection
,觸發(fā)回調(diào)onServiceConnected
林螃。
這篇的話奕删,是基于Q的代碼看bindService的行為流程。這方面android P和Android Q基本沒有差異疗认。
整個流程的話完残,和上篇startService類似。不同的是因?yàn)槌跏蓟腟erviceRecord的參數(shù)不同横漏,所以觸發(fā)了bind谨设,后面publishService操作,主要是為了向發(fā)起bind的進(jìn)程傳遞binder信息缎浇。這個的話按圖理解流程扎拣,應(yīng)該來說還是相當(dāng)清晰的。
Service篇的話就這兩篇素跺,startService和bindService二蓝。Service其他相關(guān)的當(dāng)前應(yīng)當(dāng)不會寫相關(guān)博客。