深入理解四大组件(一)Android8.0 根 Activity 的启动过程(上)

概述

Activity的启动过程分为两种,一种是根Activity的启动过程,另一种是普通Activity的启动过程。根Activity指的是应用程序启动的第一个Activity,因此根Activity的启动过程一般情况下也可以理解为应用程序的启动过程。普通Activity指的是除应用程序启动的第一个Activity之外的其他Activity。

根Activity的启动过程比较复杂,因此这里分为 3 个部分来讲,分别是 Launcher 请求 AMS 过程AMS 到 ApplicationThread 的调用过程ActivityThread 启动 Activity

1. Launcher 请求 AMS 过程

在Android系统中,Launcher的重要作用有两点:
(1)作为Android系统的启动器,用来启动应用程序。
(2)作为Android系统的桌面,用于显示和管理应用程序的快捷图标或者其他桌面组件。

当 Luancher 启动后会将已安装应用程序的快捷图标显示到桌面上,这些应用程序的快捷图标就是启动根Activity的入口,当我们点击某个应用程序的快捷图标时,就会通过 Launcher 请求 AMS 来启动该应用程序。Launcher 请求 AMS 的时序图如图所示:

《深入理解四大组件(一)Android8.0 根 Activity 的启动过程(上)》 Launcher请求AMS的时序图

当我们点击应用程序的快捷图标时,就会调用 Launcher 的 startActivitySafely 方法,如下所示:

packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        ···
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  //1
        if (v != null) {
            intent.setSourceBounds(getViewBounds(v));
        }
        try {
            if (Utilities.ATLEAST_MARSHMALLOW
                    && (item instanceof ShortcutInfo)
                    && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                     || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                    && !((ShortcutInfo) item).isPromise()) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // Could be launching some bookkeeping activity
                startActivity(intent, optsBundle);  //2
            } else {
                LauncherAppsCompat.getInstance(this).startActivityForProfile(
                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
            }
            return true;
        } catch (ActivityNotFoundException|SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
        }
        return false;
    }

在注释 1 处将 Flag 设置为 Intent.FLAG_ACTIVITY_NEW_TASK ,这样根 Activity 会在新的任务栈中启动,在注释 2 处会调用 startActivity 方法,这个 startActivity 方法在 Activity 中实现,如下所示:
frameworks/base/core/java/android/app/Activity.java

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

在 startActivity 方法中调用 startActivityForResult 方法,它的第二个参数为 -1,表示 Launcher 不需要知道 Activity 启动的结果,startActivityForResult 方法的代码如下所示:
frameworks/base/core/java/android/app/Activity.java

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {  //1
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            ···
        } else {
           ···
    }

注释 1 处的 mParent 是 Activity 类型的,表示当前 Activity 的父类。因为目前根 Activity 还没有创建出来,因此,mParent == null 成立。接着调用 InstrumentationexecStartActivity 方法,Instrumentation 主要用来监控应用程序和系统的交互,execStartActivity 方法的代码如下所示:
frameworks/base/core/java/android/app/Instrumentation.java

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        ···
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            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;
    }

首先调用 ActivityManager 的 getService 方法来获取 AMS 的代理对象,按着调用它的 startActivity 方法。这里与 Android 8.0 之前代码的逻辑有些不同,Android 8.0 之前是通过 ActivityManagerNative 的 getDefault 来获取 AMS 的代理对象的,现在这个逻辑封装到了 ActivityManager 中而不是 ActivityManagerNative 中。首先我们来查看 ActivityManager 的 getService 方法做了什么:
frameworks/base/core/java/android/app/ActivityManager.java

    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);  //1
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);  //2
                    return am;
                }
            };

getService 方法调用了 IActivityManagerSingleton 的 get 方法,我们接着往下看,IActivityManagerSingleton 是一个 Singleton 类。在注释 1 处得到名为 “activity” 的 Service 引用,也就是 IBinder 类型的 AMS 的引用。接着在注释 2 处将它转换成 IActivityManager 类型的对象,这段代码采用的是 AIDL,IActivityManager.java 类是由 AIDL 工具在编译时自动生成的,IActivityManager.aidl 的文件路径为 frameworks/base/core/java/android/app/IActivityManager.aidl。要实现进程间通信,服务器端也就是 AMS 只需要继承 IActivityManager.Stub 类并实现相应的方法就可以了。注意 Android 8.0 之前并没有采用 AIDL,而是采用了类似 AIDL 的形式,用 AMS 的代理对象 ActivityManagerProxy 来与 AMS 进行进程间通信,Android 8.0 去除了 ActivityManagerNative 的内部类 ActivityManagerProxy,代替它的是 IActivityManager,它是 AMS 在本地的代理。回到 Instrumentation 类的 execStartActivity 方法中,从上面得知 execStartActivity 方法最终调用的是 AMS 的 startActivity 方法。

2. AMS 到 ApplicationThread的调用过程

Luancher 请求 AMS 后,代码逻辑已进入 AMS 中,接着是 AMS 到 ApplicationThread 的调用流程,时序图如果所示:

《深入理解四大组件(一)Android8.0 根 Activity 的启动过程(上)》 AMS 到 ApplicationThread的调用过程的时序图

AMS 的 startActivity 方法如下所示:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

在 AMS 的 startActivity 方法中返回了 startActivityAsUser 方法,可以发现 startActivityAsUser 方法比 startActivity 方法多了一个参数 UserHandle.getCallingUserId(),这个方法会获得调用者的 UserId,AMS 根据这个 UserId 来确定调用者的权限。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @Override
    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) {
        //判断调用者进程是否被隔离
        enforceNotIsolatedCaller("startActivity");  //1
        //检查调用者权限
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);  //2
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }

在注释 1 处判断调用者进程是否被隔离,如果被隔离则抛出 SecurityException 异常,在注释 2 处检查调用者是否有权限,如果没有权限也会抛出 SecurityException 异常。最后调用了 ActivityStarter 的 startActivityLocked 方法,startActivityLocked 方法的参数要比 startActivityAsUser 多几个,需要注意的是倒数第二个参数类型为 TaskRecord,代表启动的 Activity 所在的栈。最后一个参数”startActivityAsUser” 代表启动的理由。startActivityLocked 方法的代码如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

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 globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {
         ...
        int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);
         ...
         return res;
     }
 }

ActivityStarter 是 Android 7.0 中新加入的类,它是加载 Activity 的控制类,会收集所有的逻辑来决定如何将 Intent 和 Flags 转换为 Activity,并将 Activity 和 Task 以及 Stack 相关联。ActivityStarter 的 startActivityMayWait 方法调用了 startActivityLocked 方法,如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
         String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
         IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
         IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
         String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
         ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
         ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
         TaskRecord inTask, String reason) {
     //判断启动的理由不为空
     if (TextUtils.isEmpty(reason)) { //1
         throw new IllegalArgumentException("Need to specify a reason.");
     }
     mLastStartReason = reason;
     mLastStartActivityTimeMs = System.currentTimeMillis();
     mLastStartActivityRecord[0] = null;
     mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
             aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
             callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
             options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
             container, inTask);
     if (outActivity != null) {
         outActivity[0] = mLastStartActivityRecord[0];
     }
     return mLastStartActivityResult;
 }

在注释 1 处判断启动的理由不为空,如果为空则抛出 IllegalArgumentException 异常。紧接着又调用了 startActivity 方法,如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
          String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
          IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
          IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
          String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
          ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
          ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
          TaskRecord inTask) {
      int err = ActivityManager.START_SUCCESS;
      final Bundle verificationBundle
              = options != null ? options.popAppVerificationBundle() : null;
      ProcessRecord callerApp = null;
      if (caller != null) {  //1
          //获取Launcher进程
          callerApp = mService.getRecordForAppLocked(caller);  //2
          if (callerApp != null) {
            //获取Launcher进程的pid和uid并赋值
              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;
          }
      }
      ...
      //创建即将要启动的Activity的描述类ActivityRecord
      ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
              callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
              resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
              mSupervisor, container, options, sourceRecord);
      if (outActivity != null) {
          outActivity[0] = r;  //3
      }
      ...
          doPendingActivityLaunchesLocked(false);
          return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
              options, inTask, outActivity);  //4
  }

ActivityStarter 的 startActivity 方法逻辑比较多,这里列出部分我们需要关心的代码。在注释 1 处判断 IApplicationThread 类型的 caller 是否为 null,这个 caller 是方法调用一路传过来的,指向的是 Launcher 所在的应用程序的 ApplicationThread 对象,在注释 2 处调用 AMS 的 getRecordForAppLocked 方法得到的是代表 Launcher 进程的 callerApp 对象,它是 ProcessRecord 类型的,ProcessRecord 用于描述一个应用程序进程。同样地,ActivityRecord 用于描述一个 Activity,用来记录一个 Activity 的所有信息。接下来创建 ActivityRecord,用于描述将要启动的 Activity,并在注释 3 处将创建的 ActivityRecord 赋值给 ActivityRecord [] 类型的 outActivity,这个 outActivity 会作为注释 4 处的 startActivity 方法的参数传递下去。
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        }
        ...
        return result;
    }

startActivity 方法紧接着调用了 startActivityUnchecked 方法:
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

  private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
  ...
 if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {  //1
            newTask = true;
            //创建新的TaskRecord
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);  //2
        } else if (mSourceRecord != null) {
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) {
            result = setTaskFromInTask();
        } else {
            setTaskToCurrentTopOrCreateNewTask();
        }
       ...
 if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
               ...
            } else {
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);  //3
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }
        ...
}

startActivityUnchecked 方法主要处理与栈管理相关的逻辑。根据上文中 startActivitySafely 方法我们得知,启动根 Activity 时会将 Intent 的 Flag 设置为 FLAG_ACTIVITY_NEW_TASK,这样注释 1 处的条件判断就会满足,接着执行注释 2 处的 setTaskFromReuseOrCreateNewTask 方法,其内部会创建一个新的 TaskRecord,用来描述一个 Activity 任务栈,也就是说 setTaskFromReuseOrCreateNewTask 方法内部会创建一个新的 Activity 任务栈。在注释 3 处会调用 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 方法,如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    //获取要启动的Activity所在栈的栈顶的不是处于停止状态的ActivityRecord
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();  //1
    if (r == null || r.state != RESUMED) {  //2
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);  //3
    } else if (r.state == RESUMED) {
        mFocusedStack.executeAppTransition(targetOptions);
    }
    return false;
}

在注释 1 处调用 ActivityStack 的 topRunningActivityLocked 方法获取要启动的 Activity 所在栈的栈顶的不是处于停止状态的 ActivityRecord。在注释 2 处,如果 ActivityRecord 不为 null,或者要启动的 Activity 的状态不是 RESUMED 状态,就会调用注释 3 处的 ActivityStack 的 resumeTopActivityUncheckedLocked 方法,对于即将启动的 Activity,注释 2 处的条件判断是肯定满足的,我们来查看 ActivityStack 的 resumeTopActivityUncheckedLocked 方法,如下所示:
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

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

紧接着查看注释1处 ActivityStack 的 resumeTopActivityInnerLocked 方法:
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
      ...
           mStackSupervisor.startSpecificActivityLocked(next, true, true);
       }
        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
       return true;
}

resumeTopActivityInnerLocked 方法代码非常多,我们只需要关注调用了 ActivityStackSupervisor 的 startSpecificActivityLocked 方法,代码如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

void startSpecificActivityLocked(ActivityRecord r,
           boolean andResume, boolean checkConfig) {
       //获取即将要启动的Activity的所在的应用程序进程
       ProcessRecord app = mService.getProcessRecordLocked(r.processName,
               r.info.applicationInfo.uid, true);  //1
       r.getStack().setLaunchTime(r);

       if (app != null && app.thread != null) {  //2
           try {
               if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                       || !"android".equals(r.info.packageName)) {
                   app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                           mService.mProcessStats);
               }
               realStartActivityLocked(r, app, andResume, checkConfig);  //3
               return;
           } catch (RemoteException e) {
               Slog.w(TAG, "Exception when starting activity "
                       + r.intent.getComponent().flattenToShortString(), e);
           }
       }
       mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
               "activity", r.intent.getComponent(), false, false, true);
   }

在注释 1 处获取即将启动的 Activity 所在的应用程序进程,在注释 2 处判断要启动的 Activity 所在的应用程序进程如果已经运行的话,就会调用注释 3 处的 realStartActivityLocked 方法,这个方法的第二个参数是代表要启动的 Activity 所在的应用程序进程 ProcessRecord。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
          boolean andResume, boolean checkConfig) throws RemoteException {
   ...
          app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                  System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                  new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                  task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                  newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
  ...      
      return true;
  }

这里的 app.thread 指的是 IApplicationThread,它的实现是 ActivityThread 的内部类 ApplicationThread,其中 ApplicationThread 继承了 IApplicationThread.Stub。app 指的是传入的要启动的 Activity 所在的应用程序进程,因此,这段代码指的就是要在目标应用程序进程启动 Activity。当前代码逻辑运行在 AMS 所在的进程(SystemServer 进程)中,通过 ApplicationThread 来与应用程序进程进行 Binder 通信,换句话说,ApplicationThread 是 AMS 所在进程(SystemServer 进程)和应用程序进程的通信桥梁,如图所示:

《深入理解四大组件(一)Android8.0 根 Activity 的启动过程(上)》 AMS 与应用程序进程通信

总结

本章我们学习了根 Activity 的启动过程的前两个部分,分别是 Launcher 请求 AMS 过程、 AMS 到 ApplicationThread 的调用过程,完成第二个部分后代码逻辑就运行在了应用程序进程中。

学习资料主要来源于《Android进阶解密》

    原文作者:Eren丶耶格尔
    原文地址: https://www.jianshu.com/p/50df72583e3e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞