Activity啟動流程源碼解析上(8.0)

上個小節(jié)我們學習了跨進程通信,相信大家對于AIDL已經(jīng)很熟悉了蔓肯,今天我們趁熱打鐵遂鹊,一起來看下Activity的啟動流程。對AIDL還不了解的小伙伴請先移步至上小節(jié)文章:http://www.reibang.com/p/1f1472991d72 蔗包。

我們知道秉扑,Activity有兩種常見的啟動方式,一種是在桌面點擊應用圖標调限,進入應用程序的主界面舟陆,另一種方式就是用戶在應用程序的Activity點擊某個按鈕或者其他跳轉(zhuǎn)到另一個Activity。我先簡單說下Android系統(tǒng)的啟動順序:init進程 -> Zygote進程 -> SystemServer進程 -> 應用程序進程耻矮。我們大家都知道秦躯,Android系統(tǒng)是基于Linux內(nèi)核的,所以首先啟動Linux的init進程裆装,接著由init進程啟動Zygote(受精卵)進程宦赠。Zygote進程可以說是所有Android進程的父進程陪毡,后續(xù)啟動的SystemServer進程和各種應用程序進程都是由Zygote進程fork出來的。而我們的手機桌面就是Android系統(tǒng)啟動的第一個應用程序進程勾扭,上述兩種Activity的啟動方式底層都是通過IPC機制來實現(xiàn)的毡琉。

我先舉個栗子來考考大家,當我們在應用程序中由ActivityA跳轉(zhuǎn)到ActivityB妙色,兩者的生命周期方法執(zhí)行的順序是怎樣的呢桅滋?答案是:ActivityA onPause -> ActivityB onCreate -> ActivityB onStart -> ActivityB onResume -> ActivityA onStop。這個也是面試官經(jīng)常問的一個小知識點身辨,如果你答錯的話可要好好補習下基礎知識啦哈哈哈丐谋,在這里我們就以兩者的生命周期方法執(zhí)行順序為引線,來從源碼的角度看下Activity的啟動流程煌珊。

下面的代碼我們再熟悉不過了:

    Intent intent = new Intent(MainActivity.this,OtherActivity.class);
    startActivity(intent);

跟進去startActivity方法看下:

    #Activity

    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }

    -- >

    @Override
    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) {
        startActivityForResult(intent, requestCode, null);
    }

    -->

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        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());
            }
            if (requestCode >= 0) {
               
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

可以看到方法最終會調(diào)用到mInstrumentation.execStartActivity方法号俐,我們接著跟:

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
       
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);

            // 重點
            int result = ActivityManager.getService()
                .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;
    }

上述代碼有刪減,我們可以看到方法中調(diào)用到 ActivityManager.getService().startActivity方法定庵。ActivityManager.getService()方法獲取到的是什么呢吏饿?我們跟進去看下:

    # ActivityManager
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

接著看下IActivityManagerSingleton的定義:

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

IActivityManagerSingleton的get方法直接將am返回出去了,am又是什么呢蔬浙?可以看到am是通過IActivityManager.Stub.asInterface(b); 獲取到的猪落,am所屬類型為 IActivityManager 〕氩看到這里大家有沒有一種似曾相識的感覺笨忌?AIDL,對的俱病!我們的應用程序就屬于客戶端進程官疲,而SystemServer進程則是服務端進程,在IActivityManager 接口中定義了我們應用程序進程到SystemServer進程單向通信需要調(diào)用的各種方法亮隙。SystemServer進程中對應的Binder實現(xiàn)類就是ActivityManagerService(簡稱AMS)途凫,AMS中的方法都是運行在服務端的Binder線程池中。SystemServer進程到我們的應用進程單向通信的接口為IApplicationThread咱揍,對應的Binder實現(xiàn)類為ApplicationThread颖榜,大家翻看源碼就可以發(fā)現(xiàn),ApplicationThread是ActivityThread的內(nèi)部類煤裙,同樣ApplicationThread類中的方法都是運行在客戶端的Binder線程池中掩完,正因為如此,所以我們收到服務端進程的指令后需要借助Handler硼砰,也就是mH(Handler)切換到UI線程進行處理且蓬。

我們回過頭接著看,代碼中調(diào)用ActivityManager.getService().startActivity方法题翰,也就是調(diào)用到AMS的startActivity方法恶阴,我們跟進去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());
    }

可以看到方法中直接調(diào)用了startActivityAsUser方法诈胜,我們接著跟下去,接下來的代碼量有點多冯事,做好準備哈哈焦匈。

    #ActivityManagerService
    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }

    -->

    #ActivityStarter             //代碼適當刪減
    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 globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {

            final ActivityRecord[] outRecord = new ActivityRecord[1];
            //重點
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);

            Binder.restoreCallingIdentity(origId);

    }

    -->

   #ActivityStarter
   int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask, String reason) {

        if (TextUtils.isEmpty(reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        mLastStartReason = reason;
        mLastStartActivityTimeMs = System.currentTimeMillis();
        mLastStartActivityRecord[0] = null;
        //重點
        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                container, inTask);

        if (outActivity != null) {
            // mLastStartActivityRecord[0] is set in the call to startActivity above.
            outActivity[0] = mLastStartActivityRecord[0];
        }
        return mLastStartActivityResult;
    }

    -->
 
    #ActivityStarter
    /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
    //重點
    return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
    }

    -->

    #ActivityStarter
    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            //重點
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } finally {
            // If we are not able to proceed, disassociate the activity from the task. Leaving an
            // activity in an incomplete state can lead to issues, such as performing operations
            // without a window container.
            if (!ActivityManager.isStartResultSuccessful(result)
                    && mStartActivity.getTask() != null) {
                mStartActivity.getTask().removeActivity(mStartActivity);
            }
            mService.mWindowManager.continueSurfaceLayout();
        }

        postStartActivityProcessing(r, result, mSupervisor.getLastStack().mStackId,  mSourceRecord,
                mTargetStack);

        return result;
    }

    -->

    #ActivityStarter
    // Note: This method should only be called from {@link startActivity}.
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
    //重點
    mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
    }

好吧,終于調(diào)用到ActivityStackSupervisor類了昵仅,我們接著跟:

   #ActivityStackSupervisor
   boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || r.state != RESUMED) {
            //重點   在這里r可以理解為將要執(zhí)行onPause方法的上一個Activity
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } else if (r.state == RESUMED) {
            // Kick off any lingering app transitions form the MoveTaskToFront operation.
            mFocusedStack.executeAppTransition(targetOptions);
        }
        return false;
    }

    -->

    #ActivityStack
    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            // 重點
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
      
        return result;
    }

    -->

    #ActivityStack
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
   
       if (mResumedActivity != null) {
            //重點 mResumedActivity 指的就是將要執(zhí)行onPause方法的上一個Activity缓熟,這里可以說是onPause方法執(zhí)行的入口
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }
    }

我跟跟跟:

    #ActivityStack
    /**
     * Start pausing the currently resumed activity.  It is an error to call this if there
     * is already an activity being paused or there is no resumed activity
     * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
     * it to tell us when it is done.
     */
    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
            ActivityRecord resuming, boolean pauseImmediately) {

         ActivityRecord prev = mResumedActivity;
         mResumedActivity = null;

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

我們先看下注解,大概意思就是說這個方法是用來執(zhí)行上個Activity的onPause方法的摔笤,如果上個Activity在此之前已經(jīng)為paused狀態(tài)的話够滑,調(diào)用這個方法會出錯。在調(diào)用到try代碼塊中的prev.app.thread.schedulePauseActivity方法后吕世,會直接return true彰触,然后等待客戶端進程告訴我們結(jié)果。然后在resumeTopActivityInnerLocked方法中由于startPausingLocked方法的返回值為true命辖,會使得pausing 的值為true况毅,后續(xù)進入一個if語句直接return掉了,代碼不會繼續(xù)向下執(zhí)行吮龄。至于調(diào)用到try代碼塊中的prev.app.thread.schedulePauseActivity方法后俭茧,為什么會直接return true咆疗,大家看下代碼細節(jié)就會明白了漓帚,這里就不過細分析了。在上述方法中有一個重要的點需要我們注意下午磁,那就是try代碼塊執(zhí)行前的上述兩行代碼尝抖,可以看到,代碼中首先將mResumedActivity賦值給prev迅皇,接著將 mResumedActivity 置為null昧辽。為什么要這么操作呢?答案就是后續(xù)的IPC過程中會再次調(diào)用到ActivityStack類的resumeTopActivityInnerLocked方法登颓,這個時候由于mResumedActivity已經(jīng)為null搅荞,程序不會進入到if語句塊再次執(zhí)行startPausingLocked方法,而是會接著向下執(zhí)行框咙。

我們可以看到咕痛,在上述代碼中,最終會調(diào)用到prev.app.thread.schedulePauseActivity方法喇嘱,也就是調(diào)用到客戶端進程ApplicationThread類的schedulePauseActivity方法茉贡。不知道大家在這里有沒有想過,我們的應用程序客戶端進程是怎么將ApplicationThread注冊到SystemServer進程的呢者铜?答案當然是在我們的應用程序客戶端進程啟動的時候啦腔丧,怎么你不信放椰?我們上代碼哈哈:

我們都知道,我們的應用程序進程啟動的起點就是它的ActivityThread類的main方法愉粤,下面我們一起來看下(代碼有刪減):

    public static void main(String[] args) {
        
        // 1.
        Looper.prepareMainLooper();
        // 2.
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // 3.
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

我們可以看到砾医,代碼中首先調(diào)用了 Looper.prepareMainLooper();接著創(chuàng)建了一個當前ActivityThread 類的實例對象,調(diào)用它的attach方法衣厘,最后調(diào)用到Looper.loop();方法進行循環(huán)藻烤。重點就在這個attach方法,我們跟進去看下:

    private void attach(boolean system) {
            final IActivityManager mgr = ActivityManager.getService();
            try {
                // 重點
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
    }

上述代碼有所刪減头滔,我們可以看到attach方法中最終會調(diào)用到 mgr.attachApplication方法怖亭,將mAppThread作為參數(shù),傳遞過去坤检,mAppThread是什么呢兴猩?我們看下:

    final ApplicationThread mAppThread = new ApplicationThread();

哈哈,可以看到mAppThread 就是ApplicationThread 類的一個實例對象早歇,也就是說attach方法中調(diào)用到mgr.attachApplication方法倾芝,將ApplicationThread 類的實例對象mAppThread 作為參數(shù)傳遞過去。通過mgr的定義我們可以知道箭跳,這是從客戶端進程到SystemServer進程的一次IPC晨另,所以最終會調(diào)用到AMS的attachApplication方法,我們跟過去看下:

    @Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            //重點
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }

    -->

    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

        //重點
        app.makeActive(thread, mProcessStats);
        app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
        app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        app.forcingToImportant = null;
        updateProcessForegroundLocked(app, false, false);
        app.hasShownUi = false;
        app.debugging = false;
        app.cached = false;
        app.killedByAm = false;
        app.killed = false;

可以看到attachApplicationLocked方法中調(diào)用到app.makeActive方法(app類型為ProcessRecord)谱姓,將我們ApplicationThread 類的實例對象作為第一個參數(shù)傳遞了過去借尿,我們跟進去makeActive方法看下:

    public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
        if (thread == null) {
            final ProcessState origBase = baseProcessTracker;
            if (origBase != null) {
                origBase.setState(ProcessStats.STATE_NOTHING,
                        tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
                origBase.makeInactive();
            }
            baseProcessTracker = tracker.getProcessStateLocked(info.packageName, uid,
                    info.versionCode, processName);
            baseProcessTracker.makeActive();
            for (int i=0; i<pkgList.size(); i++) {
                ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
                if (holder.state != null && holder.state != origBase) {
                    holder.state.makeInactive();
                }
                holder.state = tracker.getProcessStateLocked(pkgList.keyAt(i), uid,
                        info.versionCode, processName);
                if (holder.state != baseProcessTracker) {
                    holder.state.makeActive();
                }
            }
        }
        thread = _thread;
    }

可以看到在makeActive方法的最后,將我們ApplicationThread 類的實例對象賦值給app(ProcessRecord類型)的成員變量thread 屉来,這樣就完成了注冊路翻。

好了,我們回過頭接著看茄靠,在上述startPausingLocked方法中茂契,最終調(diào)用到prev.app.thread.schedulePauseActivity方法,也就是調(diào)用到客戶端進程ApplicationThread類的schedulePauseActivity方法慨绳,我們跟過去看下:

    public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport) {
            int seq = getLifecycleSeq();
            if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
                    + " operation received seq: " + seq);
            sendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
                    configChanges,
                    seq);
    }

可以看到客戶端進程ApplicationThread類的schedulePauseActivity方法中直接調(diào)用了sendMessage方法掉冶,接著跟:

    private void sendMessage(int what, Object obj, int arg1, int arg2, int seq) {
        if (DEBUG_MESSAGES) Slog.v(
                TAG, "SCHEDULE " + mH.codeToString(what) + " arg1=" + arg1 + " arg2=" + arg2 +
                        "seq= " + seq);
        Message msg = Message.obtain();
        msg.what = what;
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = obj;
        args.argi1 = arg1;
        args.argi2 = arg2;
        args.argi3 = seq;
        msg.obj = args;
        mH.sendMessage(msg);
    }

可以看到sendMessage方法中直接調(diào)用mH(Handler)的sendMessage方法發(fā)送了一條消息,大家想下脐雪,這里為什么需要借助Handler來發(fā)送一條消息呢厌小?答案就是ApplicationThread類的schedulePauseActivity方法是執(zhí)行在客戶端進程的Binder線程池中,需要切換至UI線程喂江,肯定要借助偉大的Handler啦召锈。下面我們到mH的handleMessage方法中看下:

    public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            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;
                case RELAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;
                    handleRelaunchActivity(r);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;

                //重點
                case PAUSE_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    SomeArgs args = (SomeArgs) msg.obj;
                    handlePauseActivity((IBinder) args.arg1, false,
                            (args.argi1 & USER_LEAVING) != 0, args.argi2,
                            (args.argi1 & DONT_REPORT) != 0, args.argi3);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                case PAUSE_ACTIVITY_FINISHING: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    SomeArgs args = (SomeArgs) msg.obj;
                    handlePauseActivity((IBinder) args.arg1, true, (args.argi1 & USER_LEAVING) != 0,
                            args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                case STOP_ACTIVITY_SHOW: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
                    SomeArgs args = (SomeArgs) msg.obj;
                    handleStopActivity((IBinder) args.arg1, true, args.argi2, args.argi3);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                case STOP_ACTIVITY_HIDE: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
                    SomeArgs args = (SomeArgs) msg.obj;
                    handleStopActivity((IBinder) args.arg1, false, args.argi2, args.argi3);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;

                ......

可以看到在 case PAUSE_ACTIVITY 語句段調(diào)用了handlePauseActivity方法,這個就是用來執(zhí)行上個Activity的onPause方法的入口获询,我們跟進去:

    private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport, int seq) {
        ActivityClientRecord r = mActivities.get(token);
          
            //1.
            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
       
            if (!dontReport) {
                try {
                    //2.
                    ActivityManager.getService().activityPaused(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
            mSomeActivitiesChanged = true;
        }
    }

在這里我們先來看下標注 1 處涨岁,調(diào)用到performPauseActivity方法拐袜,還等什么,肯定跟進去啊哈哈:

   final Bundle performPauseActivity(IBinder token, boolean finished,
            boolean saveState, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
    }

    -->
    
    final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState, String reason) {
       
        if (!r.activity.mFinished && saveState) {
            //1.
            callCallActivityOnSaveInstanceState(r);
        }
         //2.
        performPauseActivityIfNeeded(r, reason);
    }

標注 1 處的方法最終會回調(diào)Activity的onSaveInstanceState方法梢薪,我們一般情況下會重寫onSaveInstanceState方法來進行保存數(shù)據(jù)蹬铺,大家感興趣的可以點開源碼看下,這里就不展開分析了秉撇,我們一起來看下 2 處的performPauseActivityIfNeeded方法甜攀,跟進去:

   private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
        try {
            r.activity.mCalled = false;
            //重點  跟進去
            mInstrumentation.callActivityOnPause(r.activity);
            }
        } catch (SuperNotCalledException e) {
            throw e;
        } 
    }

    -->

    #Instrumentation
    public void callActivityOnPause(Activity activity) {
        activity.performPause();
    }

    -->

    #Activity
    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;
    }

最終終于在performPause方法中找到Activity的onPause方法回調(diào)了琐馆!容老夫大笑兩分鐘先哈哈哈规阀。

好了,讓我們回到handlePauseActivity方法接著看下 2 處代碼瘦麸,可以看到 2 處調(diào)用到ActivityManager.getService().activityPaused方法谁撼,這是一次由客戶端進程向SystemServer進程發(fā)起的單向IPC,最終會調(diào)用到AMS的activityPaused方法滋饲。

欲知后事如何厉碟,請看下回分解,時間不早了屠缭,我要先洗洗睡了箍鼓,明早還要早起上班。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末呵曹,一起剝皮案震驚了整個濱河市款咖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逢并,老刑警劉巖之剧,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郭卫,死亡現(xiàn)場離奇詭異砍聊,居然都是意外死亡,警方通過查閱死者的電腦和手機贰军,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門玻蝌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人词疼,你說我怎么就攤上這事俯树。” “怎么了贰盗?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵许饿,是天一觀的道長。 經(jīng)常有香客問我舵盈,道長陋率,這世上最難降的妖魔是什么球化? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮瓦糟,結(jié)果婚禮上筒愚,老公的妹妹穿的比我還像新娘。我一直安慰自己菩浙,他們只是感情好巢掺,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著劲蜻,像睡著了一般陆淀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上先嬉,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天倔约,我揣著相機與錄音,去河邊找鬼坝初。 笑死浸剩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的鳄袍。 我是一名探鬼主播绢要,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拗小!你這毒婦竟也來了重罪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤哀九,失蹤者是張志新(化名)和其女友劉穎剿配,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阅束,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡呼胚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了息裸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝇更。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呼盆,靈堂內(nèi)的尸體忽然破棺而出年扩,到底是詐尸還是另有隱情,我是刑警寧澤访圃,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布厨幻,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏况脆。R本人自食惡果不足惜平绩,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漠另。 院中可真熱鬧捏雌,春花似錦、人聲如沸笆搓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽满败。三九已至肤频,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間算墨,已是汗流浹背宵荒。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留净嘀,地道東北人报咳。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像挖藏,于是被迫代替她去往敵國和親暑刃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345