為了寫這篇文章,我可是找了好些資料,看了好幾天才把其中關節順下來好清楚,資料很多,有說 app 冷啟動的,有說從 Activity 啟動 Activity 的,還有說 window 加載頁面的,這些其實都時勾著的,一環套一環,區別是有的時候有些環節不會跑。這里我從頭帶大家走一下,整個順一遍下來就都清楚了
app 冷啟動是說從桌面啟動 app ,此時我們的應用是沒有進程的,需要創建。Activity 啟動 Activity,指的是進程內啟動新的頁面,此時應用進程是存在的。系統桌面也是一個 Activity ,名叫 Launch ,所以 app 冷啟動和 Activity 啟動 Activity 差不多,走的都是 Activity 內部的方法,區別就是先啟動應用進程的事,這樣說大家就對這兩種啟動 Activity 的情況心里有數了
這塊必須清楚,因為面試時很多時候會問的,有的面試官會問你2者的關聯,區別,簡單的自會問你 Activity 啟動流程,你把2種 Activity 啟動方式的關聯一說,絕對漲分。除了面試環節外,我們也能熟悉下系統流程,后面插件化會用到,另外也會對我們自己封裝框架,學習系統其他深入知識點有很大的幫助,比如 AIDL 雙向通訊,功能分割,代理分層,有助于我們以后看各種框架
app 的啟動流程簡單來說:
- 用戶點擊 icon
- 系統開始加載和啟動應用
- 應用啟動:開啟空白(黑色)窗口
- 創建應用進程
- 初始化Application
- 啟動 UI 線程
- 創建第一個 Activity
- 解析(Inflater)和加載內容視圖
- 布局(Layout)
- 繪制(Draw)
涉及系統類如下:
- Application
- Activity
- Instrumentation
- H
- ActivityThread
- IApplicationThread
- Instrumentation
- ActivityManagerService
- IActivityManager
- window
- ViewRootImpl
- 一對 AIDL 雙向通訊
IApplicationThread 和 IActivityManager 是一對配套的 AIDL 接口
- IActivityManager 負責 Activity -> ActivityManagerService 的通訊
- IApplicationThread 負責 ActivityManagerService -> Activity 的通訊
- 雙向通訊的綁定是在 Activity 拿到同 ActivityManagerService 通訊的 AIDL 時把自己的 IApplicationThread 也就是反向 AIDL 接口交給 ActivityManagerService ,這樣2者形成 AIDL 雙向通訊
- 功能分層,代碼類聚
若是按照 MVP 的思路來說:
- V 層是 widow ,負責 Activity 界面的渲染
- P 層是 Instrumentation,封裝了 Activity 所有的操作邏輯,所有的操作邏輯入口都是在 Instrumentation 里面
- M 層是 ActivityThread ,ActivityThread 持有 Activity 和遠程操作的 AIDL 交互接口
這么看的話,Activity 要清晰很多了,限于我小白的水平,估計有一些寫的不全,分析的疏漏的地方大家見諒呀~
正式開始
找到還可以的流程圖,方便后面比對
1. startActivity 我們去啟動一個新頁面
平時我們自己啟動 Activity 都是用的 startActivity 這個方法,那么對于 app 冷啟動,LaunchActivity 是怎么跑的?
看代碼,LaunchActivity 也沒多干什么事,LaunchActivity 會解析我們點擊圖標對應的 app 的配置文件,獲取期中信息構建 intent ,然后再調用 startActivity
// 桌面點擊app圖標
public void onClick(View v) {
...
Object tag = v . getTag ();
if (tag instanceof ShortcutInfo) {
onClickAppShortcut(v);
}
}
protected void onClickAppShortcut(final View v) {
...
// Start activities
startAppShortcutOrInfoActivity(v);
}
private void startAppShortcutOrInfoActivity(View v) {
ItemInfo item =(ItemInfo) v . getTag ();
Intent intent;
// 通過 PackageManagerService 解析 AndroidManifest.xml
if (item instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo =(PromiseAppInfo) item;
intent = promiseAppInfo.getMarketIntent();
} else {
intent = item.getIntent();
}
...
boolean success = startActivitySafely (v, intent, item);
...
}
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
...
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
...
startActivity(intent, optsBundle);
...
}
這樣 app 冷啟動和 Activity 啟動 Activity 就聯系起來了,app 冷啟動相比多了一步獲取目標 app 信息構建 intent 過程,然后都會走 Activity.startActivity() 這
2. Activity.startActivity()
現在我們進入 Activity 源碼里面了,源碼的話我們不用看的細節,了解過程就成
Activity.startActivity() 調的是 startActivityForResult(), startActivityForResult() 方法會使用 mInstrumentation.execStartActivity()
//
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
...
}
3. mInstrumentation.execStartActivity
mInstrumentation 看過上面大家都知道了把,是 Activity 的 P 層,封裝了所有 Activity 的核心業務操作
mInstrumentation.execStartActivity 里面會調 ActivityManager.startActivity ,ActivityManager 知道了吧,是 Activity 與 ActivityManagerService 的遠程 AIDL 通訊類,并把反向 AIDL 通訊對象 ApplicationThread 傳給遠程 ActivityManagerService , 方便 ActivityManagerService 回調,這樣看 Activity 把創建 Activity 的任務交給了 遠程 ActivityManagerService
//
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
...
// 這個 whoThread 就是 ApplicationThread 反向 AIDL 通訊對象
int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
...
} catch (RemoteException e) {
...
}
return null;
}
4. ActivityManagerService.startActivity
這是代碼 脫離 Ui 所在進程來到了系統 ActivityManagerService 進程,ActivityManagerService 會怎么干呢,我們拭目以待
來看代碼
//
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
ActivityManagerService 的 startActivity 里面多次調用了其他方法:
- startActivity()
- -> ActivityStarter.startActivityMayWait()
- -> ActivityStarter.startActivityLocked()
- -> ActivityStarter.startActivity()
- -> ActivityStarter.startActivityUnchecked()
- -> ActivityStackSupervisor.resumeFocusedStackTopActivityLocked()
- -> ActivityStack.resumeTopActivityUncheckedLocked()
- -> ActivityStack.resumeTopActivityInnerLocked()
- -> ActivityStackSupervisor.startSpecificActivityLocked()
上面的這一柳方法一個調一個,一直到在 tartSpecificActivityLocked 這個方法里才能看到核心內容,這個方法中會判斷目標進程是否存在,存在則通知進程啟動 Activity,否則就先將進程創建出來
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
...
if (app != null && app.thread != null) {
...
// 如果進程已存在,則通知進程啟動組件
realStartActivityLocked(r, app, andResume, checkConfig);
return;
...
}
// 否則先將進程創建出來
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
...
}
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
...
}
5. ActivityManagerService.realStartActivityLocked 創建新 Activity
我們先來看 realStartActivityLocked 這個方法,這個方法會通過 ApplicationThread 回調 UI 進程創建一個 Activity 出來,app.thread 就是我們之前傳遞過去的 ApplicationThread AIDL 反向回調
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
//...code
app.thread.scheduleLaunchActivity(new Intent (r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global and
// override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
//...code
}
大家記住 realStartActivityLocked 這個方法,因為一會我們還會提到他,記住是這個方法讓我們開始創建 Activity 對象
6. Process.start 創建目標進程
在 4 中,我們看到 ActivityManagerService 會判斷目標進程存不存在,不存在就 fork 一個新的進程出來,Process.start 就是創建進程的代碼
系統在 fork 一個新的進程后,會在新的進程里面啟動 Ui 線程,也就是 ActivtyThread 對象,而 ActivtyThread.main() 方法才是一個 app 進程真正的開始‘
public static void main(String[] args){
...
Looper.prepareMainLooper();
//初始化Looper
...
ActivityThread thread = new ActivityThread();
//實例化一個ActivityThread
thread.attach(false);
//這個方法最后就是為了發送出創建Application的消息
...
Looper.loop();
//主線程進入無限循環狀態,等待接收消息
}
mian 方法中,先把 UI 線程的 looper 消息隊列準備好,然后 new 一個 UI 線程對象,然后初始化 UI 線程的參數,最后把 UI 線程的 looper 消息隊列跑起來,UI 線程進入等待任務階段
這里面我們需要詳細看看 thread.attach(false) UI 線程初始化參數方法干了什么
public void attach(boolean system){
...
final IActivityManager mgr = ActivityManagerNative.getDefault();
//獲得IActivityManager實例,下面會看看它是個啥
try {
mgr.attachApplication(mAppThread);
//看見沒?關鍵啊。mAppThread這個參數下面也會說一下
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
恩,可以看到我們把 AIDL 反向回調通訊注冊到了 ActivityManagerService 里面,然后那必然操作又切回到了系統的 ActivityManagerService 進程里,接著 ActivityManagerService 里面的代碼走到了 attachApplicationLocked 這個位置
attachApplicationLocked 方法很重要,期中執行了2個操作,先創建 application 對象,再創建 Activity 對象,這2個方法可是串行執行的,都是 AIDL 遠程操作
//
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
....
// 創建 application 對象
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);
...
// 然后再創建 Activity 對象
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
...
}
}
...
}
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
final String processName = app.processName;
...
if (realStartActivityLocked(activity, app,
top == activity /* andResume */, true /* checkConfig */)) {
...
}
...
}
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
...
7. UI 線程接受消息,new application 對象
可以看見 attachApplicationLocked 又通過 ApplicationThread 回調,讓 UI 進程干活了,注意這個 ApplicationThread 所在的進程就不是我們發起 startActivity 的 LaunchActivity 所在的進程了,而是我們剛剛 fork 出來的目標進程了
接著我們來看看 UI 進程的 bindApplication 方法
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) {
...
sendMessage(H.BIND_APPLICATION, data);
}
private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) Slog.v(
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
+ ": " + arg1 + " / " + obj);
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
ApplicationThread 發送了一個 H.BIND_APPLICATION 的消息,該消息會由 ActivityThread 一個名叫 H 的 handle內部類接收
//
public void handleMessage(Message msg) {
...
switch (msg.what) {
...
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
}
private void handleBindApplication(AppBindData data) {
...
final InstrumentationInfo ii;
...
// 創建 mInstrumentation 實例
if (ii != null) {
final ApplicationInfo instrApp = new ApplicationInfo();
ii.copyTo(instrApp);
instrApp.initForUser(UserHandle.myUserId());
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true, false);
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
...
}
...
} else {
mInstrumentation = new Instrumentation();
}
...
Application app;
...
// 創建 Application 實例
try {
...
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
...
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
} finally {
...
}
...
}
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
...
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {// 傳入為 null 所以不走
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
}
...
return app;
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
該 handle 會創建一個 mInstrumentation 實例,然后創建出上下文對象,application 對象,application 綁定上下文,mInstrumentation 對象會執行 application.onCreate() 初始化
8. UI 線程接受消息,new activity 對象
在6里面,ActivityManagerService.attachApplicationLocked() 里面連著干了2件事,先創建 application ,完事再創建 activity 對象,在7里面我們創建完了 application 對象,下面就該創建 activity 對象了
到這 app 冷啟動有和 activity 啟動 activity 走到一起了,之后2者也沒分別了,差別就是 app 冷啟動多了創建 application 對象的過程,完事都一樣了,就是 創建 activity 對象了
//
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
ApplicationThread.scheduleLaunchActivity() 方法里發送一個 H.LAUNCH_ACTIVITY 創建 activity 對象的消息
然后 ActivityThread 的 handle 接受消息,由 Instrumentation new activity 對象,activity 對象初始化參數,最后由 Instrumentation 執行 activity.onCreate() 初始化方法
//
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
public void handleMessage(Message msg) {
...
switch (msg.what) {
...
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
Activity a = performLaunchActivity(r, customIntent);
...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
try {
// 返回之前創建過的 application 對象
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
...
// attach 到 window 上
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, r.configCallback);
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
} catch (Exception e) {
...
}
return activity;
}
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
public Activity newActivity(Class<?> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance) throws InstantiationException,
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
activity.attach(context, aThread, this, token, 0 /* ident */, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null /* referrer */, null /* voiceInteractor */,
null /* window */, null /* activityConfigCallback */);
return activity;
}
到這 activity 的創建流程算是完事了,之后走 activity 的生命周期函數,再由 window 渲染界面顯示,但是這里我們還要看看 activity.attach方法,看看 activity 初始化了什么參數,方面之后我們繼續說 window
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow (this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
mMainThread = aThread;
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
if (voiceInteractor != null) {
if (lastNonConfigurationInstances != null) {
mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
} else {
mVoiceInteractor = new VoiceInteractor (voiceInteractor, this, this,
Looper.myLooper());
}
}
mWindow.setWindowManager(
(WindowManager) context . getSystemService (Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo . FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
創建了 PhoneWindow 窗口,給窗口對象注冊監聽,通過窗口Window創建,初始參數賦值,把和 WindowManagerService 遠程通訊的 WindowManagerImpl AIDL 對象綁定給 PhoneWindow