Android AMS源码阅读分析(一)

最近学习了柯元旦所著《Android内核剖析》之AMS原理篇章,结合自己的理解以及对源码的分析,记录一下学习心得,AMS代码非常多,而且和Application以及Activity之间的交互也相对繁杂,这里学习大致的主干流程,之后有时间会再去细看。

AMS的功能

AMS的功能可以概述为以下三个:

《Android AMS源码阅读分析(一)》

首先来看看这个统一调度各个应用程序之间的activity,可以把AMS理解成一个管理员,管理着手机里面的所有应用程序,每当一个应用程序想要启动activity,都要先报告AMS,AMS认为该应用程序可以启动,那么就通知该应用程序去执行启动activity操作,当应用程序启动完毕,也要报告AMS,AMS会记录对应的进程以及对应的activity,以便对activity进行管理和调控,例如内存不足时选择杀死某些优先级的activity。

既然应用程序启动activity需要AMS的调控,那么我们就来看看activity的启动过程以及过程中,AMS如何对应用程序加以调度,并且和应用程序之间进行交互的。

Activity的启动入口是startActivityForResult(),startActivity()其实也是调用了startActivityForResult(),那么就从这个入口去看看具体的启动流程吧;

activity的启动流程

activity的启动流程大概总结为:

启动Activity B -> 当前有正在显示的activity吗 -> 有就先pause() -> B的进程存在吗 -> 不存在则创建 -> B进程启动指定的Activity

首先来看一下这个过程的具体流程图,其实就是上面流程简介的具体化:
《Android AMS源码阅读分析(一)》

现在从源码开始,一步一步的去看看具体的startActivity()的执行流程:

一.首先是startActivity的调用流程

从Activity中调用了startActivity()之后,经过一系列跳转,会执行到Instrument的execStartActivity()方法中,这个Instrumentation是什么呢?可以说它是应用进程的管家,监控着应用进程与系统的所有交互,所有的创建、暂停、停止activity,都是通过它去发起的,它可以统计所有的开销。

那么再来看看execStartActivity()方法的内部实现:


 /** 
   * 1.先看看比较重要的参数的意义:
   * @param who:  当前的执行了startActivity的activity对象
   * @param contextThread :当前activity 的主线程,即是ApplicationThread对象
   * @param token:用于鉴定启动activity的对象
   * @param target:需要被启动的activity 对象
   **/    
 public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {

        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ...
        
        //...省略关于ActivityMonitor测试工具类的部分
       
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            
            /**
              * 2.看到这里,我们发现Instrumentation将启动activity的工作交给了AMS,这里就
              * 涉及到了IPC调用了,IPC调用是同步的,而startActivity()是在主线程中调用的
              * 那么这里会导致主线程阻塞吗?
              * 答案是不会的,由于AMS内部执行startActivity()是异步的,所以会在很短时间内
              * 返回,然后最后再通过回调Activity的onActivityResult(),所以需要在这个方法
              * 中传入一个Token,即是Activity的标识
              **/
              
                int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
 

再来看下在AMS中是如何去实现这个startActivity的流程的,在AMS中经过一系列的调用,最终会调用如下startActivityAsUser()方法:

/**
  * 1.来看一下重要参数的含义:
  * @param caller :指的是ApplicationThread,代表当前要启动activity的主线程
  * @param callingPackage:发起startActivity的进程包名
  * @param resultTo:Activity传来的token变量,对应的是AMS的ActivityRecord,AMS通过来识
  *                 别客户端进程的Activity
  *           
  **/

public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        
		 //2.获取userId
        userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        /**
          * 3.这里将启动activity任务委托给了ActivityStartController,
          * ActivityStartController的主要工作就是将启动外部Activity的请求放入一个
          * 请求队列当中,使得这些请求可以被ActivityStarter处理,同时负责处理activity
          * 启动时的一些逻辑问题,例如处理待启动activity列表,记录home activity启动等,
          * 但是真正的启动逻辑还是由ActivityStarter来处理。
          **/
        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();    //4.然后再通过ActivityStarter执行startActivity的请求

    }
    

二、运行条件检查以及intent的flag处理

然后再去看看ActivityStarter里面执行startActivity的地方,ActivityStarter执行startActivity的代码非常长,各种条件、分支判断非常多,我们选择正常的流程来进行分析:

private int startActivity(....) {

 ProcessRecord callerApp = null;
    /**
      * 1.caller代表的是要启动Activity的进程的主线程,这里先去获取一个ProcessRecord,
      * 它是一个进程记录类,每个正在运行的进程都有一个ProcessRecord,
      * 在AMS中以<包名,ProcessRecord>的形式存储,这个ProcessRecord记录了进程的所有信息
      * 包括uid、userId、processName、curAdj(当前的OOM参数)等等
     **/ 
     if (caller != null) {
        callerApp = mService.getRecordForAppLocked(caller); 
             
        //2.从AMS中获取当前caller的ProcessRecord,其中ProcessRecord用到了LRU进行存储
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller
                        + " (pid=" + callingPid + ") when starting: "
                        + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }

        final int userId = aInfo != null && aInfo.applicationInfo != null
                ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
               
        
        /**
          * 3.这里出现了一个ActivityStackSupervisor,顾名思义,就是activity栈的管理者,
          * 它有一个mActivityDisplays的变量用于存储ActivityDisplay,ActivityDisplay主要
          * 存储了ActivityStack,负责当前Display的栈的创建、添加、删除等等工作;
          * 
          * 遍历该ActivityStackSupervisor的mActivityDisplays,取得各个
          * ActivityDisplay,再遍历ActivityDisplay的ActivityStack,根据token去匹配,返回
          * 源Activity的ActivityRecord,ActivityRecord是一个Activity的记录类,
          * 记录了activity的两方面信息,一是环境信息,例如该activity隶属于哪个package,
          * 所在进程名称、文件路径、图标、主题等,二是运行状态信息,例如idle、stop、finishing等
          **/  
              
        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
            
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) { 
                 //如果启动方式是startActivityForResult()且源activity还没有finishing
                    resultRecord = sourceRecord;
                }
            }
        }
        
        final int launchFlags = intent.getFlags();
        
		 /**
		   * 4.这里根据intent的信息去匹配component信息,这也是intent可以直接指定Activity名称
		   * 的原因,AMS会调用系统内部的PackageManager查询具体的Component名称,如果没有
		   * Component匹配该intent,则返回失败。
		   **/
		
        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
        /**
          * 处理FLAG_ACTIVITY_FORWARD_RESULT:
		   * 比如:A 启动了 B,此时再从B启动C,并且B设置了FLAG_ACTIVITY_FORWARD_RESULT,那么C
		   * 运行时,可以在C中调用setResult(),然后finish,其结果会从C直接返回A,同时启动过程必须
		   * 如下:
		   * A(startActivityForResult)  -> B(startActivity)  -> C. 
		   * 同时B不能调用startActivityForResult,即requestCode 不能 >= 0,否则就会回调
		   * START_FORWARD_AND_REQUEST_CONFLICT冲突。
			**/	
            
            if (requestCode >= 0) {
                SafeActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            resultRecord = sourceRecord.resultTo;
            if (resultRecord != null && !resultRecord.isInStackLocked()) {
                resultRecord = null;
            }
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }
            
            if (sourceRecord.launchedFromUid == callingUid) {
               /**
                 * 5.检查当前源activity是否和目标activity一致,即是
                 * A(startActivityForResult) -> B(startActivity)  ->B 的情况,将正在运
                 * 行的activity的包名赋值给目标activity。
                 **/
               callingPackage = sourceRecord.launchedFromPackage;
            }
        }

		 //intent 的component为空时或者activityInfo为空时,直接返回
        if (err == ActivityManager.START_SUCCESS && (intent.getComponent() == null ||( aInfo == null))) {          
           ...
        }


		 /**
		   * 6.处理voiceSession的情况,当目前的activity有语音对话,要启动的activity也存在语音
		   * 对话,那么只有当目标activity指定了Intent.CATEGORY_VOICE才能启动。
		   **/
        if (err == ActivityManager.START_SUCCESS && sourceRecord != null
                && sourceRecord.getTask().voiceSession != null) {
            if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
                    && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
                try {
                    intent.addCategory(Intent.CATEGORY_VOICE);
                    if (!mService.getPackageManager().activitySupportsIntent(
                            intent.getComponent(), intent, resolvedType)) {
                        Slog.w(TAG,
                                "Activity being started in current voice task does not support voice: "
                                        + intent);
                        err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                    }
                } catch (RemoteException e) {
                    Slog.w(TAG, "Failure checking voice capabilities", e);
                    err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
                }
            }
        }
		 ...
		
        final ActivityStack resultStack = resultRecord == null ? null : resultRecord.getStack();

        ...
        
        
		 /**
		   * 7.对要启动的activity进行权限判断
		   **/
        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity,
                inTask != null, callerApp, resultRecord, resultStack);   
        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                callingPid, resolvedType, aInfo.applicationInfo);

        ...

		 /**
		   * 8.判断是否需要拦截该activity启动请求,例如该进程已经退出或者目标进程已经暂停了等等,
		   * 例如caller在调用startActivity()之后又被意外杀死的情况。
		   **/
        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
        if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,
                callingUid, checkedOptions)) {
            ...
        }
        
		/**
		  * 9.如果请求中断了,则通过ActivityRecord回调Activity的onActivityResult()方法,
		  * 流程结束
		  **/	
        if (abort) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                        RESULT_CANCELED, null);
            }
            // We pretend to the caller that it was really started, but
            // they will just get a cancel result.
            ActivityOptions.abort(checkedOptions);
            return START_ABORTED;
        }
        
		//上面都是在对运行条件进行检查判断,遇到异常就终止流程,下面,继续执行正常流程
		
		 /**
		   * 10.创建一个临时的ActivityRecord对象,这个对象只是为了后面调用过程中的各种对比,
		   * 并非一定会加入到ActivityRecord列表中去。
		   **/	        
        ActivityRecord r = new ActivityRecord(mService, callerApp...);
        
        if (outActivity != null) {
            outActivity[0] = r;
        }

        if (r.appTimeTracker == null && sourceRecord != null) {
            // If the caller didn't specify an explicit time tracker, we want to continue
            // tracking under any it has.
            r.appTimeTracker = sourceRecord.appTimeTracker;
        }

        final ActivityStack stack = mSupervisor.mFocusedStack;
        
        
		 /**
		   * 11.检查是否允许切换activity,不允许切换的情况一般发生在当前已经暂停了正在执行的
		   * activity,正在等待下一个Activity启动时,此时不能进行Activity切换,但是会把指定的
		   * activity添加到mPendingActivityLaunches中,等待系统恢复后再继续执行。
		   **/
        if (voiceSession == null && (stack.getResumedActivity() == null
                || stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                    realCallingPid, realCallingUid, "Activity start")) {
                mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
                        sourceRecord, startFlags, stack, callerApp));
                ActivityOptions.abort(checkedOptions);
                return ActivityManager.START_SWITCHES_CANCELED;
            }
        }

        if (mService.mDidAppSwitch) {
            // This is the second allowed switch since we stopped switches,
            // so now just generally allow switches.  Use case: user presses
            // home (switches disabled, switch to home, mDidAppSwitch now true);
            // user taps a home icon (coming from home so allowed, we hit here
            // and now allow anyone to switch again).
            mService.mAppSwitchesAllowedTime = 0;
        } else {
            mService.mDidAppSwitch = true;
        }

		 /**
		   * 12.判断等待队列中是否有等待启动的Activity,如果有的话,应该先执行这里面等待的
		   * Activity。
		   **/
        mController.doPendingActivityLaunches(false);
       
        
    	 /**
    	   * 13.如果等待的队列为空,则下面的方法会调用startActivityUnchecked()方法,表明待启动
    	   * 的Activity已经经过了所有的检验,是一个“正当”的请求,可以进行启动了,启动activity有四
    	   * 种方法,standard、singleTop、 singTask、singleInstance,接下来,AMS会去判
    	   * 断要以哪种方式来启动指定的activity。
    	   **/
        return startActivity(....);
    }
    

三、AMS根据启动intent去找到或者创建合适的Task

接下来,AMS需要确定是否需要给目标activity创建一个新的Task或者是给它找到一个合适的task,具体的执行过程如下:

 private int startActivityUnchecked(...) {

   /**
     * 1.初始化状态,根据launchMode变量设置局部变量launchFlags,因为接下来要根据launchFlags来
     * 决定启动activity的方式,launchMode和launchFlags是不同的喔,mode是Activity在Android
     *  Manifest中声明的运行方式,而flags是调用者希望用哪一种形式去运行指定的Activity,是在调用
     *  startActivity()时参数intent中指定的。
     *  
     **/
       
      setInitialState(.....);
       
       
   	/**
   	  * 2.下面这里的工作就是计算flags以及是否需要创建task和目标activity,或者复用已有的activity,启动模式有四种,分别是standard、singleTop、singleTask、singleInstance
   	  * 这里会判断属于哪一种模式,然后分别进行处理:
   	  * standard:在当前栈中启动新的activity
   	  * singleTop:判断当前栈的栈顶是否是目标activity,是的话,则无需创建新的activity,而是调用它的onNewIntent(),否则就在栈顶创建一个新的目标activity
   	  * singeTask:判断指定的栈中是否存在目标activity,指定的栈由taskAffinity属性来指定,如果存在,则将该目标activity栈顶的其他activity都弹出栈,让该activity位于栈顶,且调用
   	  * 			 它的onNewIntent(),如果不存在,则在指定的栈中新建一个activity;
   	  * 			 一般情况下,同一个应用程序的activity都存在于同一个task中,但是当一个程序想调用其他的程序时,例如希望从当前程序调起发邮件的的activity,那么就需要指定目标activity
   	  * 			 为singleTask,且taskAffinity属性为邮件应用程序的包名,此时目标activity和邮件程序在同一个task中
   	  * singleInstance:判断目标activity 是否存在,不存在时则创建一个新的task,在该task中创建目标activity,一个手机中只有一个singleInstance的activity的实例,例如打电话的界面,一个
   	  * 			   手机中所有的应用程序都共享一个singleInstance的目标activity。
   	  * 			   	  
   	  * 
      computeLaunchingTaskFlags();
   	
      computeSourceStack();

       mIntent.setFlags(mLaunchFlags);
       
       ActivityRecord reusedActivity = getReusableIntentActivity();
   	 ....
   	 
       
       
   	 /**
   	   * 3.为目标activity赋予合法的权限,目标activity会在安装时指定所需要的权限,这里是将所需权限添加至缓存中
   	   **/	
       mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
               mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
       mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
               mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));

       
       /**
         * 4.接下来,根据上面的判断结果,是执行哪种activity的启动方式,创建新的目标activity或者是直接resume已有的目标activity
         **/        
       if (newTask) {
           EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
                   mStartActivity.getTask().taskId);
       }
       ActivityStack.logStartActivity(
               EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
       mTargetStack.mLastPausedActivity = null;

       mSupervisor.sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);

        /**
          * 5.这里是执行创建目标activity的操作,需要通知WMS将目标activity显示出来,并且添加activity的切换动画等
          * 
          **/
       mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
               mOptions);
       //6.执行目标activity的resume操作        
       if (mDoResume) {
           final ActivityRecord topTaskActivity =
                   mStartActivity.getTask().topRunningActivityLocked();
           if (!mTargetStack.isFocusable()
                   || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                   && mStartActivity != topTaskActivity)) {
               
               mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
               
               mService.mWindowManager.executeAppTransition();
           } else {
               
               if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                   mTargetStack.moveToFront("startActivityUnchecked");
               }
               mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                       mOptions);
           }
       } else if (mStartActivity != null) {
           mSupervisor.mRecentTasks.add(mStartActivity.getTask());
       }
       mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);

       mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
               preferredLaunchDisplayId, mTargetStack);

       return START_SUCCESS;
   }

总结startActivityForResult()的执行过程

《Android AMS源码阅读分析(一)》

    原文作者:小毕加猪
    原文地址: https://blog.csdn.net/qq_26984087/article/details/86601090
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞