從原始碼的角度看Activity是如何啟動的

溫斯渤發表於2017-07-05

前言

終於申請成為掘金的專欄啦!以後就可以在這裡與大家一起分享知識咯!!!還是希望大家訪問我的個人部落格 ,這篇文章的原文地址在這裡
今天想與大家一起分享的是Activity。我們平時接觸的最多的就是Activity了,作為四大元件中最為重要的老大,Activity究竟是如何啟動的呢?這篇文章將會從原始碼的角度為大家進行全方位的解析,為了方便大家理解整個的過程,我會用流程圖的方式將整個過程串起來,希望對大家有所幫助。

開始吧!

一般我們啟動Activity有兩種方法,這裡我就不再詳細說這兩種方法的用法了,不過他們都是呼叫了同樣的一個邏輯startActivity。所以我們分析Activity的啟動流程就從這個方法開始。

 public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        startActivityForResult(intent, -1);
    }
}複製程式碼

可以看到儘管startActivity()有多種過載方式,但是最終呼叫的還是startActivityForResult,所以我們只需要看startActivityForResult裡面的實現邏輯即可。這裡需要注意的一點就是呼叫了startActivityForResult方法時傳入的一個引數為-1,為什麼是-1呢?還記得我們如果需要下一個Activity返回資料給目前這個Activity的時候都是呼叫startActivityForResult方法,不會去呼叫startActivity,因為startActivity儘管最後還是呼叫startActivityForResult,但是他設定了requestCode引數為-1,而在startActivityForResult方法中會判斷requestCode是否大於等於0,如果小於0就不會返回結果,因此我們都會選擇startActivityForResult方法以取回結果,並且設定其code引數大於等於0。下面我們來看看startActivityForResult的實現:

public void startActivityForResult(
@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {
        //mParent是一個Activity物件,表示該Activity是否由父Activity啟動
    if (mParent == null) {
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this,
                intent, requestCode, options);
        if (ar != null) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        //這裡就是判斷requestCode的邏輯
        if (requestCode >= 0) {
            mStartedActivity = true;
        }

        cancelInputsAndStartExitTransition(options);
    } else {
        if (options != null) {
            mParent.startActivityFromChild(this, intent, requestCode, options);
        } else {
            mParent.startActivityFromChild(this, intent, requestCode);
        }
    }
}複製程式碼

在startActivityForResult方法中,首先會判斷該Activity是否由父Activity啟動,即mParent,如果他是第一個Activity,就會呼叫Instrumentation的execStartActivity方法,這裡再看一下判斷requestCode的邏輯:

if (requestCode >= 0) {
    mStartedActivity = true;
}複製程式碼

可以看到在這裡確實判斷了requestCode的大小,大於等於0的時候才會返回結果,否則是不會的。
繼續說回execStartActivity方法,這裡就是正真執行Activity啟動的操作,解釋一下他的幾個引數:

  • this,為啟動Activity的物件
  • mMainThread.getApplicationThread(),為Binder物件,是主程式的context物件
  • token,也是一個Binder物件,指向了服務端一個ActivityRecord物件
  • target,為啟動的Activity
  • intent,啟動的Intent物件
  • requestCode,請求碼
  • options,引數

這裡的第一個Binder物件在我們的整個分析過程中將扮演者非常重要的作用,如果你對Binder不熟悉的話,請到這裡瞭解有關Binder機制的內容。
接下來是execStartActivity方法:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    ...
    try {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, options);
        checkStartActivityResult(result, intent);
    } catch (RemoteException e) {
        throw new RuntimeException("Failure from system", e);
    }
    return null;
}複製程式碼

這裡最重要的就是呼叫了ActivityManagerNative.getDefault().startActivity(),但是ActivityManagerNative.getDefault()是什麼東西呢?我們繼續看getDefault()的原始碼:

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);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};複製程式碼

可以看到其中宣告瞭一個Singleton封裝類,其型別是IActivityManager,注意到其中呼叫了asInterface方法,接著看他做了什麼?

static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        return null;
    }
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }

    return new ActivityManagerProxy(obj);
}


//ActivityManagerProxy:startActivity
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }複製程式碼

可以看到asInterface返回了一個ActivityManagerProxy物件,也就是說ActivityManagerNative.getDefault()返回的就是一個ActivityManagerProxy物件,通過之前的BInder機制的文章我們可以知道Proxy是執行在客戶端的,客戶端通過將引數寫入Proxy類,接著Proxy就會通過Binder去遠端呼叫服務端的具體方法,因此,我們只是借用ActivityManagerProxy來呼叫ActivityManagerService的方法,他們之間的關係如下所示:

通訊方式
通訊方式

到目前為止Activity的啟動流程就是如下所示了,可以看到Activity的啟動邏輯來到了AMS中。

在AMS中啟動Activity

@Override
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());
}

@Override
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");
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            false, ALLOW_FULL_ONLY, "startActivity", null);
    // TODO: Switch to user app stacks here.
    return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
            resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, null, null, options, false, userId, null, null);
}複製程式碼

在startActivity中直接呼叫了startActivityAsUser方法,而在startActivityAsUser中則是呼叫mStackSupervisor.startActivityMayWait方法:

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 ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
    ActivityContainer container, TaskRecord inTask) {
    int err = ActivityManager.START_SUCCESS;

    ...
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
        startFlags, true, options, inTask);

    ...
    return err;
    }複製程式碼

這個方法中主要構造了ActivityManagerService端的Activity物件:ActivityRecord,並根據Activity的啟動模式執行了相關邏輯。然後呼叫了startActivityUncheckedLocked方法,而在startActivityUncheckedLocked中則呼叫了startActivityUncheckedLocked方法,startActivityUncheckedLocked方法則會呼叫startActivityLocked方法,startActivityLocked又會呼叫resumeTopActivitiesLocked方法,其最後呼叫了resumeTopActivityLocked方法。
經過一系列的呼叫之後,最終來到了startPausingLocked方法,它會執行Activity的onPause方法,從而結束當前的Activity。
首先來看startPausingLocked方法:

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,boolean dontWait) {
    ...
    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;
        }
    } else {
        mPausingActivity = null;
        mLastPausedActivity = null;
        mLastNoHistoryActivity = null;
    }
    ...
}複製程式碼

這裡有一個很重要的地方就是prev.app.thread,其實他就是一個IApplicationThread型別的物件,而ApplicationThread則是ActivityThread的一個內部類,它繼承了IApplicationThread,並且都是Binder物件,所以說Appcation是一個客戶端,而ActivityThread中是一個服務端,到現在為止,Activity的呼叫來到了ActivityThread中,如下圖所示:

在ActivityThread中pause掉當前Activity

在ActivityThread中則是呼叫了schedulePauseActivity來執行pause操作:

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);
}複製程式碼

可以看到在schedulePauseActivity中則是通過handler來傳送訊息,訊息型別為PAUSE_ACTIVITY_FINISHING,那接下來就應該看收到訊息之後如何來處理了,

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
    ActivityClientRecord r = mActivities.get(token);
    if (r != null) {
        //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
        if (userLeaving) {
            performUserLeavingActivity(r);
        }

        r.activity.mConfigChangeFlags |= configChanges;
        performPauseActivity(token, finished, r.isPreHoneycomb());

        // Make sure any pending writes are now committed.
        if (r.isPreHoneycomb()) {
            QueuedWork.waitToFinish();
        }

        // Tell the activity manager we have paused.
        if (!dontReport) {
            try {
                ActivityManagerNative.getDefault().activityPaused(token);
            } catch (RemoteException ex) {
            }
        }
        mSomeActivitiesChanged = true;
    }
}複製程式碼

可以看到在方法內部通過呼叫performPauseActivity方法來實現對當前Activity的onPause生命週期方法的回撥,具體是呼叫了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;
}複製程式碼

可以看到最終是呼叫了Activity的onPause()方法,接著我們回到handlePauseActivity的第二個方法ActivityManagerNative.getDefault().activityPaused(token),這是應用程式告訴服務程式,當前的Activity已經執行完成onPause方法了,其最後會呼叫completePauseLocked方法:

private void completePauseLocked(boolean resumeNext) {
    ...
    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);
            }
        }
    }
}複製程式碼

可以看到經過了一系列的邏輯之後,又呼叫了resumeTopActivitiesLocked方法,而在該方法中則是呼叫了startSpecificActivityLocked 來啟動新的Activity。來看看目前的流程圖:

啟動新的Activity

在startSpecificActivityLocked方法中,其實現細節則是和呼叫Activity的pause方法一樣,都是通過Handler機制,傳送一個啟動Activity的訊息,接著處理該訊息最後啟動Activity。其呼叫的是performLaunchActivity方法:

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());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }
        ...

        activity.mCalled = false;
        if (r.isPersistable()) {
           mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
           mInstrumentation.callActivityOnCreate(activity, r.state);
        }
        ...
        if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
        ...
        return activity;
    }複製程式碼

可以看到最終的Activity物件終於建立出來了,可以看到其過程是使用反射機制建立的,而反射機制在Android系統中的應用也是隨處可見。在接下來的過程中還會繼續執行Activity的onCreate等一系列的生命週期方法。
最後再來看一下整個過程最終的流程圖:

相關文章