AMS分析--基于深入理解android(1)

分析参考深入理解android,启动一个app可以使用am start -W -n com.android.settings/.Settings
其中,-W选项表示am将会等目标Activity启动后才返回,-n表示后面的参数用于设置Intent的Component。就本例而言,com.android.settings为Package名,.Settings 为该Package下对应的Activity类名,所以将要启动的Activity的全路径名为com.android.settings/.Settings 。
现在就以上面的命令为例来分析Am的run函数,代码如下:

 public static void main(String[] args) {
        (new Am()).run(args);
    }

会调用到函数处理 start 选项

public void onRun() throws Exception {

        mAm = ActivityManagerNative.getDefault();
        if (mAm == null) {
            System.err.println(NO_SYSTEM_ERROR_CODE);
            throw new AndroidException("Can't connect to activity manager; is the system running?");
        }

        String op = nextArgRequired();

        if (op.equals("start")) {
            runStart();
  private void runStart() throws Exception {
        Intent intent = makeIntent(UserHandle.USER_CURRENT);

        if (mUserId == UserHandle.USER_ALL) {
            System.err.println("Error: Can't start service with user 'all'");
            return;
        }

        String mimeType = intent.getType();
        if (mimeType == null && intent.getData() != null
                && "content".equals(intent.getData().getScheme())) {
            mimeType = mAm.getProviderMimeType(intent.getData(), mUserId);
        }

        do {
            if (mStopOption) {//mStopOption 由 -S 决定 先关闭activity 重新启动这个activity
                String packageName;
                if (intent.getComponent() != null) {
                    packageName = intent.getComponent().getPackageName();//获取包名
                    ....
                    ...
                      System.out.println("Stopping: " + packageName);
                mAm.forceStopPackage(packageName, mUserId);//关闭这个activity对应的app
                Thread.sleep(250);
            }

            System.out.println("Starting: " + intent);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//以为通过am启动这个app 所以添加这个标志。表示新的任务

            IActivityManager.WaitResult result = null;
            int res;
            if (mWaitOption) {//mWaitOption控制是否等待启动结果,如果有-W选项,则该值为true
                result = mAm.startActivityAndWait(null, null, intent, mimeType,
                            null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
                res = result.result;
            } else {
                res = mAm.startActivityAsUser(null, null, intent, mimeType,
                        null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
            }
public WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho,
            int requestCode, int flags, String profileFile,
            ParcelFileDescriptor profileFd, Bundle options, int userId)

有很多参数 分析一下绝大多数情况下一个activity的启动是由一个应用进程发起的,IApplicationThread 是app和AMS交互的通道,本例AMS并非应用程序所以为NULL,
String callingPackage, 调用包名也为null
resultTo 表示接收startActivityAndWait 结果
resultWho :加入 A启动 B,则A就是resultWho
requestCode:在本例中为0,该值的具体意义由调用者解释。如果该值大于等于0,则AMS内部保存该值
剩下几个都是性能统计。

  public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, String profileFile,
            ParcelFileDescriptor profileFd, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivityAndWait");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, true, "startActivityAndWait", null);
        WaitResult res = new WaitResult();//保存调用结果
        // TODO: Switch to user app stacks here.
        mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
                res, null, options, UserHandle.getCallingUserId());
        return res;
    }

findTaskLocked(ActivityRecord target) {//返回是否存在一个task的top activity 与我们给定的Intent匹配
topRunningActivityLocked(ActivityRecord notTop) 找到stack中第一个与notTop不同的并且不处于finishing的activity ,当notTop 为null 返回当前显示的activity
topRunningNonDelayedActivityLocked(ActivityRecord notTop)
返回stack中第一个与notTop不同的并且不处于finishing同时delayedRusume为false的activity (delayedRusume表示要暂缓显示)
ctivity启动模式设置:

    <activity android:name=".MainActivity" android:launchMode="standard" />

Activity的四种启动模式:

1. standard

    默认启动模式,每次激活Activity时都会创建Activity,并放入任务栈中。

2. singleTop

    如果在任务的栈顶正好存在该Activity的实例, 就重用该实例,否者就会创建新的实例并放入栈顶(即使栈中已经存在该Activity实例,只要不在栈顶,都会创建实例)。

3. singleTask

    如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移除栈。如果栈中不存在该实例,将会创建新的实例放入栈中。 

4. singleInstance

    在一个新栈中创建该Activity实例,并让多个应用共享改栈中的该Activity实例。一旦改模式的Activity的实例存在于某个栈中,任何应用再激活改Activity时都会重用该栈中的实例,其效果相当于多个应用程序共享一个应用,不管谁激活该Activity都会进入同一个应用中。

大家遇到一个应用的Activity供多种方式调用启动的情况,多个调用希望只有一个Activity的实例存在,这就需要Activity的onNewIntent(Intent intent)方法了。只要在Activity中加入自己的onNewIntent(intent)的实现加上Manifest中对Activity设置lanuchMode=“singleTask”就可以。

   onNewIntent()非常好用,Activity第一启动的时候执行onCreate()---->onStart()---->onResume()等后续生命周期函数,也就时说第一次启动Activity并不会执行到onNewIntent(). 而后面如果再有想启动Activity的时候,那就是执行onNewIntent()---->onResart()------>onStart()----->onResume().  如果android系统由于内存不足把已存在Activity释放掉了,那么再次调用的时候会重新启动Activity即执行onCreate()---->onStart()---->onResume()等。

 当调用到onNewIntent(intent)的时候,需要在onNewIntent() 中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getIntent()都是得到老的Intent。
  FLAG_ACTIVITY_NEW_TASK:将目标Activity放到一个新的Task中。

· FLAG_ACTIVITY_CLEAR_TASK:当启动一个Activity时,先把和目标Activity有关联的Task“干掉“,然后启动一个新的Task,并把目标Activity放到新的Task中。该标志必须和FLAG_ACTIVITY_NEW_TASK标志一起使用。
· FLAG_ACTIVITY_CLEAR_TOP:当启动一个不处于栈顶的Activity时候,先把排在它前面的Activity“干掉”。例如Task有A、B、C、D4个Activity,要要启动B,直接把C、D“干掉”,而不是新建一个B。

 final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
            String resultWho, int requestCode, int startFlags, String profileFile,
            ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
            Bundle options, int userId) {
            ............
              // Collect information about the target of the Intent.
        ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
                profileFile, profileFd, userId);
        //获得要启动Activity相关信息
        ...............
                synchronized (mService) {
            int callingPid;
            if (callingUid >= 0) {//callingUid=-1
                callingPid = -1;
            } else if (caller == null) {
                callingPid = Binder.getCallingPid();//调用者的uid 和pid
                callingUid = Binder.getCallingUid();
            } else {
                callingPid = callingUid = -1;
            }

            final ActivityStack stack = getFocusedStack();//返回当前显示的栈(home 或者app)
            stack.mConfigWillChange = config != null
                    && mService.mConfiguration.diff(config) != 0;
            if (DEBUG_CONFIGURATION) Slog.v(TAG,
                    "Starting activity when config will change = " + stack.mConfigWillChange);

            final long origId = Binder.clearCallingIdentity();
            //clearCallingIdentity可参见这篇文件分析http://blog.csdn.net/thinkinwm/article/details/18311211
            }
               } while (!outResult.timeout && outResult.who == null);
                } else if (res == ActivityManager.START_TASK_TO_FRONT) {//字面意思没有真正启动,只是task带到前台
                    ActivityRecord r = stack.topRunningActivityLocked(null);
                    if (r.nowVisible) {
                        outResult.timeout = false;
                        outResult.who = new ComponentName(r.info.packageName, r.info.name);
                        outResult.totalTime = 0;
                        outResult.thisTime = 0;
                    } else {
                        outResult.thisTime = SystemClock.uptimeMillis();
                        mWaitingActivityVisible.add(outResult);
                        do {
                            try {
                                mService.wait();
                            } catch (InterruptedException e) {
                            }
                        } while (!outResult.timeout && outResult.who == null);
                    }
                }
            }

            return res;
        }
    }   
    final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
            String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
            boolean componentSpecified, ActivityRecord[] outActivity) {
        int err = ActivityManager.START_SUCCESS;

        ProcessRecord callerApp = null;
        if (caller != null) {
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
                //如果caller不为空,则需要从AMS中找到它的ProcessRecord。本例的caller为null
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller
                      + " (pid=" + callingPid + ") when starting: "
                      + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }

        if (err == ActivityManager.START_SUCCESS) {
            final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
        }
          //下面两个变量意义很重要。sourceRecord用于描述启动目标Activity的那个Activity,
        //resultRecord用于描述接收启动结果的Activity,即该Activity的onActivityResult
         //将被调用以通知启动结果,读者可先阅读SDK中startActivityForResult函数的说明

        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {//参数resultTo是启动这个Activity的一个Binder对象,通过它可以获得启动这个Activity的Activity相关信息,保存在sourceRecord变量中
            sourceRecord = isInAnyStackLocked(resultTo);
            if (DEBUG_RESULTS) Slog.v(
                TAG, "Will send result to " + resultTo + " " + sourceRecord);
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {//只有 requestCode >= 0 才使resultRecord = sourceRecord
                    resultRecord = sourceRecord;//发送请求和接收请求是同一个
                }
            }
        }
        ..............
             int launchFlags = intent.getFlags();

        if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
                && sourceRecord != null) {
            // Transfer the result target from the source activity to the new
            // one being started, including any failures.
            if (requestCode >= 0) {
                ActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            resultRecord = sourceRecord.resultTo;
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(
                    sourceRecord, resultWho, requestCode);
            }
        }//此处解释看云笔记-AMS

得到Intent的launchFlags,此时会判断launchFlags中是否有Intent.FLAG_ACTIVITY_FORWARD_RESULT,也就是重定向结果,因为Android允许将结果重定向,也就是A通过startActivityForResult启动B,而B可以通过startActivity,然后加入该标志位启动C,C调用setResult后,A就能的到C中的结果了。此处的逻辑如下:
当launchFlags中有Intent.FLAG_ACTIVITY_FORWARD_RESULT的时候,判断requestCode是否大于等于0,如果大于等于0的话,那么就直接返回错误码了,因为B启动C的时候不允许通过startActivityForResult启动,如果是通过startActivity的话,那么就会执行如下代码:
[java] view plain copy
resultRecord = sourceRecord.resultTo;
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(
sourceRecord, resultWho, requestCode);
}
首先会将resultRecord重新赋值为sourceRecord.resultTo,此时sourceRecord.resultTo就是代表的A,因为A是通过startActivityForResult启动B,然后B通过startActivity启动C,所以resultRecord代表的就是A的ActivityRecord,然后将resultWho也重新赋值为A的ActivityRecord的resultWho,以及requestCode也重新被赋值,并且将B的resultTo设置成null,因为它不需要再接收结果了,所以设成null,然后通过resultRecord.removeResultLocked,将B从A中的回调删除。
检查当前正在运行的Activity是否和目标Activity一致,如果一致,则直接返回。这就是说,程序员在Activity使用startActivity启动自己,不会达到重启当前Activity的目的。

处理FLAG_ACTIVITY_FORWARD_RESULT标志。从代码的角度来看,这个标志有一个特殊的作用,就是能够跨Activity传递Result。比如A1→A2,此时如果从A2中启动A3,并且设置的启动标志为FORWARD_RESULT,那么A3运行时,可以在A3中调用setResult,然后finish(),其结果会从A3直接返回到A1,并且A1会得到A3所set的result。要满足这种调用,必须使用以下方式启动。

A1(startActivityForResult) →A2(StartActivity) →A3。注意A2不能使用forResult的方式启动A3,否则会发生冲突START_FORWARD_AND_REQUEST_CONFLICT。

 resultRecord = sourceRecord.resultTo;//sourceRecord =A2 resultRecord = A1 表示把A2的resultTo当做 A3的resultRecord 
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;//因为A2 不需要发送启动结果置位null
  ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration,
                resultRecord, resultWho, requestCode, componentSpecified, this);
        if (outActivity != null) {
            outActivity[0] = r;
        }

        final ActivityStack stack = getFocusedStack();//获得当前在前台的ActivityStack
        if (stack.mResumedActivity == null
                || stack.mResumedActivity.info.applicationInfo.uid != callingUid) {
            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
            //如果调用进程没有权限切换Activity,则只能把这次Activity启动请求保存起来,后续有机会时再启动它
                PendingActivityLaunch pal =
                        new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
                mService.mPendingActivityLaunches.add(pal);
                setDismissKeyguard(false);//不可以使用键盘
                ActivityOptions.abort(options);
                return ActivityManager.START_SWITCHES_CANCELED;
            }
        }

接着创建一个ActivityRecord r,这个ActivityRecord对象就代表着要启动的BActivity,接着如下代码会判断当前处于Resume状态的Activity是否为null,并且当前Resume状态的Activity的uid和调用者的UID是否相同,如果有一个不相同的话,那么直接返回错误码START_SWITCHES_CANCELED。
检查当前是否允许切换Activity,不允许切换的情况一般发生在当前已经暂停的正在执行的Activity,正在等待下一个Activity的启动时,此时不能进行Activity切换。如果是这样,则把指定的Activity临时添加到mPendingActivityLaunches列表中,等待系统恢复后再继续执行。
或者当前是输入密码界面。不希望来电显示界面打断当前界面

 if (allPausedActivitiesComplete()) {
            // If someone asked to have the keyguard dismissed on the next
            // activity start, but we are not actually doing an activity // switch... just dismiss the keyguard now, because we // probably want to see whatever is behind it. dismissKeyguard();
        }

//如果pre Activity已经pause完成,那么就可以解锁dismissKeyguard键盘

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