Android-Activity生命周期

文章参考:添加链接描述
文章参考:添加链接描述

五大状态

  • Starting
  • Running
  • Stopped
  • Paused
  • Destroyed
    借用一张已经包浆的图
    在这里插入图片描述
    PS:Running和Paused是可视阶段,其余都是不可视

几大函数

在这里插入图片描述

  • onCreate:通过setContentLayout初始化布局
  • onStart:此时activity可见,但没有获得焦点,无法交互,正做动画的初始化
  • onResume:获得焦点,可交互
  • onPause:如弹窗,有activity覆盖当前activity,失去焦点,但可见
  • onStop:activity不可见,系统内存紧张时会回收
  • onDestroy:结束activity

进程优先级

前台进程>可见进程>service进程>后台进程>空进程

前台进程

用户当前在做的事所必须的进程,符合其一则为

  • 进程的activity正在与用户进行交互
  • 进程持有一个service,且此service与正在交互的activity绑定/通过startForeground()在前台运行/正在进行其生命周期回调函数
  • 进程持有一个正在进行onReceive()的BroadcostReceiver

可见进程

不持有任何前台组件,但仍可见

  • 进程持有activity,此activity不在前台,处于onPause
  • 进程持有的service与可见的activtiy进行绑定

服务进程

没有和用户可见的组件绑定,所做的事情也是用户关心的,如后台下载、播放音乐的,除非内存不足,不然不会取消
当进程运行着一个startService开启的的service,且不属于前台和可见进程

后台进程

持有不可见activity,onStop调用,但没有调用onDestroy,系统会为了前三种进程任意杀死后台进程

空进程

不包含任何活跃的应用组件,则被认为是空进程
没有任何运行数据且还在内存空间,容易被杀死

启动流程

此处针对Activity A通过button点击启动位于不同进程的Activity B进行分析
在这里插入图片描述

概念梳理

  • init进程:init是所有linux程序的起点,是Zygote的父进程。解析init.rc孵化出Zygote进程。Android是基于linux系统的,手机开机之后,linux内核进行加载。加载完成之后会启动init进程。init进程会启动ServiceManager,孵化一些守护进程,并解析init.rc孵化Zygote进程
  • Zygote进程:Zygote是所有Java进程的父进程,所有的App进程都是由Zygote进程fork生成的。所有的App进程都是由Zygote进程fork生成的,包括SystemServer进程。Zygote初始化后,会注册一个等待接受消息的socket,OS层会采用socket进行IPC通信。每个应用程序都是运行在各自的Dalvik虚拟机中,应用程序每次运行都要重新初始化和启动虚拟机,这个过程会耗费很长时间。Zygote会把已经运行的虚拟机的代码和内存信息共享,起到一个预加载资源和类的作用,从而缩短启动时间。
  • SystemServer进程:System Server是Zygote孵化的第一个进程。SystemServer负责启动和管理整个Java framework,包含AMS,PMS等服务。
  • Launcher:Zygote进程孵化的第一个App进程是Launcher。
  • 进程:Android系统为每个APP分配至少一个进程
  • IPC:跨进程通信,Android中采用Binder机制。
  • ActivityStack:Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。
  • ActivitySupervisor:管理 activity 任务栈
  • ActivityThread:ActivityThread 运行在UI线程(主线程),App的真正入口。
  • ApplicationThread:用来实现AMS和ActivityThread之间的交互。
  • ApplicationThreadProxy:ApplicationThread 在服务端的代理。AMS就是通过该代理ActivityThread进行通信的。
  • IActivityManager:继承与IInterface接口,抽象出跨进程通信需要实现的功能
  • AMN:运行在server端(SystemServer进程)。实现了Binder类,具体功能由子类AMS实现。
  • AMS:AMN的子类,负责管理四大组件和进程,包括生命周期和状态切换。AMS因为要和ui交互,所以极其复杂,涉及window。
  • AMP:AMS的client端代理(app进程)。了解Binder知识可以比较容易理解server端的stub和client端的proxy。AMP和AMS通过Binder通信。
  • Instrumentation:仪表盘,负责调用Activity和Application生命周期,负责监控系统与应用之间的交互。测试用到这个类比较多。
  • ActivityStackSupervisor负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。
  • mHomeStack管理的是Launcher相关的Activity栈
  • mFocusedStack管理的是当前显示在前台Activity的Activity栈
  • mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈

省流四步

  • A告诉AMS准备启动B
  • AMS处理请求,通知A进行Pause,A处理完后,通知AMS 自己已经完成Pause了
  • B的进程还没启动,AMS首先启动一个新的进程,新进程启动完后通知AMS服务进程启动完毕
  • AMS通知新进程启动B,B启动完毕后通知AMS服务启动完毕

AMS和应用进程间通信涉及进程间通信,与Binder有关

当创建了一个新的应用进程后,系统首先会启动ActivityThread,ActivityThread是应用进程的主线程,ActivityThread创建时会创建一个ApplicationThread对象,ApplicationThread实现了一个Binder服务端

新进程创建完时会通知AMS,同时会将ApplicationThread的代理端交付,因此AMS保存了所有应用进程的ApplicationThread的代理对象,用于给应用进程发送消息

Activity.startActivity

此处button点击函调用了该函数

public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
             //intent描述B,-1表示不返回结果
              startActivityForResult(intent, -1, options);
              ……
}

Activity. startActivityForResult

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

应用程序和系统间的交互都集中交给Instrumentation来做,便于监视活动
mMainThread.getApplicationThread()是前面提到的Binder对象,实现了Binder服务端,AMS保留其client用于通信
mToken则是binder代理对象,指向AMS中保存的一个ActivityRecord信息,mToken代表了A,AMS依据其得到A的信息

Instrumentation. execStartActivity

public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
     ApplicationThread whoThread = (IApplicationThread) contextThread;
      try {
        //intent做进程间传输的准备工作
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        //进程间传输,终于调用到AMS服务中
        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);
    }
  ……
}

通过ActivityManagerNative.getDefault().startActivity()调用AMS的startActivity方法

至此都是在A的进程完成的,需要进入SystemServer中

这里调用了startActivity来启动Activity(最常用的函数),里面调用startActivityForResult,但给出的请求码是-1,即不返回数据
startActivityForResult调用了Instrumentation的execStartActivity,并传入ApplicationThread给AMS作为通信的binder对象,也传入mToken作为指向A的ActivityRecord给AMS

AMS.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());
}

caller就是App1进程的ApplicationThread的binder对象,
IBinder就是指向Activity A的ActivityRecord的Binder对象,前面提到的通信和获取活动信息所需
紧接着这种方法就调用了startActivityAsUser方法

AMS. startActivityAsUser

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) {
        ……
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
        profilerInfo, null, null, options, false, userId, null, null);
}

调用了activityStackSupervisor的startActivityMayWait方法
ActivityStackSupervisor是Activity调度的核心类
Activity的调度相关的工作都是在ActivityStackSuperVisor中处理
主要管理Task和Stack.它是在AMS启动的时候创建的。

startActivityMayWait

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, boolean ignoreTargetSecurity, int userId,
IActivityContainer iContainer, TaskRecord inTask) {
   ……
  //PMS服务依据intent查询要启动的Activity B的信息,保存到ActivityInfo中
  intent = new Intent(intent);
  ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
  //决定当前活动的stack
  ActivityContainer container = (ActivityContainer)iContainer;
  final ActivityStack stack;
  if (container == null || container.mStack.isOnHomeDisplay()) {
    stack = mFocusedStack;
  } else {
    stack = container.mStack;
  }
   ……
   //将PMS中查询到的Activity B的信息当做參数
   int res = startActivityLocked(caller, intent, resolvedType, aInfo,voiceSession, voiceInteractor, resultTo, resultWho,requestCode, callingPid, callingUid, callingPackage,
                realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,componentSpecified, null, container, inTask);
      ……
}

resolveActivity调用PMS服务依据Intent信息查询B的具体信息
查询是否有对应的ActivityStack,若传递过来的container为空,则指定Stack为当前获得焦点的ActivityStack,即mFocusedStack

ActivityStack分为几种

  • Home Stack 为 Launcher所在的Stack,一些系统界面也在此Stack执行,SystemUI等
  • FullScreen Stack 全屏的Activity所在的Stack,最常用
  • Freeform模式的Activity所在Stack,即可以自由缩放,自由移动
  • Docked Stack,分屏模式
  • Pinned Stack 画中画

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 ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,ActivityContainer container, TaskRecord inTask) {
       //callerApp 代表调用方的应用进程。即App1的应用进程
    ProcessRecord callerApp = null;
    if (caller != null) {
	    //依据caller找到AMS中保存的App1的processRecord对象
        callerApp = mService.getRecordForAppLocked(caller);
        if (callerApp != null) {
		    //得到App1应用进程的pid和应用的uid
            callingPid = callerApp.pid;
            callingUid = callerApp.info.uid;
        }
		……
    }
    ……
	//即调用者的Activity组件
    ActivityRecord sourceRecord = null;
	//返回结果的Activity组件
    ActivityRecord resultRecord = null;
    if (resultTo != null) {
	    //依据resultTo Binder对象得到其指向的ActivityRecord,即Activity A的ActivityRecord信息
        sourceRecord = isInAnyStackLocked(resultTo);
        //普通情况下请求的Activity和要接收返回结果的Activity是同一个
        if (sourceRecord != null) {
            if (requestCode >= 0 && !sourceRecord.finishing) {
                resultRecord = sourceRecord;
            }
        }
    }
    final int launchFlags = intent.getFlags();
    ……
    //依据准备的信息,创建一个即将启动的ActivityRecord对象。即Activity B
    ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
            requestCode, componentSpecified, voiceSession != null, this, container, options);
    ……
    //将刚创建的目标Activity的ActivityRecord作为參数,继续调用startActivityUncheckedLocked方法来启动
    err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
            startFlags, true, options, inTask);
    ……
    return err;
}

依据传入的A的binder对象caller获得A的ActivityRecord信息,获取调用程序的pid和uid
加上ainfo创建一个ActivityRecord对象r,代表B
至此sourceRecord获取了A的组件消息,r获取了B的信息
最终调用startActivityUncheckedLocked启动B

startActivityUncheckedLocked

final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
boolean doResume, Bundle options, TaskRecord inTask) {
    //依据flag获取对应的启动模式。我们代码中没有设置启动模式,所以默认应该是标准模式。这三个变量都应该是false		
    final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
    final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
    final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
	……
	//即将要启动activity的 task
	ActivityStack targetStack;
	……
	//是否新建一个Task
	boolean newTask = false;
	……
	//获取Activity A的Task,然后赋值给B,即两个Activity位于同一个Task中
	 else if (sourceRecord != null) {
       //获取Activity A所在的Task
       final TaskRecord sourceTask = sourceRecord.task;
       //将A所在的ActivityStack作为B启动的Stack
       targetStack = sourceTask.stack;
       targetStack.moveToFront("sourceStackToFront");
       //获取ActivityStack中的 top Task是不是和当前的Task一致,假设不一致则将当前的Task移动到ActivityStack的顶端
       final TaskRecord topTask = targetStack.topTask();
       if (topTask != sourceTask) {
         targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,r.appTimeTracker, "sourceTaskToFront");
       }
      ……
      //将当前Activity Stack mLastPausedActivity设置为null
      targetStack.mLastPausedActivity = null;
      //调用startActivityLocked方法
      targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
}

这里处理了Activity四种启动模式,根据Intent中的flag标志来决定不同的启动模式和Activity在Task中的位置
此处的启动模式是默认的,因此A和B同放在一个Task里面

每个Activity都位于一个Task中,一个Task能够包括多个Activity,同一个Activity也可由多个实例

Task管理在于近期任务列表和Back栈,AMS和WMS内部有一个容器Stack,android多窗体管理建立在Stack上,一个Stack中多个Task,一个Task包括多个Activity

最后调用ActivityTask的startActivityLocked启动

ActivityStack . startActivityLocked

final void startActivityLocked(ActivityRecord r, boolean newTask,boolean doResume, boolean keepCurTransition, Bundle options) {
    //获取要启动的Task对象
   TaskRecord rTask = r.task;
   final int taskId = rTask.taskId;
   TaskRecord task = null;
   if (!newTask) {
        //遍历AMS中全部的Task,找到目标task,然后将即将要启动的Activity增加到Task的栈顶
        boolean startIt = true;
        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
            task = mTaskHistory.get(taskNdx);
            if (task.getTopActivity() == null) {
                // All activities in task are finishing.
                continue;
            }
            if (task == r.task) {
                
                if (!startIt) {
                    task.addActivityToTop(r);
                    r.putInHistory();
                    ……
	//传入的resume位true。然后调用resumeTopActivitiesLocked方法继续启动Activity			
    if (doResume) {
        mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
    }

遍历全部Task,找到目标Task,将即将要启动的Activity的ActivityRecord增加到栈顶

ActivityStackSuperVisor. resumeTopActivitiesLocked

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions) {
       //假设目标task是frontStack调用resumeTopActivityLocked
    if (isFrontStack(targetStack)) {
        result = targetStack.resumeTopActivityLocked(target, targetOptions);
    }
    //然后遍历找到时frontStack的task运行resumeTopActivityLocked
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        ……
            }
            if (isFrontStack(stack)) {
                stack.resumeTopActivityLocked(null);
            }
     ……

确认目标task是否为frontStack,若是则直接执行resumeTopActivityLocked,不是则遍历,找到对应的frontStack执行resumeTopActivityLocked

ActivityStack.resumeTopActivityLocked

直接有调用了resumeTopActivityInnerLocked方法

ActivityStack. resumeTopActivityInnerLocked

ActivityStack. resumeTopActivityInnerLocked private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
   ……
  //找到栈顶第一个不是处于finishing状态的ActicityRecord
  final ActivityRecord next = topRunningActivityLocked(null);
  ……
  //调用startPausingLocked方法来暂停上一个Activity
  if (mResumedActivity != null) {
    if (DEBUG_STATES) 
        Slog.d(TAG_STATES,"resumeTopActivityLocked: Pausing " + mResumedActivity);
    pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
}

topRunningActivityLocked找到当前栈顶不是处于fininshiing状态的第一个ActivityRecord
将B的ActivityRecord添加到当前Task的栈顶,即next
startPausingLocked暂停上一个Activity
ActivityStack有三个成员变量:mResumedActivity、mLastResumedActivity、mLastPausedActivity

  • mResumedActivity:栈中激活状态的activity
  • mLastResumedActivity:栈中上一次被暂停的activity
  • mLastPausedActivity:栈中正在被暂停的activity
    mResumedActivity != null表示A不为空,暂停A

总结 startActivity到Pause

Activity的startActivity方法启动目标Activity

Instrumentation的方法execStartActivity,方便Instrumentation对交互进行监測

以上部分是在App1的进程中运行。之后会通过进程间通信调用到AMS服务中调用AMS的startActivity方法。

此时进入SystemServer进程。

然后由AMS中管理Acticity核心调度的类ActivityStackSupervisor的方法startActivityMayWait来处理。该方法中主要是依据Intent从PMS中查询目标Activity的信息

ActivityStackSuperVisor的startActivityLocked方法主要是在AMS中找调用进程的processRecord信息,调用Activity的ActivityRecord信息。目标Activity还没有启动,所以须要先创建一个目标Activity的ActivityRecord信息。

ActivityStackSuperVisor的StartActivityUncheckedLocked方法主要来处理启动模式相关的逻辑,依据不同的启动模式,找到对应的对的ActivityStack,然后又对应的ActivityStack进行处理

ActivityStack将目标Activity增加到相应的Task栈顶

调用ActivityStackSuperVisor的resumeTopActivityLocked方法找到处于前台的Task。然后调用它的resumeTopActivityLocked方法激活目标Activity.

当前的Task的栈開始Pasuing调用的Activity

以上几个步骤完成AMS对调用Activity及目标Activity的信息收集处理
拿到启动进程的binder对象和A的activityRecord给AMS
通过ActivityStackSuperVisor拿到启动进程的信息
根据Intent拿到目标Activity的信息
依据启动模式来决定将目标Activity方法那个栈中。然后将目标栈当前处于激活状态的Activity Pause掉给目标Activity腾地方。

Activity Resume - Pause

ActivityStack.startPausingLocked

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,boolean dontWait) {
   //mResumeActivity代表当前激活的Activity。即Activity A
   ActivityRecord prev = mResumedActivity;
   ……
   //当前处于激活状态mResumedActivity 的设置为null
   mResumedActivity = null;
   //即将要处于pasuing状态的Activity 就是Activity A
   mPausingActivity = prev;
   mLastPausedActivity = prev;
   ……
   //将Activity A的状态设置为PAUSING
   prev.state = ActivityState.PAUSING;
   //找到当前的栈顶的topActivity就是 Activity B
   final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
   //调用进程不为null,且调用进程的ApplicationThread不为null
   if (prev.app != null && prev.app.thread != null) {
     try {
           ……
          //通过调用进程的ApplicationThread通知调用进程schedulePauseActivity方法
          prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,userLeaving, prev.configChangeFlags, dontWait);
          }

从mResumeActivity拿到A的ActivityRecord,赋值prev
并将其和B设为pause状态,因为B暂时未启动,未激活
prev.app代表A的ProcessRecord,prev.app.thread则为A所在进程的ApplicationThread
通过ApplicationThread可以得到进程的Binder client,使得AMS能够向应用进程发送消息
最终通过调用A的schedulePauseActivity,完成Pause

ApplicationThread. schedulePauseActivity

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

应用进程的ApplicationThread是ActivityThread的一个内部类,token是一个Binder类型的对象,指向了AMS中与A的ActivityRecord,根据finish决定是暂停结束还是暂停
这里发送了PAUSE_ACTIVITY的message给handler

……
handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,(msg.arg1&2) != 0);

ActivityThread.handPauseActivity

private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
     //调用Activity A的onPause方法
     performPauseActivity(token, finished, r.isPreHoneycomb());
        //等待pause状态的数据写入完毕.
        if (r.isPreHoneycomb()) {
            QueuedWork.waitToFinish();
        }
         ……
        try {
            //进程间通信。调用AMS的ActivityPause方法
            ActivityManagerNative.getDefault().activityPaused(token);
            } catch (RemoteException ex) {}

ActivityThread中的mActivites集合中保存了当前进程的所有Activity,每个Activity都用一个ActivityClientRecord表示,集合中以binder为key保存
AMS中的全部Activity也是在一个集合中存储,以ActivityRecord来表示,key值也是Binder对象

此处由token获取获取ActivityClientRecord
performPauseActivity调用了A的onSaveInstance,然后调用了onPause
因为onSaveInstance需要存储当前Activity的信息,进行I/O操作,所以需要QueuedWork.waitToFinish来等待存储完成
最后调用activityPaused,进入SystemServer进程

AMS.activityPaused

public final void activityPaused(IBinder token) {
   //获取Activity 所在的ActivityStack
   ActivityStack stack = ActivityRecord.getStackLocked(token);
  if (stack != null) {
    //调用目标ActivityStack的activityPauseLocked方法
     stack.activityPausedLocked(token, false);
    }
 }

Token代表的是Activity A ,此处依据token找到Activity A所在的ActivityStack,然后由目标Stack来处理activityPause逻辑

ActivityStack.activityPauseLocked

final void activityPausedLocked(IBinder token, boolean timeout) {
    //依据token获取Activity A的ActivityRecord对象
    final ActivityRecord r = isInStackLocked(token);
    if (r != null) {
    //移除pause超时消息
    mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
    if (mPausingActivity == r) {
    //调用completePauseLocked方法继续运行pause逻辑
    completePauseLocked(true);
}
……

当运行完pause逻辑的ActivityRecord和我们运行pause逻辑前的activityRecord一样的时候,即是同一个Activity。
就能够调用completePauseLocked方法来完毕Activity A Pause最后的逻辑了。

ActivityStack. completePauseLocked

if (resumeNext) {
  final ActivityStack topStack = mStackSupervisor.getFocusedStack();
  if (!mService.isSleepingOrShuttingDown()) {
     mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
  }
  ……
}

resumeNext就是completePauseLocked传进来的參数,为true。
调用mStackSupervisor的getFocusedStack()方法来获取正在处理的ActivityStack. mService.isSleepingOrShuttingDown。推断AMS服务是否处于正常激活状态
然后调用mStackSupervisor的resumeTopActivitiesLocked继续处理。

ActivityStackSuperVisor.resumeTopActivitiesLocked

假设当前的ActivityStack是frontStack。
直接调用ActivityStack的resumeTopActivityLocked。
ActivityStack的resumeTopActivityLocked方法则直接有调用了ActivityStack的resumeTopActivityInnerLocked方法。

ActivityStack. resumeTopActivityInnerLocked

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
 ……
    //找到栈顶的Activity,此时栈顶的acitvity就是即将要启动的Activity B
    final ActivityRecord next = topRunningActivityLocked(null);
         ……
    //我们知道,在前面Activity A变为pause状态的时候。我们就把mResumeActivity 置为了Null
	if (mResumedActivity != null) {
        if (DEBUG_STATES) Slog.d(TAG_STATES,
                "resumeTopActivityLocked: Pausing " + mResumedActivity);
        pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
    }
	……
	//即将要启动的Activity处于一个新的进程,眼下还没有启动
	if (next.app != null && next.app.thread != null) {
		……
	}else{
		……
		//来启动目标Activity
		mStackSupervisor.startSpecificActivityLocked(next, true, true);
	}

推断mResumeActivity不为空,说明当前有一个处于正在激活状态的Activity,须要先将原先的Activity变为pause状态。
当Activity A变为Pause状态后。再次走到这种方法来激活目标Activity,此时mResumeActivity已经为空,所以不须要再运行pause的逻辑。
然后推断目标Activity next的进程app和ApplicationThread是否为空,由于Activity A 所在的进程还没有创建,所以两个都为空,直接运行mStackSupervisor的startSpecificActivityLocked来启动新的Activity。

此阶段由ActivityStack.startPausingLocked开始,将A进行Pause,调用onRestoreinstance保存信息等,修改当前的ActivityStack的激活activity等信息,然后定位B的ActivityStack,暂停栈顶Activity,并启动新进程

启动新进程

ActivityStackSuperVisor. startSpecificActivityLocked

void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {
   //获取目标Activity的进程ProcessRecord
   ProcessRecord app = mService.getProcessRecordLocked(r.processName,r.info.applicationInfo.uid, true);
   ……
  //因为目标Activity所在进程还没有创建,所以为空
  if (app != null && app.thread != null) {
    ……
   }
    //
   mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false, false, true);
}

该方法比較简单,依据目标Activity的ProcessName来查找相应的ProcessRecord.
依据processRecord中的进程app和ApplicationThread来推断
假设这两个变量不为空,说明目标Activity的进程和执行环境已经具备
直接启动Activity就能够,我们知道眼下目标Activity的进程还没有启动,所以须要调用AMS先启动一个目标Activity的进程

AMS. startProcessLocked

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,……) {
    long startTime = SystemClock.elapsedRealtime();
    ProcessRecord app;
    if (!isolated) {
        app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
        String hostingNameStr = hostingName != null?hostingName.flattenToShortString()null
        ……
	    startProcessLocked(app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
	    ……
	}
	……
}

获得ProcessRecord,调用startProcessLocked

private final void startProcessLocked(ProcessRecord app, String hostingType,String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
		int uid = app.uid;
        int[] gids = null;
		……
		//從PMS服务中查找目标应用相应的权限组
		final IPackageManager pm = AppGlobals.getPackageManager();
        permGids = pm.getPackageGids(app.info.packageName, app.userId);
		……
		gids = new int[permGids.length + 2];
        System.arraycopy(permGids, 0, gids, 2, permGids.length);
		……
		app.gids = gids;
		……
		if (entryPoint == null) entryPoint = "android.app.ActivityThread";
		 //调用Process的静态方法启动一个新的进程 
	   Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);

这种方法做的主要工作就是调用Process的静态方法启动一个新的进程。
启动新的进程的过程大概是
Zygote进程会fork一个新的子进程出来,子进程创建完毕之后
classLoader载入ActivityThread类并创建一个ActivityThread实例
反射调用ActivityThread的main方法
这样ActivityThread主线程就在新的进程中启动起来了。
接着看ActivityThread的main方法,此时已经在新的进程中运行了。

ActivityThread.main

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

这种方法主要工作就是调用Looper.prepareMainLooper创建一个消息循环队列
然后调用Looper.loop进入消息循环,当前线程进入消息循环中
使当前线程成为新进程的主线程,然后创建一个ActivityThread对象。调用Attach方法。

ActivityThread.attach

final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
      ……
      final IActivityManager mgr = ActivityManagerNative.getDefault();
      try {
        mgr.attachApplication(mAppThread);
     } catch (RemoteException ex) {
       // Ignore
     }
     ……
   } else {
  }

初始系统进程的执行环境的时传入的參数system为true,表示是系统进程
而这次是普通的应用进程,所以參数system为false
ActivityManagerNative.getDefault()方法获取AMS的代理
调用attachApplication方法发送一个进程间通信的请求,将创建的ApplicationThread对象传递给AMS服务
ApplicationThread是一个ActivityThread本地binder对象,Binder的服务端在ActivityThread中,将Binder对象传递给AMS服务。则AMS服务中保存它的代理,AMS就获得了与新进程通信的方式。
此前的代码运行在新建的进程中。即应用App2所在的进程,然后通过进程间通信

AMS.attachApplication

      ApplicationInfo appInfo = app.instrumentationInfo != null? app.instrumentationInfo : app.info;		
        //进程间调用:调用新进程的bindApplication方法
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked());
         ……
        if (normalMode) {
           try {
		       //调用ActivityStackSupervisor的方法来启动新的Activity
               if (mStackSupervisor.attachApplicationLocked(app)) {
                   didSomething = true;
               }
           }
	     ……
   }

依据进程ID,查询相应进程的ProcessRecord,这个ProcessRecord是新进程的对象,指向新进程
从PMS中查询与新进程相关的ContentProvider的信息
这里的thread是新进程的ApplicationThread的binder,调用新进程的handlebindApplication来初始化执行环境,包含新进程Application的初始化、Instrumentation的初始化和安装相关的ContentProvider
最后调用ActivityStackSupervisor执行attachApplication

ActivityStackSuperVisor. attachApplicationLocked

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
  final String processName = app.processName;
  //遍历全部的stack,找到处于前台的ActivityStack
  for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
    ArrayList stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
    for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
    final ActivityStack stack = stacks.get(stackNdx);
    if (!isFrontStack(stack)) {
         continue;
    }
  //找到处于栈顶的ActivityRecord
   ActivityRecord hr = stack.topRunningActivityLocked(null);
  if (hr != null) {
     if (hr.app == null && app.uid == hr.info.applicationInfo.uid&& processName.equals(hr.processName)) {
       try {
          //调用realstartActivityLocked方法来启动目标Activity
          if (realStartActivityLocked(hr, app, true, true)) {
             didSomething = true;
          }
       } catch (RemoteException e) {
             ……
     }
}

遍历并找到目标stack,然后拿到这个ActivityStack栈顶的ActivityRecord,这就是目标Activity
之前放到栈顶的。得到要启动的Activity信息之后启动新的Activity

ActivityStackSuperVisor. realStartActivityLocked

final boolean realStartActivityLocked(ActivityRecord r,ProcessRecord app, boolean andResume, boolean checkConfig)throws RemoteException {
         ……
        //将新进程的信息保存到ActivityRecord的app变量中
        r.app = app;
		//获取目标Task
		final TaskRecord task = r.task;
		//找到Task对用的Stack
		final ActivityStack stack = task.stack;
		//跨进程调用,通知目标进程来启动Activity
		app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
}

将ActivityRecord的app对象指向了新的进程。这样ActivityRecord就和新的进程关联了起来。
然后通过目标进程ApplicationThread代理Binder对象发起进程间通信请求,调用目标进程的scheduleLaunchActivity方法来启动新的Activity

ApplicationThread. scheduleLaunchActivity

 public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,ActivityInfo info, Configuration curConfig,…… ProfilerInfo profilerInfo) {
        updateProcessState(procState, false);
		//依据进程间传递的消息,初始化ActivityClientRecord
        ActivityClientRecord r = new ActivityClientRecord();
        r.token = token;
        r.ident = ident;
		……
		//发送消息,终于有Handler来处理
        sendMessage(H.LAUNCH_ACTIVITY, r);
    }

调用到ActivityThread内部的ApplicationThread中
该ApplicationThread实现了ApplicationThreadNative,这样就实现了进程间通信的Binder服务端
发送消息,由Handler的HandMessage来处理
在handleMessage中又调用了ActivityThread的handleLaunchActivity来处理

ActivityThread.handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  //调用performLaunchActivity方法来启动Activity
  Activity a = performLaunchActivity(r, customIntent);
  //Activity启动完毕后。调用handlResumeActivity来使Activity进入resume激活状态
  if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed);
        }
}

首先调用performLaunchActivity来创建一个Activity对象,并调用Activity的onCreate方法完毕Activity启动
随后调用handleResumeActivity方法。激活Activity,时Activity计入resume状态

ActivityThread.performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    //获取Activity的packageInfo信息
   if (r.packageInfo == null) {
      r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,Context.CONTEXT_INCLUDE_CODE);
}
   //获取Activity的Component信息
   ComponentName component = r.intent.getComponent();
   if (component == null) {
     component = r.intent.resolveActivity(mInitialApplication.getPackageManager());r.intent.setComponent(component);
}
   if (r.activityInfo.targetActivity != null) {
     component = new ComponentName(r.activityInfo.packageName,r.activityInfo.targetActivity);
}
    //调用Instrumentation类来创建一个依据Activity的信息Activity对象
    Activity activity = null;
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    //创建完毕后,调用Activity的attach方法来初始化Activity
    if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (DEBUG_CONFIGURATION) 
                 Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);
            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);

     ……
    //调用Activity的onCreate方法
   mInstrumentation.callActivityOnCreate(activity, r.state);
   ……
   //运行Activity的onStart方法
   if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
   ……
   //调用Activity的onRestoreInstancestate方法
   if (r.state != null) {
              mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
   ……
  //调用Activity的onPostCreate方法
  mInstrumentation.callActivityOnPostCreate(activity, r.state);
   ……
  //把创建的相应的ActivityClientRecord以binder为键值,保存到mActivities中
  mActivities.put(r.token, r);

在新的进程中,依据AMS传递过来的信息创建了一个ActivityClientRecord对象。该对象和AMS服务中的一个ActivityRecord相应。

在这种方法中。依据目标Activity B的ActivityClientRecord,调用Instrumentation类来创建一个Acitivity,创建过程就是ClassLoader载入相应的Activity类,用反射方法创建一个对象。

创建完新的Activity对象后,即Activity B的对象,然后调用它的onCreate方法,这样Activity B的onCreate对象就会被调用,以便载入自定义的用户界面,以及其它的初始化方法。

onCreate方法调用完毕之后。
然后依次调用ActivityonStart,onRestoreInstanceState,onPostCreate方法等,这个就是Activity生命周期运行的逻辑。

创建新进程的总结:
通过Zygote创建新进程,在其main方法中创建消息队列和application。
创建Application传给AMS,查找目标Activity所在的stack,拿到位于栈顶的ActivtiyRecord,对新进程和ActivityRecord进行关联,通过发送消息调用ActivityThread调用handleLaunchActivity来调用performLaunchActivity完成activity的onCreate和activity的onResume

到此为止。ActivityB就启动完毕了,它启动起来之后,意味着ActivityB所在的应用程序也就启动起来了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/25880.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Markdown笔记应用程序Note Mark

什么是 Note Mark Note Mark 是一种轻量、快速、简约,基于网络的 Markdown 笔记应用程序。具有时尚且响应迅速的网络用户界面。 安装 在群晖上以 Docker 方式安装。 ghcr.io 镜像下载 官方的镜像没有发布在 docker hub,而是在 ghcr.io,所以…

iptables和防火墙

文章目录 1.防火墙2.Iptables基本介绍2.1 什么是iptables2.2 什么是包过滤防火墙2.3 包过滤防火墙如何实现 1.防火墙 Linux防火墙主要工作在网络层,针对 TCP/IP 数据包实施过滤和限制,典型的包过滤防火墙,基于内核编码实现,具有非…

什么是低代码开发?低代码开发可以解决哪些问题?

一、什么是低代码开发? 低代码可以理解为是一种全新的应用开发理念。主要以可视化、参数化的系统配置方式来进行程序应用的开发,因此可以大幅度减少代码编写的工作,从而提高开发效率。 低代码平台则是通过对于业务场景进行高度抽象、提炼&…

unittest单元测试框架

背景 unittest也称为PyUnit,是借鉴Java中JUnit框架产生。 unittest使我们具备创建测试用例、测试套件、测试夹具的能力。 组成 Test Fixture(测试夹具):可以定义在单个或多个测试执行之前的准备工作和测试执行之后的清理工作。…

【P42】JMeter 运行时间控制器(Runtime Controller)

文章目录 一、运行时间控制器(Runtime Controller)参数说明二、测试计划设计 一、运行时间控制器(Runtime Controller)参数说明 可以通过时间来确定其后代元素运行多长时间,在时间范围内,后代元素会一直运…

八、(重点)视图集ModelViewSet自定义action路由routers

上一章: 七、Django DRF框架GenericAPIView--搜索&排序&分页&返回值_做测试的喵酱的博客-CSDN博客 下一章: 九、DRF生成API文档_做测试的喵酱的博客-CSDN博客 1、View 最基础的视图类View 2、views.APIView class APIView(View): …

kafka 的内部结构和 kafka 的工作原理

基本设置 让我们开始安装kafka。下载最新的 Kafka 版本并解压缩。打开终端并启动 kafka 和 zookeeper。 $ cd $HOME $ tar -xzf kafka_<version>.tgz $ cd kafka_<version> $ bin/zookeeper-server-start.sh config/zookeeper.properties # open another termina…

Canvas画布基本功能及实现网页签名功能

canvas 简介 <canvas> 是 HTML5 新增的&#xff0c;一个可以使用脚本(通常为 JavaScript) 在其中绘制图像的 HTML 元素。它可以用来制作照片集或者制作简单(也不是那么简单)的动画&#xff0c;甚至可以进行实时视频处理和渲染。和所有 DOM 元素一样&#xff0c;拥有自己…

Elasticsearch:数据是如何被写入的?

在我之前的文章 “Elasticsearch&#xff1a;索引数据是如何完成的”&#xff0c;我详述了如何索引 Elasticsearch 的数据的。在今天的文章中&#xff0c;我将从另外一个视角来诠释如何写入数据到 Elasticsearch。更多关于 Elasticsearch 数据操作&#xff0c;请阅读文章 “Ela…

实体店引流获客系统模式开发详解

随着互联网的日益发展&#xff0c;实体店的处境变得越来越艰难&#xff0c;获客难和销量差成为了实体店最头疼的两大问题。面对这种情况&#xff0c;一味固步自封是不行的&#xff0c;最好还是顺应潮流&#xff0c;结合一款合适的商业模式&#xff0c;来帮助自己快速引流获客和…

深入理解设计原则之接口隔离原则(ISP)【软件架构设计】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 深入理解设计模式系列 高级C并发线程编程 LSP&#xff1a;接口隔离原则 系列文章目录1、接口隔离原则的定义和解读2、案例解读3、如何判断一个接口是否符合接口隔离原则&#xff1f;小结 1、接口隔离原则的定义和…

canal server 标准化集群搭建(完结)

4.2. 创建 server 所属集群&#xff1a;选择刚才添加的 “集群名称” server 名称&#xff1a; server_1、server_2、server_3 依次类推 server ip&#xff1a;server 的 ip 地址 admin 端口&#xff1a;canal server 与 canal admin 的通信端口&#xff0c;非生产环境从 2…

云南LED、LCD显示屏系统建设,户外、室内广告大屏建设方案

LED大屏幕显示系统是LED高清晰数字显示技术、显示单元无缝拼接技术、多屏图像处理技术、信号切换技术、网络技术等科技手段的应用综合为一体&#xff0c;形成一个拥有高亮度、高清晰度、技术先进、功能强大、使用方便的大屏幕投影显示系统。通过大屏幕显示系统&#xff0c;可以…

3.1 矩阵连乘问题

博主简介&#xff1a;一个爱打游戏的计算机专业学生博主主页&#xff1a; 夏驰和徐策所属专栏&#xff1a;算法设计与分析 学习目标&#xff1a; 如果我要学习动态规划中的矩阵连乘问题&#xff0c;我会采取以下学习方法&#xff1a; 1. **理解问题的背景和目标&#xff1a;首…

【MySQL】如何速通MySQL(2)

&#x1f4cc;前言&#xff1a;本篇博客介绍如何速通MySQL的第二篇&#xff0c;主要介绍Mysql中主要的基础的入门&#xff0c;学习MySQL之前要先安装好MySQL&#xff0c;如果还没有安装的小伙伴可以看看博主前面的博客&#xff0c;里面有详细的安装教程。或者看一下下面这个链接…

SpringMVC第七阶段:SpringMVC的增删改查(01)

SpringMVC的增删改查 1、准备单表的数据库 drop database if exists springmvc;create database springmvc;use springmvc; ##创建图书表 create table t_book(id int(11) primary key auto_increment, ## 主键name varchar(50) not null, ## 书名 author varchar(50) no…

解决高并发

目录 1.4 对比单体系统、分布式系统和微服务系统 1.4.1 单体系统之痛 1、什么是单体系统 2、单体系统面临的问题 1.4.2 高并发系统之分布式架构 1.4.3 高并发系统之微服务架构 1.4 对比单体系统、分布式系统和微服务系统 接下来从企业真实场景出发&#xff0c;对比单体系统…

JavaEE进阶(5/29)SpringMVC

目录 1.复习 2.URL传参PathVariable 3.上传文件RequestPart 4.获取Cookie/Session/header 5.传统/维新获取cookies 6.传统/维信获得Header 7.获取Session&#xff08;非常重要&#xff09; 8.不加ResponseBody 9.如何获取Json数据&#xff0c;RequestBody 10.想…

python:容器:字符串——常用操作

字符串[下标]根据下标索引取出特定位置字符字符串.index(字符串)查找给定字符的第一个匹配项的下标字符串.replace(字符串1,字符串2) 将字符串内的全部字符串1&#xff0c;替换为字符串2 不会修改原字符串&#xff0c;而是得到一个新的 字符串.split(字符串) 按照给定字符串&am…

数据偏度介绍和处理方法

偏度&#xff08;skewness&#xff09;是用来衡量概率分布或数据集中不对称程度的统计量。它描述了数据分布的尾部&#xff08;tail&#xff09;在平均值的哪一侧更重或更长。偏度可以帮助我们了解数据的偏斜性质&#xff0c;即数据相对于平均值的分布情况。 有时&#xff0c;正…