4 ActivityManagerService(二)App启动流程之启动准备

所有代码均来自Android 11

App的启动流程是AMS 中非常重要的一个环节,也是在面试过程中经常被问到的一个知识点,想要理解并记住就需要对他的整个过程有一个整体的概念,这个整体的概念大致如下

1.任务封装:使用 启动App 其实就是startActivity 的过程 , 在ActivityTaskManagerService 会将这个任务做一个整体的封装,将所有参数封装成一个Request ,

startActivity开始,ContextImpl 使用 ActivityThread 获取到 Instrumentation ,使用Instrumentation 将任务调度给 ActivityTaskManagerService , 这里有一个非常重要的参数,

Instrumentation execStartActivity

  public ActivityResult execStartActivity(
          Context who, IBinder contextThread, IBinder token, Activity target,
          Intent intent, int requestCode, Bundle options) {
      IApplicationThread whoThread = (IApplicationThread) contextThread;
      Uri referrer = target != null ? target.onProvideReferrer() : null;
      try {
          intent.migrateExtraStreamToClipData(who);
          intent.prepareToLeaveProcess(who);
          int result = ActivityTaskManager.getService().startActivity(whoThread,
                  who.getBasePackageName(), who.getAttributionTag(), 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;
  } 

可以看到这里在一个叫 token 的IBinder 的参数,他有什么用呢,这就需要知道 Activity 的任务管理都是 ActivityTaskManagerService 中完成的,想要收到 ATMS 的处理结果并配合做生命周期动作就需要跨进程通信,那么这个token就是为后期做跨进程通信,那么这个IBinder是谁呢,就是在ActivityThread 的成员变量 ApplicationThread ,他就是一个IInterface.Stub

ATMS startActivityAsUser

  private int startActivityAsUser(IApplicationThread caller, String callingPackage,
          @Nullable String callingFeatureId, Intent intent, String resolvedType,
          IBinder resultTo, String resultWho, int requestCode, int startFlags,
          ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
      assertPackageMatchesCallingUid(callingPackage);
      enforceNotIsolatedCaller("startActivityAsUser");

      userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
              Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

      // TODO: Switch to user app stacks here.
      return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
              .setCaller(caller)
              .setCallingPackage(callingPackage)
              .setCallingFeatureId(callingFeatureId)
              .setResolvedType(resolvedType)
              .setResultTo(resultTo)
              .setResultWho(resultWho)
              .setRequestCode(requestCode)
              .setStartFlags(startFlags)
              .setProfilerInfo(profilerInfo)
              .setActivityOptions(bOptions)
              .setUserId(userId)
              .execute();

  }

这里将上面说的token 放到了caller 的属性上,通过这个caller 就能实现跨进程通信,通过上面代码可以看到 ATMS 通过一个 StartController 将所有请求任务封装成了 ActivityStarter , 并执行了他的 execute 方法,这里也使用到了与MessageQueue 获取消息同样的方法,查看了一下他的代码,实现效果是一致的

在ActiviteStarter 的 execute 方法里面 通过 mRootWindowContainer ,每个window 都会放入到这里, 从后向前遍历找到第一个正在Focused ActivityStack,为他做一个标记,具体方法如下

ActiviteStarter execute

              final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();
              if (stack != null) {
                  stack.mConfigWillChange = globalConfigWillChange;
              }

然后继续执行 将 封装好的 request 放入 execute 中
再接下来有做了很多的判断,被请求的activity 是否在 ActivtyStack 中, 请求这是否有权限,等等的处理,还需要判断启动队列里面是否有正在启动的activity ,如果有他就等待while(正在启动队列是否为空),没有就继续执行来到了 ActivityStarter startActivityInner 的这个方法

ActivityStarter startActivityInner

这个方法中先初始化了启动模式,并计算一下他的启动模式

     computeLaunchingTaskFlags();

      computeSourceStack();

然后根据lanuchMode 判断是否需要新建task,
如果不是新栈就调用 recycleTask 判断返回状态

是新栈就向RootWindowContainer中添加一个黑白屏 来到 RootWindowContainer 的resumeFocusedStacksTopActivities 方法

RootWindowContainer 的resumeFocusedStacksTopActivities

由于我们刚刚给 RootWindowContainer 添加了一个window,那么这个window在 RootWindowContainer 中是存在的,就来到了

ActivityStarter resumeTopActivityUncheckedLocked 做标记继续向下

ActivityStarter resumeTopActivityUncheckedLocked 在这里判断进程是否存在

if (next.attachedToProcess())

虽然我们启动了黑白屏,但是进程是不存在的接着就来到了 ActivityStackSupervisor startSpecificActivity

ActivityStackSupervisor startSpecificActivity

到了这里终于要创建进程了

  void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
      // Is this activity's application already running?
      final WindowProcessController wpc =
              mService.getProcessController(r.processName, r.info.applicationInfo.uid);

      boolean knownToBeDead = false;
      if (wpc != null && wpc.hasThread()) {
          try {
              realStartActivityLocked(r, wpc, andResume, checkConfig);
              return;
          } catch (RemoteException e) {
              Slog.w(TAG, "Exception when starting activity "
                      + r.intent.getComponent().flattenToShortString(), e);
          }

          // If a dead object exception was thrown -- fall through to
          // restart the application.
          knownToBeDead = true;
      }

      r.notifyUnknownVisibilityLaunchedForKeyguardTransition();

      final boolean isTop = andResume && r.isTopRunningActivity();
      mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
  }

由于进程不存在,需要通过 ATMS 来调用 startProcessAsync 方法

ATMS startProcessAsync

  void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
          String hostingType) {
      try {
          if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
              Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"
                      + activity.processName);
          }
          // Post message to start process to avoid possible deadlock of calling into AMS with the
          // ATMS lock held.
          final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
                  mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
                  isTop, hostingType, activity.intent.getComponent());
          mH.sendMessage(m);
      } finally {
          Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
      }
  }

看他上面的注释, 发送一个启动进程的消息, 这里需要注意的是 ActivityManagerInternal::startProcess 他是一个函数, 而且还是 AMS 的内部类 LocalService 所持有的,这样启动进程的流程就来到了AMS

AMS LocalService startProcess ---> AMS LocalService startProcessLocked -->

上面都是数据传递

mProcessList.startProcessLocked

这里再说一下 AMS 是如何管理进程的,他与进程是如何通信的 , 在AMS 中 有一个 mProcessList 进程列表,他管理着所有进程,每一个进程都被封装到 ProcessState 当中,这个进程的管理使用的LRU 的方式, 每一个Process 里面都有一个 IApplicationThread thread; 也就是 ApplicationThread ,AMS 就是通过他来与 app 进程通信

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容