1.前言
小時候聽大人們講四大組件的故事,以為Activity就是手機屏幕上被看到的那東西。長大以后才發現,原來這個說法只是大人們照顧到孩子的理解能力所編造的謊言。那么今天,我們就從源碼入手,親眼去看一看Activity是如何啟動的吧。
2.源碼分析
Activity有2種啟動的方式,前者是在Launcher界面點擊應用的圖標、后者是在應用中通過Intent進行跳轉。我們主要介紹與后者相關的啟動流程。
2.1 Instrumentation
故事要從Activity的startActivity()
開始,這個方法會在內部調用startActivityForResult()
,其中的核心代碼長這樣
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
也就是說,Activity是由mInstrumentation來啟動的。查看Instrumentation類的
execStartActivity()
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
在這里我們見到了老朋友ActivityManagerNative,它是用來與ActivityManagerService進行進程間通信的IBinder對象。
2.2 ActivityManagerService
回顧一下,在客戶端進程中,我們會調用ActivityManagerProxy(Proxy)的startActivity(),經過AIDL回調服務端進程中ActivityManagerNative(Stub)的onTransact:
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
...
switch (code) {
case START_ACTIVITY_TRANSACTION:
{
...
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
...
}
如上所示,在服務端進程,也就是系統進程中,會真正調用ActivityManagerService的startActivity()方法。這里多嘴一句,ActivityManagerService在四大組件的創建以及生命周期管理中起了至關重要的作用。
startActivity()
會轉到startActivityAsUser()
,這個方法會返回mStackSupervisor.startActivityMayWait()
方法的結果。
2.3 ActivityStackSupervisor
現在皮球踢給了ActivityStackSupervisor。從名字上可以看出,這是一個Activity棧的管理類,其中有許多不同類型的list用來存放ActivityRecord。
在Android系統中,每個應用都有許多自己的棧以及相對應的Activity們,應用自己是不會管理這些仔們的生命周期的,它也管不來。每個應用所作的,就是將Activity的狀態信息封裝到ActivityRecord并交給系統級的服務——ActivityStackSupervisor來統一管理。因此ActivityStackSupervisor可以很輕松的獲取到各種Activity。
/** List of processes waiting to find out about the next visible activity. */
final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible = new ArrayList<>();
/** List of processes waiting to find out about the next launched activity. */
final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched = new ArrayList<>();
/** List of activities that are ready to be stopped, but waiting for the next activity to
* settle down before doing so. */
final ArrayList<ActivityRecord> mStoppingActivities = new ArrayList<>();
...
startActivityMayWait()
比較長,前面大段代碼都是用來獲取Activity的相關信息,比如FLAG、PID、UID等,關鍵代碼1如下:
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveIntent(
intent, null,
PackageManager.MATCH_DEFAULT_ONLY
| ActivityManagerService.STOCK_PM_FLAGS, userId);
aInfo = rInfo != null ? rInfo.activityInfo : null;
aInfo = mService.getActivityInfoForUser(aInfo, userId);
2.3.1 PackageManagerService
這里負責去清單文件里查找要啟動的Activity是否存在。我相信大部分同學都有這樣的經歷:直接copy一個Activity到自己的項目中,運行一跑,GG,其報錯信息就是resolveIntent。
AppGlobals.getPackageManager()
也是一個AIDL的過程,其返回的IBinder對象是IPackageManager,按照國際慣例,我們找到其本尊PackageManagerService的resolveIntent()方法:
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
return chooseBestActivity(intent, resolvedType, flags, query, userId);
}
這里有一個List<ResolveInfo>
用來存符合要求的Activity,為什么會返回list呢?因為隱式啟動時,有可能會匹配一個以上的activity,所以在最后return方法中,chooseBestActivity
就用來根據不同情況選擇合適的Activity,比如優先級不同時自動返回最佳的、有默認值時直接返回默認的、優先級相同時讓用戶選擇等等。
這里還要再介紹一下PackageManagerService,這是用來管理android中“包”的系統服務,它會掃描各個APK的AndroidManifest.xml中四大組件的注冊信息并保存在自己那里,證據就在它自己的構造函數里:
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
...
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
...
而這個服務是在SystemServer中啟動的,啟動后會調用其main方法,并把自己交給系統服務的管理類(大多數系統服務都是這樣玩的)
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
ServiceManager.addService("package", m);
2.3.2 ActivityRecord
接下來回到ActivityStackSupervisor.startActivityMayWait()中,關鍵代碼2如下:
int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
componentSpecified, null, container, inTask);
這里調用了startActivityLocked,這個方法主要用來驗證intent、Class、Permission等,其中有許多if語句對err進行了判斷。
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that!
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
判斷完成之后,如果沒有任何異常,就會創建一個ActivityRecord對象。從下面的構造方法中可以看出,ActivityRecord封裝了與Activity有關的一系列參數,比如我是誰,我從哪里來,我要到哪里去。
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, this, container, options);
到此startActivityLocked()
就基本完成了歷史使命,在它代碼的最后,新時代的接力棒又交到了startActivityUncheckedLocked()
手上
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, true, options, inTask);
2.4 ActivityStack
新時代一開始,就結合Flag與啟動模式開始大清洗,得出當前Activity真正的啟動模式
final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
int launchFlags = intent.getFlags();
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
(launchSingleInstance || launchSingleTask)) {
// We have a conflict between the Intent and the Activity manifest, manifest wins.
Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
"\"singleInstance\" or \"singleTask\"");
launchFlags &=
~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
}
獲得啟動模式后,自然要開始準備與Task有關的內容。比如判斷是否要獨立分配一個棧,如果需要則創建、如果不需要則再判斷,是否要將當前Actitivy移動到當前Task的最前面。
這個方法里還有許多許多if判斷語句,可見Activity作為四大組件之首果然名不虛傳,其啟動流程是極其復雜與嚴謹的。
final ActivityStack focusStack = getFocusedStack();
ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
boolean movedToFront = false;
if (curTop != null && (curTop.task != intentActivity.task ||curTop.task != focusStack.topTask())) {
...
movedHome = true;
...
}
我們不停的向下滑動鼠標,快速瞻仰一下Google工程師的偉大,慢慢就到了代碼的最底部。
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
文章之前說過,ActivityStackSupervisor是用來管理ActivityStack的,在前面一萬個判斷中,我們已經獲得了當前的ActivityStack以及封裝Activity信息的ActivityRecord。所以接下來,就應該進入到ActivityStack中去執行具體的棧操作。
現在對ActivityStack本身操作。在系統中,對ActivityStack的管理也是基于棧這種結構的,暫且稱之為stack棧。既然啟動了新的Activity,那么該Activity所屬的ActivityStack自然也要移動到stack棧的頂端。
下面有兩種情況,一是Activity啟動了新的ActivityStack:
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
insertTaskAtTop(rTask, r);
mWindowManager.moveTaskToTop(taskId);
}
此時將新的ActivityStack移動到stack棧的最頂端,同時也要將對應的Window置頂。
第二種情況是Activity還在原來的棧中運行,此時就將Activity移動到ActivityStack的頂端
if (!newTask) {
...
task.addActivityToTop(r);
...
}
2.5 pause與resume的江湖傳說
在方法最后,代碼又從ActivityStack回到了mStackSupervisor中:
if (doResume) {
mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}
在resumeTopActivitiesLocked
中,首先判斷了當前棧是否是Top棧,如果沒有問題,就回到ActivityStack中
if (isFrontStack(targetStack)) {
result = targetStack.resumeTopActivityLocked(target, targetOptions);
}
resumeTopActivityLocked()
又調用了resumeTopActivityInnerLocked()
,這個方法里重點就來了:
// We need to start pausing the current activity so the top one
// can be resumed...
boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
}
看到這句注釋了嗎,江湖上一直流傳的前一個Activity先pause,后一個Activity再resume的說法,原來是從這里來的!
2.5.1 onPause的故事
接著深入進去瞧瞧startPausingLocked()
到底做了些什么。
ActivityRecord prev = mResumedActivity;
...
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
// Ignore exception, if process died other code will cleanup.
Slog.w(TAG, "Exception thrown during pause", e);
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
}
}
首先,這里有一個叫pre的ActivityRecord,顧名思義,這是當前Activity的上一個Activity。如果pre的應用不為空,則通過prev.app.thread.schedulePauseActivity()
來執行具體的pause操作。
在這里,我們必須先來理清楚一個概念,ActivityStackSupervisor只是用來管理Activity與任務棧的,它并不具備執行具體操作的能力。
因此在這里是通過IPC告訴要暫停的Activity進入暫停。其具體的操作是在ActivityThread中執行的:
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
configChanges);
}
這里向Handler H發送了H.PAUSE_ACTIVITY的Message,H是這樣處理回調的:
case PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
(msg.arg1&2) != 0);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
handlePauseActivity()
也是比較關鍵的方法
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
...
//注釋1
performPauseActivity(token, finished, r.isPreHoneycomb());
...
//注釋2
// Tell the activity manager we have paused.
if (!dontReport) {
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
}
}
mSomeActivitiesChanged = true;
}
}
先看注釋1處,這里調用了performPauseActivity()
,performPauseActivity()
又調用了mInstrumentation.callActivityOnPause(r.activity);
,這個方法長這樣:
public void callActivityOnPause(Activity activity) {
activity.performPause();
}
去Activity里看看performPause()
:
final void performPause() {
mDoReportFullyDrawn = false;
mFragments.dispatchPause();
mCalled = false;
onPause();
mResumed = false;
if (!mCalled && getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onPause()");
}
mResumed = false;
}
當當當當~繞了這么一大圈以后, onPause()
方法終于得到了回調!
2.5.2 onPause之后的故事
現在回到handlePauseActivity()
來看注釋2,前面的代碼已經執行了Activity的onPause()
,所以現在要做的是將操作回饋給ActivityManagerService,來看看它的activityPaused()
方法
@Override
public final void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
stack.activityPausedLocked(token, false);
}
}
Binder.restoreCallingIdentity(origId);
}
因為目標Activity已經暫停了,所以現在ActivityManagerService需要知道該讓哪一個Activity上位,此時只能去找被暫停的Activity所屬的ActivityStack尋找答案。
activityPausedLocked()
中調用了completePauseLocked(true)
來告訴ActivityStack上一個Activity已經pause完成了:
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!mService.isSleepingOrShuttingDown()) {
mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
ActivityRecord top = topStack.topRunningActivityLocked(null);
if (top == null || (prev != null && top != prev)) {
// If there are no more activities available to run,
// do resume anyway to start something. Also if the top
// activity on the stack is not the just paused activity,
// we need to go ahead and resume it to ensure we complete
// an in-flight app switch.
mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
}
}
}
所以接下來通過mStackSupervisor.getFocusedStack()
獲取頂層的ActivityStack,再執行mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null)
來resume某個Activity。
至于為什么要通過mStackSupervisor來獲取頂層棧而不是直接使用當前的ActivityStack,那是因為有可能被pause的Activity是當前ActivityStack中最后的Activity。
現在執行mStackSupervisor.resumeTopActivitiesLocked()
,該方法調用了targetStack.resumeTopActivityLocked(target, targetOptions)
,于是我們再次從ActivityStackSupervisor回到ActivityStack,并且最終調用了resumeTopActivityInnerLocked()
方法。
等等,這個過程是不是有點熟悉?往前找找,哦,原來之前通過startPausingLocked()
開始pause一個Activity時也是走的這個流程,只不過現在改成resume另一個Activity了。
2.5.3 新進程的創建
我們來重新感受一下resumeTopActivityInnerLocked()
,這里有一個很長if-else語句用來驗證是否該需要啟動的Activity所在進程和app已經存在,若存在,直接啟動,否則準備創建該進程。
if (next.app != null && next.app.thread != null) {
...
} else {
...
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
我們重點關注創建進程的方法,這個startSpecificActivityLocked()
再次進行了一波進程是否存在的判斷,接著會調用ActivityManagerService的startProcessLocked()
開始進程的創建。這個創建的過程也是相當兇殘的,在這里就先簡潔了當的介紹一下:
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
Process.start()
完成了ActivityThread的創建,之后就會執行ActivityThread的main()
方法,這一步可謂是知識點豐富啊!
2.6 ActivityThread
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
...
Looper.loop();
...
}
大家所熟知的Looper終于在此閃亮登場,下一篇文章會詳細介紹Looper機制。今天還是先把舞臺交給thread.attach(false)
。這個方法感覺熟悉嗎?在之前的window介紹中,我們提到過mWindow是在Activity的attach()方法中初始化的,現在就的走進attach
好好看一看吧。
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
}
mgr是老朋友了,其本體是IActivityManager,也就是說這里通過AIDL調用了ActivityManagerService的attachApplication(mAppThread)
,而attachApplication(mAppThread)
又接著調用了attachApplicationLocked(thread, callingPid)
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
如果此時是正常模式,那就執行mStackSupervisor.attachApplicationLocked(app)
,堅持住,曙光馬上就要來臨了!
ActivityRecord hr = stack.topRunningActivityLocked(null);
if (hr != null) {
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new application when starting activity "
+ hr.intent.getComponent().flattenToShortString(), e);
throw e;
}
}
}
還是和之前的流程一樣,在ActivityStackSupervisor中,先獲取處于棧頂的ActivityStack,再通過ActivityStack獲取處于頂層ActivityRecord的,最后通過realStartActivityLocked(hr, app, true, true)
,顧名思義,真正的啟動一個Activity。
不過有眼尖的朋友發現了,這里的if判斷怎么有個條件是hr.app == null
呢?要知道,雖然之前的代碼中ActivityThread已經創建好了,但此時還沒有與ActivityRecord關聯起來,而這正是realStartActivityLocked()
要做的。
那么Activity要如何真正的啟動呢?
第一步 mWindowManager.setAppVisibility(r.appToken, true);
,將該Activity所對應的window設置成可見。
第二步,調用app.thread.scheduleLaunchActivity(...參數很長...)
方法
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
scheduleLaunchActivity()
中先將參數封裝成ActivityClientRecord對象,再向Handler H發送Message。這部分流程和之前說的pause流程相似,會調用 handleLaunchActivity(r, null)
,接著調用performLaunchActivity(r, customIntent)
,再通過反射將Activity創建出來,最后開始Activity生命周期的調用。
Activity activity = null;
try {
ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
}
總結
看到這里,正常人應該已經暈的不要不要的了,所以還是需要象征性的總結一下。
(一)ActivityManagerService(ActivityManagerNative)是核心管理類,負責組件的管理,在這里主要與ActivityStackSupervisor通信。
(二)ActivityStackSupervisor管理整個手機任務棧,即管理著ActivityStack。
(三)ActivityStack是Activity的棧,即任務棧,從中可以獲取需要進行操作的ActivityRecord,并且可以對任務的進程進行操作。
(四)ActivityThread是安卓java應用層的入口函數類,它會執行具體對Activity的操作,并將結果通知給ActivityManagerService。
完結撒花~