Android深入四大元件(二)Service的啟動過程
相關文章
Android深入理解四大元件系列
前言
此前我用較長的篇幅來介紹Android應用程式的啟動過程(根Activity的啟動過程),這一篇我們接著來分析Service的啟動過程。建議閱讀此篇文章前,請先閱讀Android深入四大元件(一)應用程式啟動過程(前篇)和Android深入四大元件(一)應用程式啟動過程(後篇)這兩篇文章。
1.ContextImpl到ActivityManageService的呼叫過程
要啟動Service,我們會呼叫startService方法,它的實現在ContextWrapper中,程式碼如下所示。
frameworks/base/core/java/android/content/ContextWrapper.java
public class ContextWrapper extends Context {
Context mBase;
...
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
...
}
在startService方法中會呼叫mBase的startService方法,Context型別的mBase物件具體指的是什麼呢?在Android深入四大元件(一)應用程式啟動過程(後篇)這篇文章中我們講過ActivityThread啟動Activity時會呼叫如下程式碼建立Activity的上下文環境。
frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);//1
...
}
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
...
}
return activity;
}
在註釋1處建立上下文物件appContext ,並傳入Activity的attach方法中,將Activity與上下文物件appContext 關聯起來,這個上下文物件appContext 的具體型別是什麼,我們接著檢視createBaseContextForActivity方法,程式碼如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
...
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
...
return baseContext;
}
這裡可以得出結論,上下文物件appContext 的具體型別就是ContextImpl 。Activity的attach方法中將ContextImpl賦值給ContextWrapper的成員變數mBase中,因此,mBase具體指向就是ContextImpl 。
那麼,我們緊接著來檢視ContextImpl的startService方法,程式碼如下所示。
frameworks/base/core/java/android/app/ContextImpl.java
Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
/**
* 1
*/
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
...
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
startService方法中會return startServiceCommon方法,在startServiceCommon方法中會在註釋1處呼叫ActivityManageService(AMS)的代理物件ActivityManagerProxy(AMP)的startService方法,最終會呼叫AMS的startService方法。至於註釋1處的程式碼為何會呼叫AMS的startService方法,在Android深入四大元件(一)應用程式啟動過程(前篇)這篇文章中已經講過,這裡不再贅述。
ContextImpl到ActivityManageService的呼叫過程如下面的時序圖所示。
2.ActivityThread啟動Service
我們接著來檢視AMS的startService方法。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
...
synchronized(this) {
...
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);//1
Binder.restoreCallingIdentity(origId);
return res;
}
}
註釋1處呼叫mServices的startServiceLocked方法,mServices的型別是ActiveServices,ActiveServices的startServiceLocked方法程式碼如下所示。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
...
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
...
return r.name;
}
startServiceLocked方法的末尾return了startServiceInnerLocked方法,而startServiceInnerLocked方法中又呼叫了bringUpServiceLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
...
final String procName = r.processName;//1
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);//2
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {//3
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);//4
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
app = r.isolatedProc;
}
if (app == null && !permissionsReviewRequired) {//5
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {//6
...
}
if (isolated) {
r.isolatedProc = app;
}
}
...
}
在註釋1處得到ServiceRecord的processName的值賦值給procName ,其中ServiceRecord用來描述Service的android:process屬性。註釋2處將procName和Service的uid傳入到AMS的getProcessRecordLocked方法中,來查詢是否存在一個與Service對應的ProcessRecord型別的物件app,ProcessRecord主要用來記錄執行的應用程式程式的資訊。註釋5處判斷Service對應的app為null則說明用來執行Service的應用程式程式不存在,則呼叫註釋5處的AMS的startProcessLocked方法來建立對應的應用程式程式。關於建立應用程式程式請檢視Android應用程式程式啟動過程(前篇) 和Android應用程式程式啟動過程(後篇)這兩篇文章。註釋3處判斷如果用來執行Service的應用程式程式存在,則呼叫註釋4處的realStartServiceLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
try {
...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
...
}
...
}
在realStartServiceLocked方法中呼叫了app.thread的scheduleCreateService方法。其中app.thread是IApplicationThread型別的,它的實現是ActivityThread的內部類ApplicationThread,其中ApplicationThread繼承了ApplicationThreadNative,而ApplicationThreadNative繼承了Binder並實現了IApplicationThread介面。ApplicationThread的scheduleCreateService方法如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
首先將要啟動的資訊封裝成CreateServiceData 物件並傳給sendMessage方法,sendMessage方法向H傳送CREATE_SERVICE訊息,H是ActivityThread的內部類並繼承Handler。這個過程和應用程式的啟動過程(根Activity啟動過程)是類似的。我們接著檢視H的handleMessage方法。
frameworks/base/core/java/android/app/ActivityThread.java
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
...
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
...
}
...
}
handleMessage方法根據訊息型別,呼叫了handleCreateService方法:
frameworks/base/core/java/android/app/ActivityThread.java
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);//1
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();//2
service = (Service) cl.loadClass(data.info.name).newInstance();//3
} catch (Exception e) {
...
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);//4
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());//5
service.onCreate();//6
mServices.put(data.token, service);//7
...
} catch (Exception e) {
...
}
}
註釋1處獲取要啟動Service的應用程式的LoadedApk,LoadedApk是一個APK檔案的描述類。註釋2處通過呼叫LoadedApk的getClassLoader方法來獲取類載入器。接著在註釋3處根據CreateServiceData物件中儲存的Service資訊,將Service載入到記憶體中。註釋4處建立Service的上下文環境ContextImpl物件。註釋5處通過Service的attach方法來初始化Service。註釋6處呼叫Service的onCreate方法,這樣Service就啟動了。在註釋7處將啟動的Service加入到ActivityThread的成員變數mServices中,其中mServices是ArrayMap型別。
最後給出這一節的時序圖。
歡迎關注我的微信公眾號,第一時間獲得部落格更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。
相關文章
- Android深入四大元件(三)Service的繫結過程Android元件
- Android深入四大元件(五)Content Provider的啟動過程Android元件IDE
- Android Service的啟動過程Android
- 深入理解四大元件(四)Service 的繫結過程元件
- Android深入四大元件(六)Android8.0 根Activity啟動過程(前篇)Android元件
- Android深入四大元件(七)Android8.0 根Activity啟動過程(後篇)Android元件
- 【Android原始碼】Service的啟動過程Android原始碼
- Android 四大元件之二-------ServiceAndroid元件
- Android啟動過程深入解析Android
- Service啟動過程分析
- Android學習之四大元件(二)——serviceAndroid元件
- Android啟動過程剖析-深入淺出Android
- Android 四大元件之 ServiceAndroid元件
- Android 四大元件之" Service "Android元件
- 根Activity元件的啟動過程元件
- Android 原始碼分析之旅2 1 IPC以及Service的啟動過程Android原始碼
- Android四大元件之Service篇Android元件
- Android Activity的啟動過程Android
- 深入理解ORACLE啟動過程Oracle
- 深入理解 iOS App 的啟動過程iOSAPP
- Android四大元件之Service,以及IntentServiceAndroid元件Intent
- Android App啟動過程AndroidAPP
- 重溫Android四大元件(二)—Activity的啟動模式與標誌位Android元件模式
- 深入理解linux啟動過程Linux
- Android 系統啟動過程Android
- Android必知必會的四大元件 -- Service篇Android元件
- 淺析Android Activity的啟動過程Android
- Activity的啟動過程第二篇
- 深入理解Linux啟動過程薦Linux
- 四大元件之 Service元件
- 【Android原始碼】Service的繫結過程Android原始碼
- Android系統啟動過程剖析Android
- Android中Activity啟動過程探究Android
- Tomcat啟動過程(二):EndPoint解析Tomcat
- 理解 Android 程式啟動之全過程Android
- 【Android】【init】解析init程式啟動過程Android
- Android應用程式程式啟動過程Android
- Android效能優化之啟動過程(冷啟動和熱啟動)Android優化