前言
要想啓動一個應用程序,首先要保證這個應用程所需要的應用程序進程已經創建啓動。AMS在啓動應用程序時,會檢查這個應用程序需要的應用程序進程是否存在,不存在就會請求Zygote孵化器進程來啓動需要的應用程序進程。因此應用程序進程啓動過程可以概括爲兩個部分:
- AMS發送啓動應用程序進程請求
- Zygote接收請求並創建應用程序進程
關於這部分的具體流程分析可參考《Android進階解密》第二章內容。本文重點分析Zygote創建應用程序進程走到ActivityThread的main方法後,創建Application的流程。
進入ActivityThread的main方法,需要關注的核心代碼如下:
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// 需要關注的代碼
thread.attach(false);
...
Looper.loop();
...
}
接下來進入attach方法,代碼很多,但是需要重點關注的就這幾行:
private void attach(boolean system) {
...
// 註釋1
final IActivityManager mgr = ActivityManager.getService();
try {
// 註釋2
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
如果對Binder機制稍有了解,你就會知道,註釋1處調用ActivityManager的getService方法來獲取AMS的代理對象,接着調用AMS的attachApplication方法。這裏與Android8.0之前的代碼邏輯有些不同,Android8.0之前是通過ActivityManagerNative的getDefault來獲取AMS的代理對象的,現在這個邏輯封裝到了ActivityManager中而不是ActivityManagerNative中。這裏先查看ActivityManager的getService方法:
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
// 註釋1
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
// 註釋2
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
在註釋1處獲取IBinder類型的AMS引用(binder對象),接着在註釋2處將它轉換成IActivityManager類型的對象(也就是AMS的代理對象),這段代碼採用的AIDL,IActivityManager.java文件是由AIDL工具在編譯時自動生成的,IActivityManager.aidl的文件路徑爲frameworks/base/core/java\android/app/IActivityMananger.aidl。要實現跨進程通信,服務端也就是AMS只需要繼承IActivityManager.Stub類並實現相應的方法就可以了。Android8.0之前並沒有採用AIDL,用AMS的代理對象ActivityManagerProxy來與AMS進行通信,Android8.0去除了ActivityManagerNative的內部類ActivityManagerProxy,代替它的是IActivityManager,它是AMS在本地的代理。言歸正傳,回到attach方法,接下來進入AMS的attachApplication方法(跨進程通信,AMS在SystemServer進程)
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
// 註釋1
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
接下來進入註釋1處的attachApplicationLocked方法:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
// 用於描述一個應用程序進程(記錄應用程序進程的相關信息)
ProcessRecord app;
...
if (app.instr != null) {
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
...
return true;
}
AMS負責四大組件的啓動、切換、調度以及應用程序進程的管理,是Android中最爲核心的服務,參與了應用程序的啓動管理。這裏省去了大量的檢查和初始化的代碼,保存要創建應用程序進程的相關信息等操作,也就是說通過ProcessRecord即應用程序進程信息的相關判斷,thread是IApplicationThread類型的,此處代表的是IApplicationThread的代理對象,調用bindApplication方法,ApplicationThread繼承IApplicationThread.Stub,此處又是Binder機制的跨進程通信,接下來進入ApplicationThread的bindApplication方法,ApplicationThread是ActivityThread的內部類,又從AMS所在的SystemServer系統服務進程回到了應用程序進程。
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
......
// 註釋1
sendMessage(H.BIND_APPLICATION, data);
}
將應用程序進程的相關信息保存到AppBindData類型的data中,通過sendMessage方法發送消息,交給H類型的Handler處理
private class H extends Handler {
...
public static final int BIND_APPLICATION = 110;
...
public void handleMessage(Message msg) {
switch (msg.what) {
...
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
//調用ActivityThread的handleBindApplication()方法處理
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
}
}
進入H類的handleMessage方法,找到BIND_APPLICATION對應的case,從msg中取出之前保存的AppBindData類型的數據data,交給handleBindApplication方法
private void handleBindApplication(AppBindData data) {
// 註釋1 獲取LoadedApk
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
...
try {
// 註釋2
// 創建一個Application對象
Application app = data.info.makeApplication(data.restrictedBackupMode,null);
mInitialApplication = app;
try {
// 註釋3
// 通過mInstrumentation對象,回調Application的onCreate()方法
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
} finally {
...
}
...
}
先看註釋1處,通過getPackageInfoNoCheck()方法對AppBindData對象的info變量賦值,info變量的類型是LoadedApk,關於LoadedApk,有一個通俗的說法,LoadedApk對象是apk文件在內存中的表示,apk文件的相關信息,比如apk文件中的資源,甚至是代碼裏面的Activity、Service等組件的信息都可以通過此對象獲取,我們來看下getPackageInfoNoCheck()方法的源碼
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
CompatibilityInfo compatInfo) {
return getPackageInfo(ai, compatInfo, null, false, true, false);
}
接着進入getPackageInfo方法:
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
boolean registerPackage) {
/*
* 下面這個地方不是很理解,看下面這一行代碼的意思應該是判斷是不是同一個用戶
* 查了一下,differentUser的值大部分情況下應該都是false
*/
final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
synchronized (mResourcesManager) {
WeakReference<LoadedApk> ref;
if (differentUser) {
// Caching not supported across users
ref = null;
} else if (includeCode) {
/*在getPackageInfoNoCheck()方法中調用本方法時,includeCode的值爲true
*從緩存中根據應用的報名獲取LoadedApk的弱引用對象
*/
ref = mPackages.get(aInfo.packageName);
} else {
ref = mResourcePackages.get(aInfo.packageName);
}
LoadedApk packageInfo = ref != null ? ref.get() : null;
/*
* 當獲取的LoadedApk對象爲null時,或者說是放緩存中不存在對應的LoadedApk對象時候
* 則調用LoadedApk的構造方法,創建一個LoadedApk對象
*/
if (packageInfo == null || (packageInfo.mResources != null
&& !packageInfo.mResources.getAssets().isUpToDate())) {
...
packageInfo =
new LoadedApk(this, aInfo, compatInfo, baseLoader,
securityViolation, includeCode &&
(aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
...
if (differentUser) {
// Caching not supported across users
} else if (includeCode) {
//把創建的LoadedApk對象放入緩存中
mPackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
} else {
mResourcePackages.put(aInfo.packageName,
new WeakReference<LoadedApk>(packageInfo));
}
}
return packageInfo;
}
}
總結一下getPackageInfo()方法的作用就是,從緩存中獲取對應的LoadedApk對象,若緩存中不存在該對象,便去創建一個對象,保存在緩存裏,並return LoadedApk的對象,最終把該對象賦值給handleBindApplication()中的data.info。
我們繼續回到handleBindApplication()方法中的註釋2處,調用data.info也就是LoadedApk對象的makeApplication()方法,創建一個Application對象,我們來看下makeApplication()方法
frameworks/base/core/java/android/app/LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//若Application已經創建過,直接return
if (mApplication != null) {
return mApplication;
}
...
Application app = null;
...
try {
...
// 註釋1
// 獲取一個ContextImpl上下文對象
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
// 註釋2
// 通過Instrumentation對象的newApplication()方法創建一個Application對象,
// 創建的這個Application對象也是makeApplication()方法最終return的對象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
...
return app;
}
註釋1處,內部主要還是通過new ContextImpl(xxx)的形式創建ContextImpl對象。再看註釋2處,進入Instrumentation的newApplication方法,顧名思義它的作用就是創建Application
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
該反方最終通過反射的方式創建了一個Application對象,並且調用了Appliction的attach()方法,而attach方法又調用了attachBaseContext方法,現在應該明白爲什麼該方法在Application的onCreate之前調用了。
final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
接下來回到handleBindApplication方法的註釋3處,通過mInstrumentation對象,調用callApplicationOnCreate方法,顧名思義就是去調用執行Application的onCreate()方法
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
文章的後半部分主要是從handleBindApplication方法的3處重要邏輯展開的,爲了看得更清晰一點,簡單小結一下:
- data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); 獲取保存Apk文件信息的LoadedApk對象
- Application app = data.info.makeApplication(data.restrictedBackupMode,null); 內部通過反射創建Application對象,在這個過程中會調用Application的attachBaseContext方法
- mInstrumentation.callApplicationOnCreate(app); 通過Instrumentation的callApplicationOnCreate方法執行Application的生命週期方法onCreate