原文地址:http://blog.csdn.net/windskier/article/details/7096521

      终于下定决心写写ActivityManagerService的源码分析的文章了,ActivityManagerService 业务的整个逻辑关系被各种复杂的数据结构包裹着,因此对ActivityManagerService 的分析主要就是对各种数据结构的分析,明白了这些数据结构,理解ActivityManagerService的业务内容就水到渠成了。

    AMS提供了一个ArrayList mHistory来管理所有的activity,activity在AMS中的形式是ActivityRecord,task在AMS中的形式为TaskRecord,进程在AMS中的管理形式为ProcessRecord。如下图所示

    

    从图中我们可以看出如下几点规则:

    1. 所有的ActivityRecord会被存储在mHistory管理;

    2. 每个ActivityRecord会对应到一个TaskRecord,并且有着相同TaskRecord的ActivityRecord在mHistory中会处在连续的位置;

    3. 同一个TaskRecord的Activity可能分别处于不同的进程中,每个Activity所处的进程跟task没有关系;

    因此,在分析Activity管理之前,先了解一下这个规则。


1. Activity 启动

    这篇文章关于整个Activity的启动过程,侧重于分析相关数据结构的构建与管理,以达到理解整个AMS对Activity的管理。

1.1 获得要启动的activity信息

        final int startActivityMayWait(IApplicationThread caller,
            Intent intent, String resolvedType, Uri[] grantedUriPermissions,
            int grantedMode, IBinder resultTo,
            String resultWho, int requestCode, boolean onlyIfNeeded,
            boolean debug, WaitResult outResult, Configuration config)方法中。

    我们知道,android中是通过Intent来启动一个新的activity的,因此AMS在得到请求启动activity时,首先需要根据Intent从PM中获得要启动的activity,PM通过parse 每个application的AndroidManifest.xml来获得所有的activity信息,针对每个Intent提供的信息,PM会提供给AMS一个ResolveInfo对象。

    

startActivityMayWait()@ActivityManagerService.java

[java]  view plain copy
  1. // Don't modify the client's object!  
  2.  intent = new Intent(intent);  
  3.   
  4.  // Collect information about the target of the Intent.  
  5.  ActivityInfo aInfo;  
  6.  try {  
  7.      ResolveInfo rInfo =  
  8.          AppGlobals.getPackageManager().resolveIntent(  
  9.                  intent, resolvedType,  
  10.                  PackageManager.MATCH_DEFAULT_ONLY  
  11.                  | ActivityManagerService.STOCK_PM_FLAGS);  
  12.      aInfo = rInfo != null ? rInfo.activityInfo : null;  
  13.  } catch (RemoteException e) {  
  14.      aInfo = null;  
  15.  }  
  16.   
  17.  if (aInfo != null) {  
  18.      // Store the found target back into the intent, because now that  
  19.      // we have it we never want to do this again.  For example, if the  
  20.      // user navigates back to this point in the history, we should  
  21.      // always restart the exact same activity.  
  22.      intent.setComponent(new ComponentName(  
  23.              aInfo.applicationInfo.packageName, aInfo.name));  
  24.   
  25.      // Don't debug things in the system process  
  26.      if (debug) {  
  27.          if (!aInfo.processName.equals("system")) {  
  28.              mService.setDebugApp(aInfo.processName, truefalse);  
  29.          }  
  30.      }  
  31.  }  

    通过这个过程,AMS就知道了要启动那个activity。在找到要启动的activity信息之后,需要将这个activity信息记录到Intent中。

1.2 创建ActivityRecord

    final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType,
            Uri[] grantedUriPermissions,
            int grantedMode, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, boolean onlyIfNeeded,
            boolean componentSpecified) 

    这一函数主要为了创建对应activity的ActivityRecord,这里先简单的对startActivityLocked方法的几个关键的参数根据代码做一个解释。

    1. IApplicationThread caller :请求启动当前Activity的应用方,IApplicationThread 类型是AMS IPC调用ActivityThread的IBinder接口;

    

    2. IBinder resultTo: 调用方Activity的ActivityRecord,每个Activity在启动之后,AMS均会将这个Activity的ActivityRecord的IBinder再传递给Activity,作为其在AMS中的标识。因此此时的resultTo经过2次IPC传递之后,已经不再是接口了,回到AMS之后就会再次变为ActivityRecord。

   3. callingPid和callingUid: 如果caller为空,其为请求启动Activity的进程的PID和UID;caller不为空,为caller activity所在的进程的PID和UID,基本上是一码事。这个PID和UID为了权限检查用的,检查当前的请求方是否有权限启动这个Activity。


    startActivityLocked()方法在创建ActivityRecord前,还做了如下几不操作:

    1. 确定sourceRecord和resultRecord,这两个变量均为ActivityRecord类型,前者代表请求启动当前activity的activity;后者表示当前的activity在启动之后需要返回结果的ActivityRecord,一般情况下,如果sourceRecord的activity使用startActivityForResult()启动当前activity并且requestCode>=0时,则resultRecord不为空,且resultRecord=sourceRecord。

    

   还有一种特殊的情况,当启动一个activity时,启动的Intent设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT标志,在这种情况resultRecord并不指向sourceRecord,而是指向sourceRecord的sourceRecord,比较绕上个图先

    

   如上图所示,Activity A 启动了Activity B,Activity B又启动了C,A-->B-->C, 这种情况下,A启动B要求B返回result给A,但是如果B在启动C时,Intent设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT标志,那么此时将会交由C向A setResult。为了避免冲突,B启动C时不得指定resultRecord>=0。

[java]  view plain copy
  1. ActivityRecord sourceRecord = null;  
  2. ActivityRecord resultRecord = null;  
  3. if (resultTo != null) {  
  4.     int index = indexOfTokenLocked(resultTo);  
  5.     if (DEBUG_RESULTS) Slog.v(  
  6.         TAG, "Sending result to " + resultTo + " (index " + index + ")");  
  7.     if (index >= 0) {  
  8.         sourceRecord = (ActivityRecord)mHistory.get(index);  
  9.         if (requestCode >= 0 && !sourceRecord.finishing) {  
  10.             resultRecord = sourceRecord;  
  11.         }  
  12.     }  
  13. }  
  14.   
  15. int launchFlags = intent.getFlags();  
  16.   
  17. if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0  
  18.         && sourceRecord != null) {  
  19.     // Transfer the result target from the source activity to the new  
  20.     // one being started, including any failures.  
  21.     if (requestCode >= 0) {  
  22.         return START_FORWARD_AND_REQUEST_CONFLICT;  
  23.     }  
  24.     resultRecord = sourceRecord.resultTo;  
  25.     resultWho = sourceRecord.resultWho;  
  26.     requestCode = sourceRecord.requestCode;  
  27.     sourceRecord.resultTo = null;  
  28.     if (resultRecord != null) {  
  29.         resultRecord.removeResultsLocked(  
  30.             sourceRecord, resultWho, requestCode);  
  31.     }  

1.2.2 Activity permission检查

1.2.2.1 callingPid和callingUid

    根据前面获得的callingPid和callingUid,我们看一下callingPid和callingUid是如何获得的。

    如果当前的activity不是从一个application启动的,也就是说参数caller==null,此时的callingPid和callingUid可以从IPC调用AMS的调用方获得,例如am启动,启动Home时,是没有caller的:

@startActivityMayWait()

[java]  view plain copy
  1. if (caller == null) {  
  2.     callingPid = Binder.getCallingPid();  
  3.     callingUid = Binder.getCallingUid();  
  4. else {  
  5.     callingPid = callingUid = -1;  
  6. }  
    如果 当前的activity是从一个application启动的 也就是说参数caller!=null,此时的callingPid和callingUid可以从caller所处的进程中得出。
[java]  view plain copy
  1. ProcessRecord callerApp = null;  
  2. if (caller != null) {  
  3.     callerApp = mService.getRecordForAppLocked(caller);  
  4.     if (callerApp != null) {  
  5.         callingPid = callerApp.pid;  
  6.         callingUid = callerApp.info.uid;  
  7.     } else {  
  8.         Slog.w(TAG, "Unable to find app for caller " + caller  
  9.               + " (pid=" + callingPid + ") when starting: "  
  10.               + intent.toString());  
  11.         err = START_PERMISSION_DENIED;  
  12.     }  
  13. }  

1.2.2.2    permission检查的规则

    1. Root uid(0), System Server uid (Process.SYSTEM_UID), own process(MY_PID),将授权permission

    2. 如果请求启动的activity的属性android:exported=false, 并且请求的callingUid不等于请求启动的activity的UID,不允许启动;

    3. 请求启动的activity没有设定permission,只有当activity的permission和其所在的application的android:permission均为设置时才为null,直设置了application未设置activity,那么activity的permission与application相同。activity的permission为空,则授权;

    4. 请求启动的activity设定了permission,那么检查请求方的activity中是否声明了使用这个permission,如果声明,授权。

[java]  view plain copy
  1. final int perm = mService.checkComponentPermission(aInfo.permission, callingPid,  
  2.         callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);  
  3. if (perm != PackageManager.PERMISSION_GRANTED) {  
  4.     if (resultRecord != null) {  
  5.         sendActivityResultLocked(-1,  
  6.             resultRecord, resultWho, requestCode,  
  7.             Activity.RESULT_CANCELED, null);  
  8.     }  
  9.     String msg = "Permission Denial: starting " + intent.toString()  
  10.             + " from " + callerApp + " (pid=" + callingPid  
  11.             + ", uid=" + callingUid + ")"  
  12.             + " requires " + aInfo.permission;  
  13.     Slog.w(TAG, msg);  
  14.     throw new SecurityException(msg);  
  15. }  

    创建ActivityRecord

[java]  view plain copy
  1. ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid,  
  2.         intent, resolvedType, aInfo, mService.mConfiguration,  
  3.         resultRecord, resultWho, requestCode, componentSpecified);  

1.3  task管理

    在android应用开发中,task是一个很重要的概念,在文章开始,我就画出了task和activity以及process整体的关系,在这里还需要说明一下,task和application的区别,application在android中的作用仅仅是activity在未被使用前的一个容器,我们开发android应用程序时,需要一个application来组织我们开发的activity,application和activity之间是一个静态关系,并且是一一对应的关系;也就是说我们开发的activity在PM中的最终形式是唯一的,永远对应一个application。

    而task和activity之间的关系是动态的关系,是我们在运行应用程序时,activity的调用栈,同一个task中的activity可能来自不同的application。

    关于task,更详细的资料参考:http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html

    这部分源码主要是在

        final int startActivityUncheckedLocked(ActivityRecord r,
            ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
            int grantedMode, boolean onlyIfNeeded, boolean doResume)

    这一部分比较繁琐,写的可能比较乱。

1.3.1 Intent.FLAG_ACTIVITY_NO_USER_ACTION

    检查Intent是否设置了Intent.FLAG_ACTIVITY_NO_USER_ACTION,如果设置了,则在activity pause之前将不再调用activity的onUserLeaveHint()方法。

[java]  view plain copy
  1. mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;  
  2. if (DEBUG_USER_LEAVING) Slog.v(TAG,  
  3.         "startActivity() => mUserLeaving=" + mUserLeaving);  

1.3.2 Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP

     检查Intent是否设置了Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP,这个标志我有点困惑,从它的注释可以看出它的含义是指如果设置了该flag,那么mHistory中最top的activity在后续的处理中将不被视为top,而将前一个activity视为top,如A-->B-->C,将B视为top。

    这个top activity的作用很大,涉及到后面对task的处理。但是目前来看这个flag并没有起到该有的作用,代码中判断如果设置了该标志,那么AMS将会视当前正在启动的activity为top,然后去mHistory中去查找它的前一个activity为后续task处理的top activity(topRunningNonDelayedActivityLocked()中实现),但是现在的问题是此时此刻,正在启动的activity并不存在于mHistory中,因为我们在前一个函数中刚刚创建了这个ActivityRecord。如下面代码所示:

[java]  view plain copy
  1. ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)  
  2.         != 0 ? r : null;  

因此,感觉这个flag的意义不是太大。

1.3.3  何时应该创建新的task

    sourceRecord为空;sourceRecord的activity的launch mode为ActivityInfo.LAUNCH_SINGLE_INSTANCE,也就是sourceRecord activity的task只允许一个activity;当前activity的launch mode为ActivityInfo.LAUNCH_SINGLE_INSTANCE或者r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK。以上几种情况,均可视为需要为启动的activity创建一个新的task.

[java]  view plain copy
  1. if (sourceRecord == null) {  
  2.     // This activity is not being started from another...  in this  
  3.     // case we -always- start a new task.  
  4.     if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {  
  5.         Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "  
  6.               + intent);  
  7.         launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;  
  8.     }  
  9. else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {  
  10.     // The original activity who is starting us is running as a single  
  11.     // instance...  this new activity it is starting must go on its  
  12.     // own task.  
  13.     launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;  
  14. else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE  
  15.         || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {  
  16.     // The activity being started is a single instance...  it always  
  17.     // gets launched into its own task.  
  18.     launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;  
  19. }  

1.3.4 Intent.FLAG_ACTIVITY_NEW_TASK时断开与Caller依赖

    如果启动的activity需要新的task,那么新启动的activity将会与其caller断开依赖关系,这个关系主要是指result反馈,A-->B,如果A是通过startActivityForResult()请求启动的,并且requestCode >=0,那么如果B是在新的task中,那么B在finish的时候将不再向A反馈result,而是在启动过程中就会向A反馈一个RESULT_CANCELED

[java]  view plain copy
  1. if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {  
  2.     // For whatever reason this activity is being launched into a new  
  3.     // task...  yet the caller has requested a result back.  Well, that  
  4.     // is pretty messed up, so instead immediately send back a cancel  
  5.     // and let the new task continue launched as normal without a  
  6.     // dependency on its originator.  
  7.     Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");  
  8.     sendActivityResultLocked(-1,  
  9.             r.resultTo, r.resultWho, r.requestCode,  
  10.         Activity.RESULT_CANCELED, null);  
  11.     r.resultTo = null;  
  12. }  

1.3.5  Task复用

1.3.5.1 Task的基本属性 


    检查mHistory中是否有task可复用,在分析这段之前,先了解一下task的一些基本概念

    task的root activity是指如果一个activity启动时创建的了一个新的task,那么这个activity是task的root activity;

    task.affinity是指root activity的affinity;

    task.intent是指启动root activity的Intent;

    task.affinityIntent是指activity在进行了TaskReparenting之后,AMS为activity分配了新的task,该task的affinityIntent则是启动该activity时的Intent,此时task.intent==null。

    TaskReparenting操作举例说明一下,假如有2个activity拥有不同的affinity,且自Activity A中启动Activity B,假如Activity A是所在task的root activity,如下图示:

    

    假如Activity B设置了ActivityInfo.FLAG_ALLOW_TASK_REPARENTING,那么如果此时另外一个application启动了Activity B并要求其在新的task中,那么此时的Activity B将被从Task A中移动到新的task中,如下图所示:

    

    这个过程就称之为TaskReparenting,关于TaskReparenting,我会专门写一篇文章分析一下。下面来分析task复用的过程。

1.3.5.2 查找可复用的task

    以下3种条件需要检查是否有有task可复用

    ⑴ (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;

    ⑵ r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK

    ⑶ r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE

    第⑴是一个组合条件,Intent.FLAG_ACTIVITY_MULTIPLE_TASK不能单独使用,它是和Intent.FLAG_ACTIVITY_NEW_TASK结合起来使用的,如果设置了Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那么将会永远启动一个新的task,不管是否有可复用的task。

   为什么是这3种条件,从android的开发文档中,我们可知LAUNCH_SINGLE_TASK和LAUNCH_SINGLE_INSTANCE两种launch mode的activity只允许作为task的root activity,既然是作为root activity,那么它所处的task的affinity必然是和它的是一样的,因此从mHistory中找打一个和自己的affinity相同的task是非常有必要的。

    而对于设置了Intent.FLAG_ACTIVITY_NEW_TASK的Intent来说,并且没有设置Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那么同样的,它也必须是作为它所处的task的root activity。道理是一样的。

    AMS去mHistory中查找可复用的task,查找这个task的规则如下:    

    ⑴ launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE的情况,遵循如下规则: @findTaskLocked()

        ① 查找mHistory中是否有与要启动的activity相同affinity的task,上面也提过这几类activity启动时,均是作为task的root activity,并且其task的affinity必须和自己的affinity相同,因此首先需要去mHistory查找和自己affinity相同的task。

        ② 如果activity没有affinity,即属性android:taskAffinity设置为“”,空字符串时。此时AMS就会去mHistory中去查找是否有task的root activity和启动的activity相同,通过比较task.intent.getComponent()和启动activity的Comeponent比较,为什么是root activity,前面分析过了;

        ③ 如果task.Intent为空,这种情况发生在TaskReparenting之后,TaskReparenting之后,AMS为这个activity创建一个新的task,并将启动这个activity的Intent赋值给task.affinityIntent,并且此时的task.Intent==null。此时就需要比较task.affinityIntent.getComponent()和启动activity的Comeponent比较,看是否和启动的activity相同。

    以上3个规则中,均是返回找的task中最上面的activity,而不一定是task的activity,至于如何处理要启动的activity和task中已有的activity,后面会介绍。

     launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE的情况,遵循如下规则: @findActivityLocked()

    对于ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式来说,它所处的task中只允许有它一个activity,因此它的规则只符合上面规则中的②;

    对于第①条,由于设置了ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity,它只能自己独处一个task,不可能和别人共享同一个task,因此mHistory即使存在了与该activity有相同的affinity的activity,如果这个activity和启动的activity不同,那么ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity也不可能和它共用一个task,因此这第①条完全可以不用检查。

    对于第②条,由于该模式的activity独处一个task,因此完全没有可能所处的task的affinity和自己的affinity不同,因此,假如mHistory存在相同的activity与启动的activity相同,那么这个activity的affinity必然和自己的相同。所以对于这种模式,第②条囊括了其他模式的①②两条。

    对于第③条,同样的道理,ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity不可能处在与自己不同affinity的task中,因此不可能出现TaskReparenting操作,所以这条也不需要。

[java]  view plain copy
  1. ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE  
  2.         ? findTaskLocked(intent, r.info)  
  3.         : findActivityLocked(intent, r.info);  

    在获得taskTop之后,下面来分析这个taskTop的意义。

1.3.5.3 task移到mHistory前端

    由于我们要复用task,因此需要将taskTop所在的task移到mHistory前端
[java]  view plain copy
  1. ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);  
  2. if (curTop.task != taskTop.task) {  
  3.     r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);  
  4.     boolean callerAtFront = sourceRecord == null  
  5.             || curTop.task == sourceRecord.task;  
  6.     if (callerAtFront) {  
  7.         // We really do want to push this one into the  
  8.         // user's face, right now.  
  9.         moveTaskToFrontLocked(taskTop.task, r);  
  10.     }  
  11. }  

1.3.5.4 Reset Task

    如果Intent设置Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,最常见的情况,当从Home启动应用程序时,会设置这个flag;从recently task进入应用程序,则不会设置这个falg。

    设置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,AMS会对复用的task作如下处理,下面称这个可复用的task为复用task:

    ⑴ mHistory中,对于复用task中的除root activity外的activity,有如下处理

        在此之前,先介绍activity的几个关键属性:

        ① 如果复用task在后台时间超过30min,那么在这个过程中将删除除root activity之外的所有的activity;

        ② 如果新启动的activity设置了属性ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE,那么表明它并不要求后台20min的复用task删除activity;

        ③ 如果新启动的activity设置了属性ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH,那么表明不论复用task在后台是否超过30min,一律要求删除除root activity之外的所有的activity;

        ④ 复用task中的activity设置了属性ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH,那么复用task从home中再次被启动到前台时,这个activity会被删除;

        ⑤ 复用task中的activity设置了属性ActivityInfo.FLAG_ALLOW_TASK_REPARENTIN,并且这个activity的resultTo为空,那么也就是说这个activity和它的caller没有依赖关系,那么AMS认为这个activity暂时没有用处了,需要对其进行TaskReparenting操作,最好的方法是把它放到mHistory栈底,不影响其他task。

        ⑥ 复用task中的activity的Intent设置属性Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,那么下次再从home中进入到task中,那么将删除设置了该属性的activity以上所有的activity,例如A-->B-->C-->D-->E,加入在C启动D时设置了该属性,那么下次从HOME中再次进入到这个task中时,将会是A-->B-->C。

        ⑦ 如果复用task中的activity的resultTo不为空,也就是启动这个activity的是一个activity,那么这个activity的处理将按照它的前一个activity的处理方式来处理,不管在何时情况下,它的前一个activity都是启动它的activity,即便resultTo不是前一个activity,如设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT。如果复用task中每个activity的resultTo都不为空,并且上述处理优先级在其前面的属性没有设置的话,那么这个复用task中的activity将不作任何的处理。

         一般情况下,activity的resultTo都不为空,除非设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT,那么此时被启动的activity的caller的resultTo将会为空。

        task中的activity的属性设置是上述属性的组合,因此reset task过程要按照一定的优先级来处理,上述属性的处理优先级是:⑥=④>⑦>⑤>③=②>①

        具体操作顺序如下:

        ♣ 根据⑥,④条件来删除复用task中相应的activity;

        ♣ ⑦条件下,将会暂时不做处理,再根据它的前一个activity的属性来做处理,即使这个activity设置了allowTaskReparenting;

        ♣ 如果activity的resultTo为空,并且满足条件⑤,那么将其及其以上未作处理的,满足条件⑦的所有activity,一并进行TaskReparenting操作,并放置在mHistory栈底。它们在mHistory栈底顺序如同在复用task中的顺序;

        ♣ 根据①②③的条件来删除复用task中相应的activity。

     ⑵ mHistory中,不属于复用task的activity,并且它的resultTo不为空,那么将根据它的前一个activity的处理来处理;

     ⑶ mHistory中,不属于复用task,但是和当前启动的activity有相同affinity,并且允许TaskReparenting操作,那么将进行以下操作:

          ♣ 如果满足上述的①②③④的条件,但是其中的task不是复用task,而是这个activity所处的task,那么将输出这个activity,而不是进行TaskReparenting操作。

            为什么非复用task中的activity,和当前启动的activity有相同affinity,并且允许TaskReparenting操作,满足了①②③④的条件之后要删除呢,为什么非复用task中的其他activity,不需要删除呢?

            正因为它和启动的activity有相同的affinity,因此AMS认为这个activity是和启动activity相关的,以后可能会重新调用,所以当其满足删除条件后,这时它将不允许TaskReparenting操作,并且不应该再允许它存在于其他的task中,此时应该删除。

          ♣ 如果没有满足①②③④的条件,那么将会对其进行TaskReparenting操作,重新将其移动到复用task或新启动的task中。

[java]  view plain copy
  1. // If the caller has requested that the target task be  
  2. // reset, then do so.  
  3. if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {  
  4.     taskTop = resetTaskIfNeededLocked(taskTop, r);  
  5. }  

    上面就是这个复用task的reset 过程,它的执行过程是按照上述的⑴⑵⑶的顺序来执行的,下面给出一个图示,便于更好的理解reset task的过程。

    

1.3.5.5 判断是否有可复用的activity

    如果mHistory中有可复用的task,那么在某些情况下并不需要启动这个activity,下面分析具体是什么情况:

      Intent设置了Intent.FLAG_ACTIVITY_CLEAR_TOP,或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK,或者r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;这3种条件有一个共同点,就是启动的activity启动之后,在这个task中,这个activity之上不能有其他的activity。

        一般情况下,需要将复用task中启动的activity之上的所有的activity删除,

        当activity的launchMode == ActivityInfo.LAUNCH_MULTIPLE,即普通模式,并且Intent并未要求singletop模式,这种情况是连复用task中与启动activity相同的activity都要删除,也就是不希望复用相同的activity。

        performClearTaskLocked()实现了上述功能,并返回可复用的activity。

[java]  view plain copy
  1. ActivityRecord top = performClearTaskLocked(  
  2.         taskTop.task.taskId, r, launchFlags, true);  

        如果有可复用的activity,并且这个activity是task的root activity,由于task的Intent是root activity的Intent,所以需要重新设置task的Intent。

        向可复用的activity发送新的Intent,通知它Intent的变化,最终会调用到这个activity的onNewIntent()方法。

     ⑵ 如果不满足⑴条件的话,但是启动的activity与复用task的root activity相同。

         如果此时Intent设置了Intent.FLAG_ACTIVITY_SINGLE_TOP,并且复用task的top activity正好是要启动的activity,则复用这个activity,同时更新activity的Intent,如果需要更新task的Intent。

         如果Intent没有设置了Intent.FLAG_ACTIVITY_SINGLE_TOP,即使设置了,但是当前的top activity不是正要启动的activity,那么会判断当前启动的Intent和task的Intent不同,那么将会重新启动这个activity。

 其他情况,将直接resume top的activity。

     ⑶ 如果⑴ ⑵条件均不满足,其实如果不满足⑴ ⑵条件的话,复用的task中就不存在与启动的activity相同的activity了,如果启动的Intent没有设置Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那么一定不会复用任何的activity。

     (4) 如果⑴ ⑵条件均不满足,并且Intent设置了Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那么需要检查当前复用task的Intent是否设置了Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

        如果没有设置,重新设置新的Intent,同样不可能复用activity。

        这种情况下,将不会显示要启动的activity,而是改为显示复用的task中的内容,如下图:

        


    至此,整个Task复用,已经activity复用的过程就介绍完了,如果没有可复用的activity,则需要启动一个新的activity,如果有可复用的activity,那么activity的启动过程至此结束,直接调用resumeTopActivityLocked()resume top的activity即可。

    以后的处理均为Task复用和activity复用失败之后的处理。

1.3.6 singleTop和singleTask属性的处理

    这一部分是针对singleTop和singleTask属性的处理,前面分析Task复用的时候,也有对singleTop和singleTask属性的处理,两者有什么不同呢?

    Task复用中是启动的activity需要在新的task中,而这里的处理主要是针对同一个task。

    当设置Intent.FLAG_ACTIVITY_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK这几种情况下,如果top activity与启动的activity为同一个activity,那么将复用top activity,并直接resume top activity。

    

[java]  view plain copy
  1. if (top != null && r.resultTo == null) {  
  2.     if (top.realActivity.equals(r.realActivity)) {  
  3.         if (top.app != null && top.app.thread != null) {  
  4.             if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0  
  5.                 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP  
  6.                 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {  
  7.                 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);  
  8.                 // For paranoia, make sure we have correctly  
  9.                 // resumed the top activity.  
  10.                 if (doResume) {  
  11.                     resumeTopActivityLocked(null);  
  12.                 }  
  13.                 if (onlyIfNeeded) {  
  14.                     // We don't need to start a new activity, and  
  15.                     // the client said not to do anything if that  
  16.                     // is the case, so this is it!  
  17.                     return START_RETURN_INTENT_TO_CALLER;  
  18.                 }  
  19.                 top.deliverNewIntentLocked(callingUid, r.intent);  
  20.                 return START_DELIVERED_TO_TOP;  
  21.             }  
  22.         }  
  23.     }  
  24. }  
    r.resultTo == null这个条件是在startActivityForResult()的requestCode<0时成立。

    为什么没有ActivityInfo.LAUNCH_SINGLE_INSTANCE?这是因为这种启动模式,如果Task复用失败之后,直接启动为其启动一个Intent.FLAG_ACTIVITY_NEW_TASK即可。

1.3.7 standard和singleInstance模式

    为什么代码中没有明显的针对ActivityInfo.LAUNCH_SINGLE_INSTANCE模式的处理?这是因为这种启动模式,如果Task复用失败之后,直接启动为其启动一个Intent.FLAG_ACTIVITY_NEW_TASK即可。

    ⑴ 设置了Intent.FLAG_ACTIVITY_NEW_TASK,则为该activity创建一个新的task;

    ⑵ 在当前的task中启动新的activity,

        ①当前的caller是一个activity,如果设置Intent.FLAG_ACTIVITY_CLEAR_TOP,当前的task如果存在要启动的activity(这个和上一节中的Task复用时的clear top过程不同,两者是互斥的过程,不冲突),清除其上的所有的activity;

        ② 当前的caller是一个activity,如果设置Intent.FLAG_ACTIVITY_REORDER_TO_FRONT,这个flag表示如果启动的activity已经在当前的task中,那么如果当前启动的Intent设置了该flag,那么则会将这个activity从task中移动到top。

             如果A-->B-->C-->D,D启动B时,设置了该flag,那么将变为A-->C-->D-->B

             ①②两个条件,则不需要再启动新的activity,直接resume top。

        ③  当前的caller是一个activity,其他情况则需要启动新的activity。

    ⑶ 当前的caller不是activity,那么仍将新启动的activity放在top的task中。

更多相关文章

  1. Android中可自由移动悬浮窗口的实现
  2. 14天学会安卓开发(第十一天)Android图形技术
  3. android Gradle例如:“style attribute 'android:attr/keyboardNa
  4. android定位
  5. android ProgressBar 样式讲解
  6. android persistent属性研究
  7. ActivityManagerService启动流程详解
  8. ListView与BaseAdapter优化
  9. Android临时和永久关闭selinux

随机推荐

  1. Part 1:Multi-threading Android Apps fo
  2. android 判断联网类型
  3. cross compile busybox for android
  4. android 书架效果实现
  5. Android简单计算器界面实现
  6. Android Studio计算器 app
  7. Android GMS认证项总结
  8. Android中数据库升级
  9. android 获取当前设备的ip地址 mac地址
  10. AndroidStudio修改虚拟机AVD路径