Android四大组件之Activity启动流程源码实现详解(四)

     Pause前台显示Activity,Resume目标Activity

Android四大组件源码实现详解系列博客目录:

Android应用进程创建流程大揭秘
Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Android四大组件之Activity启动流程源码实现详解(一)
Android四大组件之Activity启动流程源码实现详解(二)
Activity启动流程(三)- Activity Task调度算法复盘分析
Activity启动流程(四)- Pause前台显示Activity,Resume目标Activity


前言

  还记得我们在前面博客Android四大组件之Activity启动流程源码实现详解(二)Activity启动流程(三)- Activity Task调度算法复盘分析中做的艰苦卓越的斗争吗!这场战役之惨烈,战况之持久前所未有!虽然过程是疼苦的,但是战果也是显赫和令人满意的,通过上述战役我们取得了如下的阶段性成果:

  • 初始化了Activity启动状态
  • 计算了启动launchFlag
  • 计算了调用者的ActivityStack
  • 检查了是否存在复用的TaskRecord
  • 对于存在复用的TaskRecord则进行相应的ActivityStack、TaskRecord的移动(说实话,我也没有真的搞懂,希望这块比较有经验的小伙们能和我一起学习)
  • 计算了当前启动Activity所属的TaskRecord
  • 把当前启动的Activity放到所属TaskRecord的栈顶
  • 并且前面的TaskRecord放到了ActivityStack的栈顶

总而言之经过上述一顿猛虎般的操作,此时要启动的目标Actvity及其对应的task位置以及ActivityStack已经安排妥当,现在可以准备接下来的相关工作了,那么在本篇博客中我们将继续分析system_server对Activity启动请求的处理流程:

  • system_server进程通过AMS处理启动Activity请求
    5.Pause前台Activity
    6.Resume请求的目标Activity
    7.AMS请求zygote进程为目标Activity创建所属进程

注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:

frameworks/base/services/core/java/com/android/server/am/
  --- ActivityManagerService.java
  --- ProcessRecord.java
  --- ActivityRecord.java
  --- ActivityResult.java
  --- ActivityStack.java
  --- ActivityStackSupervisor.java
  --- ActivityStarter.java
  --- TaskRecord.java 

frameworks/base/services/core/java/com/android/server/pm/
 --- PackageManagerService.java
 
frameworks/base/core/java/android/content/pm/
--- ActivityInfo.java

frameworks/base/core/java/android/app/
  --- IActivityManager.java
  --- ActivityManagerNative.java (内部包含AMP)
  --- ActivityManager.java
  --- AppGlobals.java
  --- Activity.java
  --- ActivityThread.java(内含AT)
  --- LoadedApk.java  
  --- AppGlobals.java
  --- Application.java
  --- Instrumentation.java
  
  --- IApplicationThread.java
  --- ApplicationThreadNative.java (内部包含ATP)
  --- ActivityThread.java (内含ApplicationThread)
  --- ContextImpl.java

并且在后续的源码分析过程中为了简述方便,会将做如下简述:

  • ApplicationThreadProxy简称为ATP
  • ActivityManagerProxy简称为AMP
  • ActivityManagerService简称为AMS
  • ActivityManagerNative简称AMN
  • ApplicationThreadNative简称ATN
  • PackageManagerService简称为PKMS
  • ApplicationThread简称为AT
  • ActivityStarter简称为AS,这里不要和ActivityServices搞混淆了
  • ActivityStackSupervisor简称为ASS

在正式开始今天博客相关源码分析前,还是先奉上调用的时序图以便小伙们先从整体上有个清晰的概括,然后再从细节开撸!

在这里插入图片描述



一.Pause处于Resume状态Actvity以及Resume目标Activity

  战斗还没有结束,革命尚未成功仍需努力!让我们带着前面博客Android四大组件之Activity启动流程源码实现详解(二)未完成使命继续前进!

//[ActivityStarter.java]
	/*	这里的sourceRecord是指发起调用者
		r是指本次的将要启动的Activity,startFlags取值为0,
		doResume的值为true
	*/
    private int startActivityUnchecked(final ActivityRecord r, 
    									ActivityRecord sourceRecord,
            							IVoiceInteractionSession voiceSession, 
            							IVoiceInteractor voiceInteractor,
            							int startFlags, boolean doResume, 
            							ActivityOptions options, 
            							TaskRecord inTask) {
    
    
         ...
        if (mDoResume) {
    
    
            if (!mLaunchTaskBehind) {
    
    
			/*
			  * 设置当前focused,因为经过以上几步,启动的activity已经转移到
			  *栈顶端,这时候设置AMS当前focused的Activity
			  *另外调用这个函数也会有ActivityStack、Task栈的移动,即调用各自栈把当
			  *前正在启动的Activity所属的Task、ActivityStack移动到栈顶
			  */
                mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
            }
            final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
            if (!mTargetStack.isFocusable()//当前的目标Stack被设置成了焦点所以不会走此分支
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
    
    
                    ...
            } else {
    
    
            	//开始resume,详见章节1.1
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else {
    
    
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }

        return START_SUCCESS;
        ...
}

搞了这么久,发起端Activity和目标Actvity的生命周期一个都没有看到,小伙们是不是心里有些慌了! 不急,这不它就来了,让我们先来看看Acitivyt A启动Activty B的正常生命周期调度:

---> Activity A onCreate
---> Activity A onStart 
---> Activity A onResume
---> Activity A onPause
---> Activity B onCreate
---> Activity B onStart
---> Activity B onResume
---> Activty  A onStop

而我们接下来会沿着上面的主线进行相关的分析,这里我们从A的onPause为起始段开始本篇博客的分析。此时我们将上述场景Activity A启动Activity B带入下面的相关分析中。


1.1 ASS.resumeFocusedStackTopActivityLocked

  让我们对ActivityStackSupervisor中的resumeFocusedStackTopActivityLocked继续分析,其中Android中对于Activity的启动主要表现在如下两个方面:

并且关于这两部分读者最好参考我前面的博客先假定某种启动模式,然后进行相关的分析,否则很容易陷入代码中而不能自拔。而我们这里的resumeFocusedStackTopActivityLocked其实对应的就是Activity的生命周期。

//[ActivityStackSupervisor.java]
    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, 
            ActivityRecord target, 
            ActivityOptions targetOptions) {
    
    
        if (targetStack != null && isFocusedStack(targetStack)) {
    
    
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);//详见章节1.1.1
        }
		...
    }

让我们单刀直入直捣黄龙,接着分析ActivityStack的resumeTopActivityUncheckedLocked方法(不是我不分析,确实是因为没有啥好分析的)。

1.1.1 ActivityStack.resumeTopActivityUncheckedLocked

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

        boolean result = false;
        try {
    
    
			...
            result = resumeTopActivityInnerLocked(prev, options);//详见章节1.2
        } finally {
    
    
            mStackSupervisor.inResumeTopActivity = false;
        }
        return result;
    }

这里没有过多可以介绍的,让我们单刀直入直捣黄龙,接着分析其方法resumeTopActivityInnerLocked,在分析这个方法之前小伙们该上厕所的可以上厕所了,喝水的可以喝水了,因为这又是一个重量级的方法。


1.2 ActivityStack.resumeTopActivityInnerLocked

  在正式开始分析该方法之前,我们先来看看该方法的入参,方法入参的名字挺奇怪的!

参数类型 参数名称 参数功能
ActivityRecord prev 目标Activity的相关信息
ActivityOptions options 额外附加信息

不知各位小伙们发现没有,在上一个方法中发起调用时,传入的参数名称是target,表示待启动的ActivityRecord,但这里摇身一变,参数名称却是prev,看参数意思是表示之前启动的ActivityRecord,即将要进入Pausing状态的那个Activity,到底意欲几何,是不是谷歌的哥哥搞错了啊?这里小伙们先暂且将该疑问放在一边,待我们后续的源码中一一揭秘。此时我们要重点关注,此时的入参为位目标ActivityRecord,虽然它换了一个马甲叫做prev。

//[ActivityStack.java]
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    
    


        if (!mService.mBooting && !mService.mBooted) {
    
    
        	// 如果系统还未启动完毕,那AMS还不能正常工作,所以也不能显示Activity,主要是为防止没有开机启动完成
            return false;
        }
		//此处忽略
        ActivityRecord parent = mActivityContainer.mParentActivity;
		...

		// 当前AS中可能存在一些正处于Intializing状态的ActivityRecord,
	    // 如果这些ActivityRecord不是位于栈顶,而且正在执行窗口启动动画,
	    // 那么,就需要取消这些Activity的启动动画。
        mStackSupervisor.cancelInitializingActivities();


        /*
	        找到第一个没有finishing的栈顶activity,通常指向了要启动的Activity目标组件
	        此场景下prev和next都是同一个,都指向了Activity B
        */
        final ActivityRecord next = topRunningActivityLocked();


        //这个变量是表示是否回调Activity中的onUserLeaveHint和onUserInteraction函数
        final boolean userLeaving = mStackSupervisor.mUserLeaving;
        mStackSupervisor.mUserLeaving = false;

        final TaskRecord prevTask = prev != null ? prev.task : null;
        if (next == null) {
    
    //这个表示如果当前ActivityStack不存在待启动的Activity,那么会启动Launcher桌面
            final String reason = "noMoreActivities";
            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
                    ? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();

			// 当前AS不是全屏显示,则需要将焦点切换到下一个待显示的AS
            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
    
    
                return mStackSupervisor.resumeFocusedStackTopActivityLocked(
                        mStackSupervisor.getFocusedStack(), prev, null);
            }

            
            ActivityOptions.abort(options);

			// 默认情况下,Stack都是占据全屏的,所以,当前Stack如果没有要显示的Activity,则会要求显示桌面
            return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
        }

        next.delayedResume = false;


        //检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
        //并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件
        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                    mStackSupervisor.allResumedActivitiesComplete()) {
    
    
             //当前正在显示的Activity正好就是下一个待显示的Activity,
            // 那么,就中断对目标ActivityRecord的调度
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            return false;
        }

        final TaskRecord nextTask = next.task;
         /*这个是对上一个resumed的Activity的相关处理
		 * 由于我们是第一次启动B Activity,所以不可能处于finish跳过此处
		 */
        if (prevTask != null && prevTask.stack == this &&
                prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
    
    
			...
        }

        // 系统进入休眠状态,当前Stack的栈顶Activity已经处于Paused状态
        // 那么,中断待显示Activity的相关调度(有点拗口,学习源码就是这么枯燥的事情)
        if (mService.isSleepingOrShuttingDownLocked()
                && mLastPausedActivity == next
                && mStackSupervisor.allPausedActivitiesComplete()) {
    
    
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            return false;
        }

		...

		/*
			在ASS中存在很多的数据结构,用来统一管理ActivityRecord的状态
	    	譬如mStoppingActivities记录了当前所有处于Stopping状态的ActivityRecord
	    	mGoingToSleepActivities记录了当前所有要进入休眠状态的ActivityRecord
	    	在某些场景下,待显示的ActivityRecord可能处于这些数组中,但需要从中剔除
		*/
        mStackSupervisor.mStoppingActivities.remove(next);
        mStackSupervisor.mGoingToSleepActivities.remove(next);
        next.sleeping = false;
        mStackSupervisor.mWaitingVisibleActivities.remove(next);

        

         // 如果当前ASS中还有ActivityRecord不是处于PAUSED, STOPPED或STOPPING这三个状态之一,
    	// 那么,需要先等这些ActivityRecord进入停止状态
        if (!mStackSupervisor.allPausedActivitiesComplete()) {
    
    
            return false;
        }

  分析至此,让我们先缓缓,停下前进的脚步看看我们来时的路!前面的代码片段,主要是做一些初始化和可能的"异常"处理工作。虽然我们待显示的目标ActivityRecord已经位于栈顶,但要真正将其显示到前台来,即执行目标Activity的onCreate/onStart/onResume等状态,这一路有很多障碍和初始化工作还处理,或者说还有很多前提条件需要满足,譬如,系统要休眠时,当前启动目标Activity过程要中断;当前ASS中有Activity正处于Pausing状态时,也需要等相关Activity执行完毕才行。我们可以将上述的相关工作认为是准备阶段!前路漫漫是征途,我将上下而求索!

//[ActivityStack.java]
		/*
			setLaunchSource设置待启动的Activity的信息
			跟进setLaunchSource源码发现它最终会获取一个WakeLock,保证在显示Activity的过程中,系统不会进行休眠状态
		*/
        mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
        

         /*
           目标Activity的启动参数中是否包含FLAG_RESUME_WHILE_PAUSING
   		   如果存在FLAG_RESUME_WHILE_PAUSING的flag,表示可以在当前显示的发起端Activity执行Pausing时,
   		   能同时进行Resume操作
    	   即变量dontWaitForPause的取意就是不需要等到Activity执行Pause完毕
    	*/
        final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;


		/* 
		  这个是pause掉不是FocusedStack的其它ActivityStack的栈顶activity
 		  对于不是当前focusStack的并且存在有mResumedActivity不为null的都要paused
 		  譬如从Luncher启动一个新的App时会走入此分支
 		*/
		boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
		/********************************************************************************/
			//这里是为了演示使用
			//ASS.java
		    boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
    
    
		        boolean someActivityPaused = false;
		        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
    
    
		            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
		            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
    
    
		                final ActivityStack stack = stacks.get(stackNdx);
		                if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
    
    
		                    someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
		                            dontWait);
		                }
		            }
		        }
		        return someActivityPaused;
		    }			
		/********************************************************************************/

		//此时要带入真是场景了,此时的mResumedActivity表示目标Stack栈中处于Resume状态的Activity,那么在此场景下就是Activity A,这个因该比较容易理解
		if (mResumedActivity != null) {
    
    
			//当前resumd状态activity不为空,则需要先暂停该Activity
			// pause当前栈的activity,即执行Activity的生命周期onPause
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);//详见章节1.3
			
        }
        if (pausing) {
    
    //当前有正在pause的Activity,尼玛按照我们场景Activity A启动Activity B,那不是到此就结束了啊,直接返回了,事实就是这样的,尼玛是不是走错片场了,后续你就知道了
            if (next.app != null && next.app.thread != null) {
    
    
                mService.updateLruProcessLocked(next.app, true, null);
            }
            return true;
        }
         //检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
        //并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件 
        else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                mStackSupervisor.allResumedActivitiesComplete()) {
    
    
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            return true;
        }

  我们在此就此打住,先不往后分析resumeTopActivityInnerLocked的相关逻辑了,实时上启动目标Acitivity第一次进入该方法时也会从此处返回,事实就是这样的,尼玛是不是走错片场了,后续你就知道了。让我们接着后续分析前面章节1.2提出的问题也会解决了,至于此处为啥在此就return也会解决了。


1.3 Pause前台显示的Activity

  我们对要显示的目标Activity已经做好入栈工作了,就是放在Stack的栈顶,我们可以通过方法ActivityStack.topRunningActivityLocked可以找到它。然后如果当前要Resume的目标Activity不是之前已经Resume的Activity,那么必须将Pause之前的Activity才行,而这部分的具体工作分两部分完成:

  • Pause其他所有已经focus的任务栈的mResumedActivity,调用方法ASS.pauseBackStacks执行
  • Pause当前任务栈的mResumedActivity

最后上述两步都会调到核心方法,ActivityStack.startPausingLocked,而这也是我们本章节将要介绍的:

//[ActivityStack.java]
    final boolean startPausingLocked(boolean userLeaving, 
    								boolean uiSleeping, //此时传递进来的参数为false
    								boolean resuming,//此时传递进来的参数为true
            						boolean dontWait) 
   {
    
    
        //判断当前的Stack栈中是否存在正在pausing的Activity
        if (mPausingActivity != null) {
    
    
            if (!mService.isSleepingLocked()) {
    
    
                completePauseLocked(false);
            }
        }
        
        //获取当前Stack栈中处于Resume状态的Activity,在我们当前的环境下就是Activity A了
        ActivityRecord prev = mResumedActivity;
        if (prev == null) {
    
    
            if (!resuming) {
    
    
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
            }
            return false;
        }

		...
		// 变更ActivityStack中pauseActivity的记录,此处是重点
        mResumedActivity = null;
        mPausingActivity = prev;
        mLastPausedActivity = prev;
        mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
        prev.state = ActivityState.PAUSING;
        prev.task.touchActiveTime();
        clearLaunchTime(prev);
        
		...
		 // 通知APP执行发起端的pause操作
        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);//详见章节1.3.1
            } catch (Exception e) {
    
    
                mPausingActivity = null;
                mLastPausedActivity = null;
                mLastNoHistoryActivity = null;
            }
        } else {
    
    
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null;
        }

		//获取锁,防止休眠
        if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
    
    
            mStackSupervisor.acquireLaunchWakelock();
        }

        if (mPausingActivity != null) {
    
    
            if (!uiSleeping) {
    
    
                prev.pauseKeyDispatchingLocked();
            } else if (DEBUG_PAUSE) {
    
    
            }

            if (dontWait) {
    
    
                completePauseLocked(false);
                return false;

            } else {
    
    
            	//这个是经典的ANR埋雷,监控APP是否pause超时,时间只有500ms
                Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
                msg.obj = prev;
                prev.pauseTime = SystemClock.uptimeMillis();
                mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
                return true;
            }

        } else {
    
    
			...
        }
    }

在正式开始上述的源码分析前,我们先来阐述一个重要的知识点,即在这个调用过程中涉及到两个进程,不妨令发起startActivity的发起进程记为进程Process_A,AMS Service所属进程记为进程Process_B;那么进程Process_A通过Binder机制(采用IActivityManager接口)向进程Process_B发起请求服务,进程Process_B则通过Binder机制(采用IApplicationThread接口)向进程Process_A发起请求服务。也就是说进程Process_A与进程Process_B能相互间主动发起请求,进而完成进程通信,但是这里有一点需要注意IApplicationThread的Binder实体端并没有注册到servicemanager进程中,它是一个依赖于实名Binder的匿名Binder。

这里涉及IApplicationThread很重要,它串联起了AMS对App进程的生命周期及其其它的控制,那么下面直接把其相关的类图展示如下:

在这里插入图片描述

这里的IApplicationThread与IActivityManager的Binder通信原理一样,ATP作为Binder通信的客户端,ATN作为Binder通信的服务端,其中ApplicationThread继承ATN类,覆写其中的部分方法。


并且在目标Activity A的进程创建的时候会存在如下的流程关系(这里小伙们可以先记住,后面再理解)

在这里插入图片描述

前面分析了一大堆主要想说明如下问题:

  • 这里的IApplicationThread和IActivityManager类似,是可以实现Binder跨进程通信的
  • 客户端进程可以通过AMP实现和AMS(system_server进程)的通信
  • AMS(system_server进程)可以通过ATP和客户端发起进程AT通信

如果小伙们对上述Binder跨进程调用不是很清晰的,可以参见系列博客Android Binder框架实现源码分析,这里就不过多讲述了,总之通过prev.app.thread.schedulePauseActivity实际上调用的就是ApplicationThread的schedulePauseActivity方法中去了,其调用过程可以使用下面的伪代码来表示:

ATP.schedulePauseActivity()---> 
BinderProxy.transact() --->
BpBinder.transact()--->
binder驱动传输--->
JavaBBinder.onTransact()--->
ATN.onTransact()--->
ATN.schedulePauseActivity()

1.3.1 AT.schedulePauseActivity处理Pause请求

  通过ATP的努力和我们的Binder框架的协助,我们跨越万水千山,完成了system_server所在进程到发起端所在目的端进程调用过程,让我们接着分析看看目的端进程是怎么处理schedulePauseActivity的RPC请求的。我好难啊!

//[ActivityThread.java]
    private class ApplicationThread extends ApplicationThreadNative {
    
    
        public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport) {
    
    
            int seq = getLifecycleSeq();
            sendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
                    configChanges,
                    seq);//详见1.3.2
        }    	
    }

巧用ActivityThread的主线程的Handler发送消息,这里我们可以总结一下规律,通常AMS通过ATP发送过来的消息,遵循如下的处理逻辑,如下

scheduleXXX() ---> handleXXX()

1.3.2 H.handleMessage

//ActivityThread.java
private class H extends Handler {
    
    
	public void handleMessage(Message msg) {
    
    
	    switch (msg.what) {
    
    
	        ...
                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);//详见章节1.3.3
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
	        ...
	    }
	}
}

1.3.3 AT.handlePauseActivity

//[ActivityThread.java]
    private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport, int seq) {
    
    
        //获取需要
        ActivityClientRecord r = mActivities.get(token);


        if (r != null) {
    
    

            if (userLeaving) {
    
    
                performUserLeavingActivity(r);
            }

            r.activity.mConfigChangeFlags |= configChanges;
            //执行Activity的onPause操作
            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");//详见章节1.3.4

  
            if (r.isPreHoneycomb()) {
    
    
                QueuedWork.waitToFinish();
            }


            if (!dontReport) {
    
    
                try {
    
    
                	//通知AMS已经Pause成功了
                    ActivityManagerNative.getDefault().activityPaused(token);//详见章节1.3.5
                } catch (RemoteException ex) {
    
    
                    throw ex.rethrowFromSystemServer();
                }
            }
            mSomeActivitiesChanged = true;
        }
    }

无需多言,直接进入下一关,打怪升级!

1.3.4 AT.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) {
    
    
		
		...
        performPauseActivityIfNeeded(r, reason);

		...

        return !r.activity.mFinished && saveState ? r.state : null;
    }

    private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
    
    
        if (r.paused) {
    
    
            // You are already paused silly...
            return;
        }

        try {
    
    
            r.activity.mCalled = false;
            mInstrumentation.callActivityOnPause(r.activity);
            EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
                    r.activity.getComponentName().getClassName(), reason);
            if (!r.activity.mCalled) {
    
    
				...
            }
        } catch (SuperNotCalledException e) {
    
    
            throw e;
        } catch (Exception e) {
    
    
			...
        }
        r.paused = true;
    }

  还是原来的配方,还是原来的味道,最终通过Instrumentation类回调了Activity实例的onPause方法,如下:

//[Instrumentation.java]
    public void callActivityOnPause(Activity activity) {
    
    
        activity.performPause();
    }

见证奇迹的时刻要到了,让我们拭目以待:

//[Activity.java]
    final void performPause() {
    
    
        mDoReportFullyDrawn = false;
        mFragments.dispatchPause();
        mCalled = false;
        onPause();//执行Activity的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;
    }

  尼玛,太不容易了,终于回调到了ASS中处于Resume状态的Activity的onPause方法,这其中涉及的弯弯绕绕可真多啊。网上有有博主说我们在启动一个Activity的时候最先被执行的是栈顶的Activity的onPause方法,我个人不是很赞同上述说法,应该是目标Activity所属Stack栈存在Resume状态的Activity时会执行其onPause方法,否则执行的就是其它Stack栈中的了。

1.3.5 AMS.activityPaused

  继续回到章节1.3.3未完成之实名,在将当前显示的Activity执行onPause之后,在该方法的最后面执行了ActivityManagerNative.getDefault().activityPaused(token);方法,这是应用进程告诉system_server服务进程,当前显示的Activity已经执行完成onPause方法了,通过前面我们的分析,我们知道这句话最终会被ActivityManagerService的activityPaused方法执行了!,其调用流程可以使用如下的伪代码来表述:

AMP.activityPaused(...)---> 
BinderProxy.transact(...) --->
BpBinder.transact(...)--->
binder驱动传输--->
JavaBBinder.onTransact(...)--->
AMN.onTransact(..)--->
AMN.activityPaused(...)
//[AMS.java]
    public final void activityPaused(IBinder token) {
    
    
        final long origId = Binder.clearCallingIdentity();
        synchronized(this) {
    
    
        	//获取已经pause的Activity所属Stack
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
    
    
                stack.activityPausedLocked(token, false);
            }
        }
        Binder.restoreCallingIdentity(origId);
    }

在activityPaused内部继续调用ActivityStack的activityPausedLocked方法进行下一步的处理,让我们接着分析:

    final void activityPausedLocked(IBinder token, boolean timeout) {
    
    
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
    
    
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            if (mPausingActivity == r) {
    
    
                completePauseLocked(true);//此处传入的参数为true
                return;
            } else {
    
    
					...
            }
        }
        mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
    }

接着继续分析completePauseLocked,注意此时传入的参数为true,我们继续分析:

    private void completePauseLocked(boolean resumeNext) {
    
    
        ActivityRecord prev = mPausingActivity;
		...
		        if (resumeNext) {
    
    
            final ActivityStack topStack = mStackSupervisor.getFocusedStack();
            if (!mService.isSleepingOrShuttingDownLocked()) {
    
    //会进入此分支,继续章节1.1.1的逻辑
                //此时的prev为前台显示已经pause的Activity
                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
            } else {
    
    
                mStackSupervisor.checkReadyForSleepLocked();
                ActivityRecord top = topStack.topRunningActivityLocked();
                if (top == null || (prev != null && top != prev)) {
    
    
                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                }
            }
        }
    	...
    }

经过了一系列的逻辑之后,又调用了resumeFocusedStackTopActivityLocked方法,又回到了章节1.1解析的方法中了,此时的传入的prev就是我们已经pause的Activity的了,而不是目标Activiyt了,现在章节1.2最后的谜题可以解决了。感觉resumeFocusedStackTopActivityLocked不是这么简单啊!

1.3.6 Pause前台显示的Activity小结

  虽然本人也反对分析源码过程中大量堆砌源码,但是有时候又不得不为之,因为如果不放上源码调用逻辑,整个流程下来就不是很清晰了,这个也木有办法,臣妾也不想啊!好吗,我们来总结一下Pause前台显示的Activity的流程,如果站在进程交互的角度出发,其中Pause前台显示的Activity牵涉到两次的跨进程调用:

  • AMS通过ATP通知前台Activity进行相关的onPause操作

  • 前台显示的Activity执行onPause成功之后通过AMP跨进程通知AMS已经成功执行

其中整个Pause前台显示的Activity的流程可以使用如下的伪代码流程来表示,如下:

//AMS端
ActivityStack.startPausingLocked(...)	--->
ATP.schedulePauseActivity(...)	---> 
BinderProxy.transact(...)	--->
BpBinder.transact(...)	--->

binder驱动传输	--->

//前台显示Activity端
JavaBBinder.onTransact(...)	--->
ATN.onTransact(...)	--->
ATN.schedulePauseActivity(...)	--->
ApplicationThread.schedulePauseActivity(...)	--->
ActivityThread.H.handleMessage(...)	--->
ActivityThread.handlePauseActivity(...)	--->
ActivityThread.performPauseActivity(...)	--->
ActiivtyThread.performPauseActivityIfNeeded(...)  --->
Instrumentation.callActivityOnPause(...)   --->
Activity.performPause(...)   --->
Activity.onPause(...)   --->
AMP.activityPaused(...)---> 
BinderProxy.transact(...) --->
BpBinder.transact(...)--->

binder驱动传输--->

//AMS端
JavaBBinder.onTransact(...)--->	
AMN.onTransact(..)--->
AMN.activityPaused(...)	

1.4 Resume目标Activity

  爱的魔力转圈圈,让我们继续第二轮回,重新开始源码的分析

//[ActivityStackSupervisor.java]
    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, 
            ActivityRecord target, //此时的target为前台已经处于pause状态的Activity,如果在我们当前的场景下即为Activity A
            ActivityOptions targetOptions) {
    
    
        if (targetStack != null && isFocusedStack(targetStack)) {
    
    
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
		...
    }

继续往下分析此时我想各位应该明白我们在章节1.2的疑问了


//[ActivityStack.java]

    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
    
    
		...
        boolean result = false;
        try {
    
    
			...
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
    
    
            mStackSupervisor.inResumeTopActivity = false;
        }
        return result;
    }

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    
    


        if (!mService.mBooting && !mService.mBooted) {
    
    
        	// 如果系统还未启动完毕,那AMS还不能正常工作,所以也不能显示Activity,主要是为防止没有开机启动完成
            return false;
        }
		//此处忽略
        ActivityRecord parent = mActivityContainer.mParentActivity;
		...

		// 当前AS中可能存在一些正处于Intializing状态的ActivityRecord,
	    // 如果这些ActivityRecord不是位于栈顶,而且正在执行窗口启动动画,
	    // 那么,就需要取消这些Activity的启动动画。
        mStackSupervisor.cancelInitializingActivities();


        /*
	        找到第一个没有finishing的栈顶activity,通常指向了要启动的Activity目标组件
	        此场景下prev和next不是同一个了,prev指向前面已经
        */
        final ActivityRecord next = topRunningActivityLocked();


        //这个变量是表示是否回调Activity中的onUserLeaveHint和onUserInteraction函数
        final boolean userLeaving = mStackSupervisor.mUserLeaving;
        mStackSupervisor.mUserLeaving = false;

        final TaskRecord prevTask = prev != null ? prev.task : null;
        if (next == null) {
    
    //这个表示如果当前ActivityStack不存在待启动的Activity,那么会启动Launcher桌面
            final String reason = "noMoreActivities";
            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack()
                    ? HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();

			// 当前AS不是全屏显示,则需要将焦点切换到下一个待显示的AS
            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(returnTaskType, reason)) {
    
    
                return mStackSupervisor.resumeFocusedStackTopActivityLocked(
                        mStackSupervisor.getFocusedStack(), prev, null);
            }

            
            ActivityOptions.abort(options);

			// 默认情况下,Stack都是占据全屏的,所以,当前Stack如果没有要显示的Activity,则会要求显示桌面
            return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
        }

        next.delayedResume = false;


        //检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
        //并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件
        if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                    mStackSupervisor.allResumedActivitiesComplete()) {
    
    
             //当前正在显示的Activity正好就是下一个待显示的Activity,
            // 那么,就中断对目标ActivityRecord的调度
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            return false;
        }

        final TaskRecord nextTask = next.task;
         /*这个是对上一个resumed的Activity的相关处理
		 * 由于我们是第一次启动B Activity,所以不可能处于finish跳过此处
		 */
        if (prevTask != null && prevTask.stack == this &&
                prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
    
    
			...
        }

        // 系统进入休眠状态,当前Stack的栈顶Activity已经处于Paused状态
        // 那么,中断待显示Activity的相关调度(有点拗口,学习源码就是这么枯燥的事情)
        if (mService.isSleepingOrShuttingDownLocked()
                && mLastPausedActivity == next
                && mStackSupervisor.allPausedActivitiesComplete()) {
    
    
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            return false;
        }

		...

		/*
			在ASS中存在很多的数据结构,用来统一管理ActivityRecord的状态
	    	譬如mStoppingActivities记录了当前所有处于Stopping状态的ActivityRecord
	    	mGoingToSleepActivities记录了当前所有要进入休眠状态的ActivityRecord
	    	在某些场景下,待显示的ActivityRecord可能处于这些数组中,但需要从中剔除
		*/
        mStackSupervisor.mStoppingActivities.remove(next);
        mStackSupervisor.mGoingToSleepActivities.remove(next);
        next.sleeping = false;
        mStackSupervisor.mWaitingVisibleActivities.remove(next);

        

         // 如果当前ASS中还有ActivityRecord不是处于PAUSED, STOPPED或STOPPING这三个状态之一,
    	// 那么,需要先等这些ActivityRecord进入停止状态
        if (!mStackSupervisor.allPausedActivitiesComplete()) {
    
    
            return false;
        }

  分析至此,让我们先缓缓,停下前进的脚步看看我们来时的路!前面的代码片段,主要是做一些初始化和可能的"异常"处理工作。虽然我们待显示的目标ActivityRecord已经位于栈顶,但要真正将其显示到前台来,即执行目标Activity的onCreate/onStart/onResume等状态,这一路有很多障碍和初始化工作还处理,或者说还有很多前提条件需要满足,譬如,系统要休眠时,当前启动目标Activity过程要中断;当前ASS中有Activity正处于Pausing状态时,也需要等相关Activity执行完毕才行。我们可以将上述的相关工作认为是准备阶段!前路漫漫是征途,我将上下而求索!

//[ActivityStack.java]
		/*
			setLaunchSource设置待启动的Activity的信息
			跟进setLaunchSource源码发现它最终会获取一个WakeLock,保证在显示Activity的过程中,系统不会进行休眠状态
		*/
        mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
        

         /*
           目标Activity的启动参数中是否包含FLAG_RESUME_WHILE_PAUSING
   		   如果存在FLAG_RESUME_WHILE_PAUSING的flag,表示可以在当前显示的发起端Activity执行Pausing时,
   		   能同时进行Resume操作
    	   即变量dontWaitForPause的取意就是不需要等到Activity执行Pause完毕
    	*/
        final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;


		/* 
		  这个是pause掉不是FocusedStack的其它ActivityStack的栈顶activity
 		  对于不是当前focusStack的并且存在有mResumedActivity不为null的都要paused
 		  此时下没有需要要进行pause
 		*/
		boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);

		//此时要带入真是场景了,此时的mResumedActivity表示目标Stack栈中处于Resume状态的Activity,通过前面的分析可以此时没有处于Resume状态的Activty了,所以不会走入此分支
		if (mResumedActivity != null) {
    
    
			....
        }
        if (pausing) {
    
    //也不会进入此分支可以往后续分析了
            if (next.app != null && next.app.thread != null) {
    
    
                mService.updateLruProcessLocked(next.app, true, null);
            }
            return true;
        }
         //检查要启动的Activity 组件是否等于当前被激活的 Activity 组件,如果等于
        //并且处于 RESUMED 状态,直接返回,我们前面演示的启动情况很显然不满足条件 
        else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                mStackSupervisor.allResumedActivitiesComplete()) {
    
    
            mWindowManager.executeAppTransition();
            mNoAnimActivities.clear();
            ActivityOptions.abort(options);
            return true;
        }

  在前面章节1.3的最后我们知道当前台Activity被执行pause以后,会回调activityPaused通知AMS,然后AMS会执行completePauseLocked。该函数也会调用resumeTopActivityInnerLocked。这一次,由于所有resumedActivity都已经paused了,所以返回的结果pausing为false,所以可以继续进行目标activity的resume工作。让我们对相关的流程继续分析!

//[ActivityStack.java]
		//对已经Pause的Activity继续处理,主要是通知WMS做进一步的处理
        if (prev != null && prev != next) {
    
    
            if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                    && next != null && !next.nowVisible) {
    
    
                mStackSupervisor.mWaitingVisibleActivities.add(prev);
            } else {
    
    
                if (prev.finishing) {
    
    
                    mWindowManager.setAppVisibility(prev.appToken, false);
                } else {
    
    
                }
            }
        }


        try {
    
    
        	 // 通过PackageManager修改待启动Package的状态
            AppGlobals.getPackageManager().setPackageStoppedState(
                    next.packageName, false, next.userId); /* TODO: Verify if correct userid */
        } catch (RemoteException e1) {
    
    
        } catch (IllegalArgumentException e) {
    
    
        }

		...

        ActivityStack lastStack = mStackSupervisor.getLastStack();
		
        if (next.app != null && next.app.thread != null) {
    
    //如果目的端进程已经创建,即要启动的目标Activity所属进程已经存在
			...
            next.state = ActivityState.RESUMED;
            mResumedActivity = next;
            next.task.touchActiveTime();
            mRecentTasks.addLocked(next.task);
            mService.updateLruProcessLocked(next.app, true, null);
            updateLRUListLocked(next);
            mService.updateOomAdjLocked();
			...
            try {
    
    
			
				...

                next.sleeping = false;
                mService.showUnsupportedZoomDialogIfNeededLocked(next);
                mService.showAskCompatModeDialogLocked(next);
                next.app.pendingUiClean = true;
                next.app.forceProcessStateUpTo(mService.mTopProcessState);
                next.clearOptionsLocked();
				//执行目的端Activity的scheduleResumeActivity操作
                next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                        mService.isNextTransitionForward(), resumeAnimOptions);
				...
            } catch (Exception e) {
    
    
				...
            }

            try {
    
    
                completeResumeLocked(next);
            } catch (Exception e) {
    
    
				//处理异常
                requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
                        "resume-exception", true);
                return true;
            }
        } else {
    
    //当目标Activity所属进程没有启动的时候,则会创建进程

            if (!next.hasBeenLaunched) {
    
    
                next.hasBeenLaunched = true;
            } else {
    
    
                if (SHOW_APP_STARTING_PREVIEW) {
    
    
                    next.showStartingWindow(null, true);
                }
            }
			
			//创建目标Activity进程
            mStackSupervisor.startSpecificActivityLocked(next, true, true);

			
        }


        return true;
    }

  到这里终于快要告一段落了,此处的逻辑主要分为两个分支:

  • 如果要启动的目标Activity所属进程已经创建,则直接通过ATP调用目标进程的ActivityThread执行相关的Activity的onCreate等相关生命周期
  • 如果目标Activity所属进程没有创建,则通过startSpecificActivityLocked方法创建目标进程,经过层层调用最后会调用到AMS.attachApplicationLocked, 然后再执行resumeTopActivityInnerLocked继续resume操作这个逻辑我想也是小伙们最关心的, 我们后续从这个地方开撸

1.5 Pause前台显示Activity,Resume目标Activity小结

  Pause前台显示Activity,Resume目标Activity到这里就基本完结了,是时候停下前进的脚步回过头来看看了!在上述过程中我们会进行两次resumeTopActivityInnerLocked方法:

  • 第一次是将所有resumedActivity进行pause,此时流程不会继续往下进行而是待前台显示的Activity真正执行pause后,然后回调AMS继续第二执行resumeTopActivityInnerLocked相关操作
  • 由于此时所有处于Resume状态的Activity已经都被Pause了,所以继续往下执行,此时会判断目标Activity所属进程是否创建,如果创建则直接执行目标Activity的生命周期,如果没有创建则会创建目标Activity所属进程,进而再执行下一步操作

对于上述的整个流程,可以使用下述的图示来表达:

在这里插入图片描述

其中红色箭头表示Binder跨进程调用
黄色框表示的是发起端进程
紫色框表示的是AMS所属system_server进程
红色框表示的是目标Activity所属进程
蓝色框表示的前台处于Resume的Activity所属进程


总结

  Activity启动流程(四)- Pause前台显示Activity,Resume目标Activity这里就要告一段落了,从前面的分析可以看出来,此时我们已将将需要Pause前台Activity已经Pause,接下来就是专心的来Resume目标Activity了,如果此时是冷启动的目标Activity那么就会先期进行目标Activity目标所属进程的创建,然后接着继续Resume目标Activity,如果是热启动就简单一些了直接执行目标Activity相关的onCretate等相关的操作。好了今天就到这里了,是时候说再见了!希望小伙们能点赞和关注,谢谢!

猜你喜欢

转载自blog.csdn.net/tkwxty/article/details/108850530
今日推荐