1. 程式人生 > >Activity啟動流程分析(基於android 5.1)

Activity啟動流程分析(基於android 5.1)

最近由於工作需要,需要深入瞭解AMS的內部實現。說老實話,雖然已經經過了幾輪重構,AMS的程式碼還是又臭又長。。。

萬事開頭難,先找個入口開始看吧。當從Launcher介面點選啟動一個app時,會啟動一個新的activity。所以就從startActivity()看起,研究一下activity啟動的整個流程。

雖然程式碼很長,大體上還是有個一個脈絡的,參見下圖:


這樣是不是感覺清楚很多?基本上分為下面這些步驟:

  • 建立相關的資料結構並建立聯絡(ActivityRecord, ActivityStack, TaskRecord等等)
  • Pause前一個activity(這裡指的就是Launcher)
  • 建立新程序,啟動新的ActivityThread
  • 傳遞binder通訊物件,建立Activity並呼叫其onCreate()方法

下面詳細分析一下相關程式碼(基於android 5.1):

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);
    }
}

Activity呼叫Instrumentation去啟動新的activity

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
... ...
    Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
... ...
}

Instrumentation通過binder將請求傳送到遠端的ActivityManagerServiceActivityManagerNative.getDefault()返回的是一個IActivityManager介面,後面會詳細講解這個介面是怎麼和遠端聯絡起來的。

public ActivityResult execStartActivity(
    Context who, IBinder contextThread, IBinder token, Fragment target,
    Intent intent, int requestCode, Bundle options) {
    ... ...
    int result = ActivityManagerNative.getDefault()
        .startActivity(whoThread, who.getBasePackageName(), intent,
                intent.resolveTypeIfNeeded(who.getContentResolver()),
                token, target != null ? target.mWho : null,
                requestCode, 0, null, options);
    ... ...
}
static public IActivityManager getDefault() {
    return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        return am;
    }
}

先看一下Java Binder的一般結構:


左半邊是server端的具體實現,右半邊是client端使用的代理。這樣一來就很清楚了,IActivityManager必定有一個ActivityManagerProxy的代理類,裡面包含了一個BinderProxy物件來和遠端通訊。遠端也必定有一個ActivityManagerNative的類負責響應binder請求,同時有一個子類來完成具體的業務邏輯,這個類就是ActivityManagerService。具體類圖如下:


這裡談到了ActivityManagerService,那我們就先來看一下它是怎麼啟動的。

ActivityManagerService是在SystemServer裡通過SystemServiceManagerstartService()方法啟動的,傳入的引數是一個叫Lifecycle的內部類。該方法會利用反射的方式,根據類名獲取其建構函式,建立物件例項,最後呼叫serviceonStart()方法。

// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
	ActivityManagerService.Lifecycle.class).getService();

public <T extends SystemService> T startService(Class<T> serviceClass) {
    ... ... 
    Constructor<T> constructor = serviceClass.getConstructor(Context.class);
    service = constructor.newInstance(mContext);
    ... ...
    // Register it
    mServices.add(service);
    // Start it
    service.onStart();
    ... ...
}

看一眼Lifecycle類,該類繼承自SystemService,建構函式裡會建立ActivityManagerService例項,onStart()裡會呼叫ActivityManagerServicestart()方法。

public static final class Lifecycle extends SystemService {
    private final ActivityManagerService mService;

    public Lifecycle(Context context) {
        super(context);
        mService = new ActivityManagerService(context);
    }

    @Override
    public void onStart() {
        mService.start();
    }

    public ActivityManagerService getService() {
        return mService;
    }
}

僅僅啟動ActivityManagerService是不夠的,外面的人怎麼來訪問它呢?顯然需要把ActivityManagerService註冊到ServiceManager裡,這一步也是在SystemService裡完成的:

private void startBootstrapServices() {
    ... ...
    // Set up the Application instance for the system process and get started.
    mActivityManagerService.setSystemProcess();
    ... ...
}

public void setSystemProcess() {
    ... ...
    ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
    ... ...
}
再回到之前的話題,我們通過binder 遠端呼叫ActivityManagerService的startActivity()方法:
public final int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options) {
    return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        resultWho, requestCode, startFlags, profilerInfo, options,
        UserHandle.getCallingUserId());
}

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
    enforceNotIsolatedCaller("startActivity");
    ... ...
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, userId, null, null);
}

呼叫ActivityStackSupervisorstartActivityMayWait()方法:

final int startActivityMayWait(IApplicationThread caller, int callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
        Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {
    ... ...
    ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
            profilerInfo, userId);
    ... ...
    int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                voiceSession, voiceInteractor, resultTo, resultWho,
                requestCode, callingPid, callingUid, callingPackage,
                realCallingPid, realCallingUid, startFlags, options,
                componentSpecified, null, container, inTask);
    ... ...
}

resolveActivity()會從PackageManagerService獲取目標activity的資訊,比如package名、activity名等。然後呼叫startActivityLocked()

final int startActivityLocked(IApplicationThread caller,
        Intent intent, String resolvedType, ActivityInfo aInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode,
        int callingPid, int callingUid, String callingPackage,
        int realCallingPid, int realCallingUid, int startFlags, Bundle options,
        boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,
        TaskRecord inTask) {
    ... ...
    ProcessRecord callerApp = null;
    callerApp = mService.getRecordForAppLocked(caller);
    ... ...
    ActivityRecord sourceRecord = null;
    if (resultTo != null) {
        sourceRecord = isInAnyStackLocked(resultTo);
    ... ...
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
        intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
        requestCode, componentSpecified, this, container, options);
    if (outActivity != null) {
        outActivity[0] = r;
    }
    ... ...
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
        startFlags, true, options, inTask);
    ... ...
}

首先獲得呼叫程序的ProcessRecordActivityRecord,然後為要啟動的activity建立新的ActivityRecord,最後呼叫startActivityUncheckedLocked()

final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
        boolean doResume, Bundle options, TaskRecord inTask) {
    ... ...
    int launchFlags = intent.getFlags();
    ... ...
    // Should this be considered a new task?
    if (r.resultTo == null && inTask == null && !addingToTask
        && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
    ... ...
    newTask = true;
    targetStack = adjustStackFocus(r, newTask);
    ... ...
    if (reuseTask == null) {
        r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                newTaskInfo != null ? newTaskInfo : r.info,
                newTaskIntent != null ? newTaskIntent : intent,
                voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                taskToAffiliate);
    ... ...
    targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    ... ...
}

首先從intent中獲取activity的啟動模式,如果AndroidManifest.xml中沒有顯示指定launchMode屬性,預設以ActivityInfo.LAUNCH_MULTIPLE的方式啟動activity。(其他三種方式是LAUNCH_SINGLE_INSTANCELAUNCH_SINGLE_TASKLAUNCH_SINGLE_TOP

如果是從Launcher中啟動的activity,預設會帶有FLAG_ACTIVITY_NEW_TASK的標誌,表示需要新建一個task,然後把activity加入到這個task中。

但是在這之前,我們需要先確定要把這個新建的task放到哪個ActivityStack上。ActivityStackSupervisor裡會包含兩個stack,一個叫mHomeStack,主要用於管理Launcher還有SystemUI Rectent Tasksactivity,另一個叫mFocusedStack,用於管理其他appactivity。如果當前沒有其他app在執行,那麼就只有mHomeStack,當其他app啟動時會動態建立一個新的stack。因此你用“dumpsys activity activities”檢視stack狀態時,總能看見一個ID0stack,而另一個stackID是可變的。

首先通過adjustStackFocus()獲取目標stack,由於當前是在home stack,因此需要建立一個新的stack,然後讓mFocusedStack指向這個新棧。

ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
    ... ...
    int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
    ... ...
    mFocusedStack = getStack(stackId);
    return mFocusedStack;
}

值得一提的是,createStackOnDisplay()並不是直接建立一個ActivityStack,而是建立了一個ActivityContainer物件,ActivityContainer的建構函式裡會建立一個ActivityStack

另外,ActivityContainer是一個binder物件,有一個IActivityContainer.aidl與之對應,可以通過IActivityManagerAPI建立和刪除。所以可以把ActivityContainer理解為ActivityStack的馬甲,外部如果想訪問ActivityStack,只能通過ActivityContainer暴露的一些binder API。更多關於ActivityContainer的應用後面有一篇關於ActivityView的文章裡會詳細描述。

接下來就是建立TaskRecord並加入到目標stacktask列表中,並把這個task設定到當前的ActivityRecord中。

TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        boolean toTop) {
    TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
            voiceInteractor);
    addTask(task, toTop, false);
    return task;
}

最後呼叫ActivityStackstartActivityLocked()方法。

final void startActivityLocked(ActivityRecord r, boolean newTask,
        boolean doResume, boolean keepCurTransition, Bundle options) {
    ... ...
    task.addActivityToTop(r);
    task.setFrontOfTask();
    r.putInHistory();
    ... ...
    if (doResume) {
        mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
    }
    ... ...
}

首先把activity加入到task中,然後把ActivityRecord中的inHistory標誌置上表示該activity已經在棧中了,最後呼叫ActivityStackSupervisorresumeTopActivitiesLocked()方法。

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
        Bundle targetOptions) {
    ... ...
    result = targetStack.resumeTopActivityLocked(target, targetOptions);
}

這裡主要是為了多個display的處理,一般只有一個顯示屏,因此又調回到了ActivityStack裡面的resumeTopActivityLocked()

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    ... ...
    result = resumeTopActivityInnerLocked(prev, options);
    ... ...
}
final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
    ... ...
    // Find the first activity that is not finishing.
    final ActivityRecord next = topRunningActivityLocked(null);
    ... ...
    // We need to start pausing the current activity so the top one
    // can be resumed...
    if (mResumedActivity != null) {
        pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
    }
    if (pausing) {
        ... ...
        return true;
    }
    ... ...
}

首先獲取棧頂的ActivityRecord,就是我們要啟動的新activity,因為上一步我們已經把要啟動的新activityActivityRecord(其實是包含它的TaskRecord)加入到棧中了。

mResumedActivity表示當前前臺的activity,也就是Launcher activity,呼叫startPausingLocked()pause掉這個activity

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
        boolean dontWait) {
    ... ...
    ActivityRecord prev = mResumedActivity;
    ... ...
    mResumedActivity = null;
    mPausingActivity = prev;
    mLastPausedActivity = prev;
    ... ...
    if (prev.app != null && prev.app.thread != null) {
        prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
             userLeaving, prev.configChangeFlags, dontWait);
    }
    ... ...
}

這一步先獲得當前前臺activityActivityRecord,然後通過它裡面包含的IApplicationThread代理物件和遠端appLauncher)進行通訊。之前提到過app端可以通過一個IActivityManager代理和ActivityManagerService進行binder IPC通訊,反之,ActivityManagerService這端和app端通訊時是通過IApplicationThread代理物件完成,或者確切的說是一個ApplicationThreadProxy物件。類圖基本和之前類似,在此省略。

下面看看appLauncher)端是怎麼響應這個請求的。每個app程序都擁有一個ActivityThread執行緒,它的main()函式是整個程式的主入口。ActivityThread內部聚合了一個ApplicationThread物件,用於響應遠端的請求。接收到請求後,向looper中投遞一個訊息,由handler進行處理。

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);
}

public void handleMessage(Message msg) {
    ... ...
    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;
    ... ...
}

private void handlePauseActivity(IBinder token, boolean finished,
    boolean userLeaving, int configChanges, boolean dontReport) {
    ActivityClientRecord r = mActivities.get(token);
    ... ...
    performPauseActivity(token, finished, r.isPreHoneycomb());
    ... ...
    // Tell the activity manager we have paused.
    if (!dontReport) {
        try {
            ActivityManagerNative.getDefault().activityPaused(token);
        } catch (RemoteException ex) {
    }
}

這裡主要進行了3步操作:

第一步根據token獲取ActivityClientRecord物件,這個物件是在activity啟動時建立的,可以理解為client端的ActivityRecord,複製了一份activity的相關資訊。

第二步呼叫performPauseActivity(),通過Instrumentation物件呼叫我們熟悉activity生命週期中的onPause()方法。

final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState) {
    ... ...
    mInstrumentation.callActivityOnPause(r.activity);
    ... ...
}

第三步通過IActivityManager代理通知ActivityManagerService本端的activity已經進入paused狀態,可以進行下一步操作也就是啟動新的activity了。

ActivityManagerSerivce端的響應程式碼:

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);
}
final void activityPausedLocked(IBinder token, boolean timeout) {
    ... ...
    completePauseLocked(true);
    ... ...
}
private void completePauseLocked(boolean resumeNext) {
    ActivityRecord prev = mPausingActivity;
    if (prev != null) {
        ... ...
        mPausingActivity = null;
    }
    ... ...
    if (resumeNext) {
        final ActivityStack topStack = mStackSupervisor.getFocusedStack();
        if (!mService.isSleepingOrShuttingDown()) {
            mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
        ... ...
    }
}

這裡mPausingActivity在之前的步驟裡已經被置成了Launcher,在執行一些其他清理操作之後將其置為null。最後再次呼叫resumeTopActivitiesLocked()開始啟動新的activity

這次進這個函式,情況已經和之前不同了,mResumedActivity已經被置成了null,因此不會再走進pause activity的邏輯,繼續往前執行。

final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
    ... ...
    final ActivityRecord next = topRunningActivityLocked(null);
    ... ...
    if (next.app != null && next.app.thread != null) {
        ... ...
    } else {
        ... ...
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
}
void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    ... ...
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
        "activity", r.intent.getComponent(), false, false, true);
}

看到startProcessLocked()這個函式,大家應該比較熟悉了,後面就是建立ProcessRecordfork新的程序,然後執行ActivityThreadmain()函數了。

public static void main(String[] args) {
    ... ...
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    ... ...
    Looper.loop();
}

ActivityThreadmain()函式裡,首先建立了一個ActivityThread物件,然後呼叫其attach()方法,最後通過Looper.loop()進入訊息迴圈。

private void attach(boolean system) {
    ... ...
    if (!system) {
    ... ...
    final IActivityManager mgr = ActivityManagerNative.getDefault();
    try {
        mgr.attachApplication(mAppThread);
        ... ...
    }
    ... ...
}

通過binder IPC呼叫到ActivityManagerServiceattachApplicationLocked()。注意這裡傳入的是一個ApplicationThread物件,經過binder傳輸後ActivityManagerService端會獲得該物件的一個代理,之後就可以通過這個代理和app端進行通訊了。

public final void attachApplication(IApplicationThread thread) {
     ... ...
    attachApplicationLocked(thread, callingPid);
    ... ...
}

private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
    ProcessRecord app;
    ... ... //初始化ProcessRecord的一些欄位
    if (mStackSupervisor.attachApplicationLocked(app)) {
        ... ...
    }

    boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    ... ...
    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)) {
    ... ...
}

首先取出棧頂的activity,也就是要要啟動的新activity,然後呼叫realStartActivityLocked()

final boolean realStartActivityLocked(ActivityRecord r,
	ProcessRecord app, boolean andResume, boolean checkConfig) {
    ... ...
    app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
        System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
        r.compat, r.launchedFromPackage, r.task.voiceInteractor, app.repProcState,
        r.icicle, r.persistentState, results, newIntents, !andResume,
        mService.isNextTransitionForward(), profilerInfo);
    ... ...
}

和之前的pause activity一樣,這裡也是通過IApplicationThread代理呼叫到app端的ActivityThread,只不過這裡是新建立的app程序的ActivityThread

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
	ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
	String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
	PersistableBundle persistentState, List<ResultInfo> pendingResults,
	List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
	ProfilerInfo profilerInfo) {
    ActivityClientRecord r = new ActivityClientRecord();
    ... ... //初始化ActivityClientRecord的一些欄位
    sendMessage(H.LAUNCH_ACTIVITY, r);
}

這裡建立了我們之前遇到過的ActivityClientRecord物件,實際上可以理解為對端ActivityRecord的一個本地映象。然後傳送LAUNCH_ACTIVITY的訊息啟動新的activity

public void handleMessage(Message msg) {
    ... ...
    switch (msg.what) {
	case LAUNCH_ACTIVITY: {
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
            ... ...
            handleLaunchActivity(r, null);
            ... ...
}

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ... ...
    Activity a = performLaunchActivity(r, customIntent);
    ... ...
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ... ...
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        ... ...
    }
    ... ...
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    ... ...
    if (activity != null) {
	Context appContext = createBaseContextForActivity(r, activity);
	CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
	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);
        ... ...
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }
        ... ...
    }
    ... ...
    mActivities.put(r.token, r);
    ... ...
}

這裡執行了3個關鍵步驟:

  • 通過class loader載入activity類,並建立新的activity物件
  • 建立Application物件(即Applicaiton Context
  • 建立activity的上下文物件,呼叫onCreate()方法

中間還有一步呼叫activityattach()方法,會建立PhoneWindow物件並與WindowManagerService建立聯絡,後面會專門寫一篇文章研究這部分內容。

至此,整個應用程式的啟動流程就基本完成了。