草庐IT

Android系统启动-Launcher进程

isLJli 2023-03-28 原文

本次源码基于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信息。

有关Android系统启动-Launcher进程的更多相关文章

  1. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  2. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  3. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  4. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  5. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  6. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  7. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  8. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  9. ruby - 无法在 Ruby 中将 ffmpeg 作为子进程运行 - 2

    我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope

  10. Ruby 守护进程导致 ActiveRecord 记录器 IOError - 2

    我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame

随机推荐