上一篇我們講了Context和Activity的相關知識,
Android 插件化開發——基礎底層知識(Context家族史,Activity啟動流程)
本篇我們講述Service的工作流程
關于Service的建立啟動流程,其實和Activity的建立啟動流程是相似的。都是和AMS互動,通信媒體是:Binder
Service工作流程
關于Service的啟動方式,我們分為兩種:startService和bindService, 關于這兩個啟動方式的差別以及使用方法,在此不再贅述。
啟動建立Service,我們分為兩種:同一程序,不同程序。
新程序啟動Service
假設要在新程序啟動一個Service,可分為5個階段:
- APP給AMS發送消息,附帶Manifest定義的相關資訊。
- AMS檢查新的程序是否存在,如果不存在,就建立一個新的程序,并且把Service資訊儲存起來。
- 啟動新程序,然後通知AMS,:新的程序已經存在
- 此時AMS發送剛才存儲的Service資訊給新程序
- 新程序啟動Service
1: APP給AMS發送消息,附帶Manifest定義的相關資訊。
以startService為例,該方法最終調用的是ContextWrapper中的startService方法。
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
我們知道mBase實際上就是ContextImp, 進入ContextImp,最終調用的是:startServiceCommon方法,可以看到這麼一句話:
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
發送消息給AMS。
2.AMS檢查新的程序是否存在,如果不存在,就建立一個新的程序,并且把Service資訊儲存起來。
AMS會首先檢查Manifest中是否生命了Service,如果沒有直接報錯。有的話,就建立程序,并且把Service的相關資訊封裝成ServiceRecord對象儲存。
3.啟動新程序,然後通知AMS,:新的程序已經存在
Service在啟動的新程序的過程中和上一篇部落格講的APP的啟動流程相似。
此時會建立一個ActivityThread。然後ActivityThread會告訴AMS:新程序啟動成功。
4.此時AMS發送剛才存儲的Service資訊給新程序
AMS收到消息時候,會把之前存儲的ServiceRecord通過ApplicationThread發送給新程序。這個ServiceRecord就是将要啟動的Service的相關資訊。
5:新程序啟動Service
還是以startService為例,AMS發送消息給APT(ApplicationThread),執行:scheduleCreateService, 再給H 執行handleCreateService方法,其中可以看到這個代碼塊:
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
可以看出通過classloader反射出(建立)了一個新的Service,這裡用的是反射。
注意:實際上可以回顧一下,建立Activity的時候,用到的也是反射,可以在Instrumentation中看到,在此不贅述。
至此,新程序的Service就建立啟動完成了。
同一程序綁定Service
在同一程序綁定Service,大緻分為五個步驟:
- APP發送消息給AMS,附帶要啟動的Service資訊。
- AMS接收到資訊之後,會注冊Service在AMS這邊,會通知APP啟動Service
- APP收到消息1, 啟動Service,啟動完成之後,會發送一個消息給AMS:啟動完成
- APP在收到消息2, 綁定Service,把Binder對象傳遞給AMS。
- AMS再把接收到的Binder對象傳回給APP。
最後兩把繞了一圈 Binder又給了APP,考慮的因素可能是:不在同一個程序。是以這樣代碼公用。
調用bindService還是走的ContextWrapper,
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
接着走了ContextImp的bindServiceCommon方法
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
.....
ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
}
最終傳遞給AMS。
AMS收到資訊之後,檢查Manifest,并且會檢視新的程序是否存在。
最終發送消息給APP(假設同一程序),然後回調給APP的APT的scheduleCreateService方法, 在傳遞給H,
private void handleCreateService(CreateServiceData data) {
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
建立完了Service, 最後調用了serviceDoneExecuting方法,是告訴AMS:我建立完畢了,是否有下一步操作。
然後AMS收到消息之後,最終間接會調用APP的handleBindService方法,這是開始了綁定操作。
private void handleBindService(BindServiceData data) {
....
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);
}
......
}
執行了Service的onBind方法,并且告訴調用AMS的publishService方法告訴它:綁定完畢。
其中傳遞了Binder對象,這個Binder對象是ServiceDispatcher内部類的InnerConnection。 InnerConnection實作了IServiceConnection.Stub。
重新回到ContextImp:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
.....
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
......
}
進入到LoadedApk.java中可自行檢視ServiceDispatcher類, 把Binder包裝成了ServiceDispatcher對象發送給了AMS。最終調用:connected方法 --> doConnected方法:
// 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);
}
看到了熟悉的onServiceConnected回調。 如果不在同一個程序,Service 通信的流程是:Service -->AMS -->Activity, 中間是Binder驅動。
附上網上的一張流程圖,個人覺得bindService流程跟這幅圖完全比配:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwJWZ39CX0FWby9mZvw1M2IzLcd3LcJzLcJzdllmVldWYtl2Q3UCcpJHdz9CX05WZpJ3bt8Gd1F2LcJjcn9WTldWYtl2Pn5GcucjN5kjZxM2NwYTOxAzMiJTL0IjNwYDNvw1cldWYtl2XkF2bsBXdvw1bp5SdoNnbhlmauMXZnFWbp1CZh9GbwV3Lc9CX6MHc0RHaiojIsJye.png)
至此綁定流程講述完了。整體的流程和Activity的啟動流程是相似的。