Android系统启动-Launcher进程

本次源码基于Android11分析

相关源码:

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
/packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
/packages/apps/Launcher3/src/com/android/launcher3/LauncherModel.java
/packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java

在前面文章中分别讲解了在SystemServer进程startBootstrapServices()、startOtherServices()方法中启动了ActivityManagerService(ActivityTaskManagerService)PackageManagerService系统服务。

  1. ActivityManagerService:主要负责四大组件的创建和管理。
  2. PackageManagerService:主要负责安装包的查询、安装、卸载。

系统的桌面进程Launcher就是在ActivityManagerService服务启动完成后开始启动。

Launcher进程启动

ActivityManagerService.systemReady方法中开始了Launcher进程的启动

public class ActivityManagerService extends IActivityManager.Stub
      implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

  // mAtmInternal为ActivityTaskManagerService.LocalService类
  public ActivityTaskManagerInternal mAtmInternal;

  // ActivityManagerService准备完成
  public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {

      // 调用启动Launcher进程
      mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
  }
}

public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
  RootWindowContainer mRootWindowContainer;

  final class LocalService extends ActivityTaskManagerInternal {
      @Override
      public boolean startHomeOnAllDisplays(int userId, String reason) {
          synchronized (mGlobalLock) {
              return mRootWindowContainer.startHomeOnAllDisplays(userId, reason);
          }
      }

  }
}
  1. 在AMS的systemReady方法中启动Launcher进程,但并没有真正的启动进程,这只是一个开始,而后给ActivityTaskManagerService.LocalService类的startHomeOnAllDisplays方法继续执行。
  2. 在ActivityTaskManagerService中并没有做处理,而是调用了RootWindowContainer.startHomeOnAllDisplays方法处理。

RootWindowContainer.startHomeOnAllDisplays通过一系列的调用最终调用到RootWindowContainer.startHomeOnTaskDisplayArea方法:

class RootWindowContainer extends WindowContainer<DisplayContent>
      implements DisplayManager.DisplayListener {

  ActivityTaskManagerService mService;

  boolean startHomeOnAllDisplays(int userId, String reason) {
      boolean homeStarted = false;
      // getChildCount获取显示设备数目,这个主要从mChildren参数中获取对应的数量
      // mChildren是一个WindowList的一个对象,其包含的数据是在setWindowManager函数被调用时,从DisplayManagerService中获取到的Display的数目
      for (int i = getChildCount() - 1; i >= 0; i--) {
          // 获取到对应新建的DisplayContent的displayId
          final int displayId = getChildAt(i).mDisplayId;
          // 调用startHomeOnDisplay函数
          homeStarted |= startHomeOnDisplay(userId, reason, displayId);

      }
      return homeStarted;

  }
  //一系列调用最终调用startHomeOnTaskDisplayArea.......

  boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea,
                                     boolean allowInstrumenting, boolean fromHomeKey) {
      // Fallback to top focused display area if the provided one is invalid.
      if (taskDisplayArea == null) {
          final ActivityStack stack = getTopDisplayFocusedStack();
          taskDisplayArea = stack != null ? stack.getDisplayArea()
                  : getDefaultTaskDisplayArea();
      }

      Intent homeIntent = null;
      ActivityInfo aInfo = null;
      if (taskDisplayArea == getDefaultTaskDisplayArea()) {
          // 1.向ActivityTaskManagerService获取 Launcher 的启动意图
          homeIntent = mService.getHomeIntent();
          //2. 向PackageManagerService通过意图解析到 ActivityInfo
          aInfo = resolveHomeActivity(userId, homeIntent);
      } else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
          Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
          aInfo = info.first;
          homeIntent = info.second;
      }
      if (aInfo == null || homeIntent == null) {
          return false;
      }

      if (!canStartHomeOnDisplayArea(aInfo, taskDisplayArea, allowInstrumenting)) {
          return false;
      }

      // Updates the home component of the intent.
      homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
      homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
      // Updates the extra information of the intent.
      if (fromHomeKey) {
          homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
          mWindowManager.cancelRecentsAnimation(REORDER_KEEP_IN_PLACE, "startHomeActivity");
      }
      // Update the reason for ANR debugging to verify if the user activity is the one that
      // actually launched.
      final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
              aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId();

      // 根据homeIntent、aInfo,调用 startHomeActivity 方法去启动和创建 Launcher
      mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
              taskDisplayArea);
      return true;
  }

  // 根据Intent的Component向PackageManagerService找到对应的ActivityInfo
  ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
      final int flags = ActivityManagerService.STOCK_PM_FLAGS;
      final ComponentName comp = homeIntent.getComponent();
      ActivityInfo aInfo = null;
      try {
          if (comp != null) {
              // Factory test.
              aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
          } else {
              final String resolvedType =
                      homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
              final ResolveInfo info = AppGlobals.getPackageManager()
                      .resolveIntent(homeIntent, resolvedType, flags, userId);
              if (info != null) {
                  aInfo = info.activityInfo;
              }
          }
      } catch (RemoteException e) {
          // ignore
      }

      if (aInfo == null) {
          Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
          return null;
      }

      aInfo = new ActivityInfo(aInfo);
      aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
      return aInfo;
  }

}



public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
  String mTopAction = Intent.ACTION_MAIN;
  String mTopData;

  // homeIntent.action = Intent.ACTION_MAIN   ACTION_MAIN = "android.intent.action.MAIN"
  // homeIntent的flags包含Intent.FLAG_DEBUG_TRIAGED_MISSING
  // homeIntent的category包含Intent.CATEGORY_HOME  CATEGORY_HOME = "android.intent.category.HOME";
  Intent getHomeIntent() {
      Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
      intent.setComponent(mTopComponent);
      intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
      if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
          intent.addCategory(Intent.CATEGORY_HOME);
      }
      return intent;
  }

}

代码很长,但不外乎做了两件事:

  • 调用ActivityTaskManagerService.getHomeIntent方法获取Intent意图
  • 根据意图Intent.Component向PackageManagerService查询对应的ActivityInfo
    最后,通过ActivityStartController.startHomeActivity方法,通过层层调用最后调用Process.start方法去启动和创建Launcher。关于后面进程的创建和Activity的启动后面文章讲解,本篇继续分析Launcher启动后如何查询所有App信息

Launcher查询App信息

LauncherActivity中,会在onCreate方法去查询所有App信息:

public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
      Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {

  @Override
  protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      // 实例化LauncherAppState
      LauncherAppState app = LauncherAppState.getInstance(this);
      // 根据LauncherAppState获取到LauncherModel
      mModel = app.getModel();

      // LauncherModel.addCallbacksAndLoad就会去查询App信息
      if (!mModel.addCallbacksAndLoad(this)) {
          if (!internalStateHandled) {
              // If we are not binding synchronously, show a fade in animation when
              // the first page bind completes.
              mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
          }
      }

  }
}

在onCreate中通过调用LauncherModel.addCallbacksAndLoad去查询App信息,此方法通过一个Handler去执行一个Runnable去执行查询任务。

public class LauncherModel extends LauncherApps.Callback implements InstallSessionTracker.Callback {

  // Launcher也实现了Callbacks
  public boolean addCallbacksAndLoad(Callbacks callbacks) {
      synchronized (mLock) {
          // 将Launcher加入到回调列表
          addCallbacks(callbacks);
          // 调用startLoader()
          return startLoader();
      }
  }

  public boolean startLoader() {
      synchronized (mLock) {
          //.....
          stopLoader();
          LoaderResults loaderResults = new LoaderResults(
                  mApp, mBgDataModel, mBgAllAppsList, callbacksList, mMainExecutor);
          // 开始查询App信息
          startLoaderForResults(loaderResults);
          return false;
      }
  }

  public void startLoaderForResults(LoaderResults results) {
      synchronized (mLock) {
          stopLoader();
          // LoaderTask是一个Runnable
          mLoaderTask = new LoaderTask(mApp, mBgAllAppsList, mBgDataModel, results);

          // Handler去执行LoaderTask
          MODEL_EXECUTOR.post(mLoaderTask);
      }
  }

}

通过对重点代码的查看,LauncherModel只是发送了一个LoaderTask的Runnable让Handler去执行。所以查询App在LoaderTask类的run()方法中。

public class LoaderTask implements Runnable {

  public void run() {
      //.....

      // 加载所有App
      List<LauncherActivityInfo> allActivityList = loadAllApps();

      //.....
  }
  
  // 查询所有App
  private List<LauncherActivityInfo> loadAllApps() {
      final List<UserHandle> profiles = mUserCache.getUserProfiles();
      List<LauncherActivityInfo> allActivityList = new ArrayList<>();
      // Clear the list of apps
      mBgAllAppsList.clear();
      for (UserHandle user : profiles) {
          // Query for the set of apps
          final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
          // Fail if we don't have any apps
          // TODO: Fix this. Only fail for the current user.
          if (apps == null || apps.isEmpty()) {
              return allActivityList;
          }
          //....
          allActivityList.addAll(apps);
      }
      //.....
      return allActivityList;
  }


}

public class LauncherApps {

  public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
      logErrorForInvalidProfileAccess(user);
      try {
          return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
                  packageName, user), user);
      } catch (RemoteException re) {
          throw re.rethrowFromSystemServer();
      }
  }
}

LoaderTask的run的方法会查询所有App的信息。

总结

Launcher是系统的桌面进程,它是由ActivityManagerService完成准备后开始启动的,启动的时候会通过向ActivityManagerService获取Intent意图和向PackageManagerService获取对应ActivityInfo。Launcher Activity启动后会向在onCreate()方法中查询所有App信息。

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

推荐阅读更多精彩内容