總結了幾篇系統底層相關的文章,終于要接觸到應用層了,不過需要提前掌握 Binder架構,系統啟動流程,進程啟動流程 的相關姿勢,不然很難理清整個流程。相對于 startAcitivity(),startService() 的流程相對簡單,因為不涉及界面相關的操作,便于理清用戶進程,AMS 所在進程(也即 SystemServer 進程)和 服務所在進程三者之間的關系。
1. 整體流程
這里借用 gityuan 的一篇文章 里的圖:
這個圖畫的非常好,關鍵點基本上都標注出來了,涉及到三個進程的交互(當然Remote Service 進程也可以和 Process A 進程是同一個,那樣就省略2、3創建進程的步驟)。重點注意整個流程中涉及到通過 Binder 進行跨進程交互的部分,如果不熟悉 Binder 架構,很難理解。下面以從一個 Activity 里面調用 startActivity() 啟動服務為例,進行詳細分析。
2. ContextImpl.startService()
Activity -> ContextThemeWrapper -> ContextWrapper,ContextWrapper 是個代理類,實際功能都由其成員變量 Context mBase 實現,mBase 實際上是一個 ContextImpl 對象(具體怎么來的,以后的文章會講到,簡單的說是啟動Activity 時注入的)。在 Application 或者 Service 里面啟動 startService 也是一樣,最終都調用到 ContextImpl.startService():
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
...
// Binder 調用 AMS
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
...
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
這里有兩個關鍵點:
- ActivityManagerNative.getDefault() 獲取了 ActivityManagerService (AMS)的遠程代理對象 ActivityManagerProxy,并發起了 startService 的請求
- mMainThread.getApplicationThread(),這里 mMainThread 是一個 ActivityThread 對象,getApplicationThread() 返回 ActivityThread 的成員變量 ApplicationThread mAppThread,ApplicationThread 是 ActivityThread 的一個內部類,看定義:
private class ApplicationThread extends ApplicationThreadNative {
...
}
明顯也是一個 Binder 架構,把這個 Binder 對象傳遞給 AMS,是為了 AMS 與發起 startService 的調用進程通信,后面會具體分析。
到這里,發起 startService 請求的部分就完成了,接下來會通過 Binder 跨進程調用,進入到 AMS 中繼續分析。
3. AMS.startService()
通過 Binder
機制,ActivityManagerProxy.startService ----跨進程---> ActivityManagerNative.onTransact() --> AMS.startService(),AMS 是 AMN 的子類,實現了其 startService 方法。
AMS 中的 startService 方法:
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
...
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
...
return res;
}
}
這里 IApplicationThread caller 就是發起進程在 AMS 所在的進程中的代理。mService 是 一個 ActiveServices 類型的成員變量,其持有 AMS 的引用。
4. ActiveServices
4.1 startServiceLocked()
這個方法源碼比較長,這里只保留關鍵部分:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); // 1. 查找調用進程是否存在
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
...
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false); // 2. 查找要啟動的服務是否已經存在
...
ServiceRecord r = res.record;
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting)
兩個關鍵點已經用注釋中標記出來,retrieveServiceLocked() 內部流程也比較復雜,有各種條件、權限的檢查等,這里不深入分析了,簡單說就是有一個 Map 用來保存用戶所有已啟動的服務,如果不存在符合條件的 ServiceRecord,就新建一個并保存在 Map 中。最后流程進入到 startServiceInnerLocked() --> bringUpServiceLocked()
4.2 bringUpServiceLocked()
仍然先貼出簡化后的代碼:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
//1. Service 所在的進程和 Service 線程都已經啟動的情況
sendServiceArgsLocked(r, execInFg, false);
return null;
}
...
if (!isolated) {
// 2.查找服務對應的進程是否存在
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
...
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
// 3. 如果進程已經存在,直接啟動服務
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
}
...
if (app == null && !permissionsReviewRequired) {
// 4. 如果進程不存在,啟動進程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
...
}
...
}
幾個關鍵點已經注釋標明:
- 如果服務所在進程和線程都已經啟動(r.app != null && r.app.thread != null),那么調用 sendServiceArgsLocked(),這個方法里的關鍵代碼只有一句:
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
r.app.thread 就是發起 startService 的進程在 AMS 中的遠程代理對象,這里又通過了 Binder 跨進程調用,最終調用到 ApplicationThreadNative.onTransact() --> ApplicationThread.scheduleServiceArgs():
public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
sendMessage(H.SERVICE_ARGS, s);
}
調用該方法后,ApplicationThread 會把消息 post 到主線程的 handler 處理,對應 SERVICE_ARGS 的處理函數是 handleServiceArgs(),在這個方法里,終于看到了我們熟悉的 Service.onStartCommand() !這也是為什么當反復啟動 Service 的時候,只有 onStartCommand() 會被反復調用。
- 如果服務所在進程已經存在,那么進入 realStartServiceLocked() 啟動服務,這里也不貼出大段源碼了,關鍵代碼有兩處:
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
...
sendServiceArgsLocked(r, execInFg, true);
和第一種情況類似,這里也是兩個 Binder 跨進程調用,最終分別調用到 Service 的 onCreate() 和 onStartCommand 生命周期,這又是我們非常熟悉的部分了。
- 如果服務所在進程不存在,那么調用 AMS.startProcessLocked 啟動進程。在上一篇 Android 進程啟動流程總結 中已經分析了從 AMS.startProcessLocked 開始的流程,這里終于找到了它的調用的源頭之一,就是當啟動的服務所在進程還不存在時,就要調用 AMS.startProcessLocked 先啟動對應的進程。在上篇文章的最后提到,進程啟動后會調用 ActivityThread.main() 方法 -->ActivityThread.attach() --> ActivityManagerProxy.attachApplication() --Binder跨進程調用--> AMS.attachApplication() --> AMS.attachApplicationLocked() --> ActiveServices.attachApplicationLocked() --> ActiveServices.realStartServiceLocked(),終于殊途同歸!回到了和第2種情況一樣的函數。
至此,startService() 的整個流程就走完了。
5. 總結
startService() 的流程看起來有些復雜,但是只要先建立了如第一節所示的三個進程間交互的整體結構圖,那么整體思路還是很清晰的,這中間涉及了 Binder 和 Socket 兩種跨進程調用(上一篇介紹的進程啟動流程里講到),是把前面學習的 Android 底層架構知識融會貫通的一個非常好的學習范例,也為后面分析更為復雜的 startActivity() 流程打好了基礎。