Android笔记 - Android启动之Launcher启动

Posted demonyan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android笔记 - Android启动之Launcher启动相关的知识,希望对你有一定的参考价值。

android 启动的第三阶段是 Launcher 的启动,也就是最终会看到的 Android 桌面的启动。在之前第二阶段 Android启动之Android Framework启动中, Zygote, ServiceManager, ActivityManagerService 和 PackageManagerService 等系统服务已经启动起来,接下来的 Launcher 启动过程就会看到它们的身影。由于 Launcher 也是应用程序,因此其他应用程序的启动过程基本类似。
ActivityManagerService 在完成服务注册等一系列初始化过程后,其 main 方法中会调用 systemReady 方法,开始以下过程:

ActivityStackSupervisor::resumeTopActivitiesLocked()
ActivityStackSupervisor::resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions)
ActivityStack::resumeTopActivityLocked(ActivityRecord prev, Bundle options)
ActivityStackSupervisor::resumeHomeActivity(ActivityRecord prev)
ActivityManagerService::startHomeActivityLocked(int userId)

需要注意的是 Launcher 启动过程中, resumeTopActivityLocked 方法会进入两次,第一次由于任务栈中还没有 ActivityRecord,所以会调用 resumeHomeActivity 方法。
经历以上5个方法调用,最后进入 ActivityManagerService 的 startHomeActivityLocked 方法开始 Launcher 启动历程。首先通过 getHomeIntent 方法获得启动 Launcher 的 intent 信息,然后调用 resolveActivityInfo 方法通过 PackageManagerService 获得 Launcher 的 Activity 描述信息 aInfo。如下所示:

代码路径:frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

boolean startHomeActivityLocked(int userId) 
    ......
    Intent intent = getHomeIntent();
    ActivityInfo aInfo =
            resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) 
        intent.setComponent(new ComponentName(
                    aInfo.applicationInfo.packageName, aInfo.name));
        // Don't do this if the home app is currently being
        // instrumented.
        aInfo = new ActivityInfo(aInfo);
        aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
        ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
        if (app == null || app.instrumentationClass == null) 
            intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
            mStackSupervisor.startHomeActivity(intent, aInfo);
        
    

    return true;


Intent getHomeIntent() 
    Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
    intent.setComponent(mTopComponent);
    if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) 
            intent.addCategory(Intent.CATEGORY_HOME);
    
    return intent;

从 getHomeIntent 方法的实现可知,理论上通过在应用程序的 AndroidManifest.xml 文件中添加 Intent.CATEGORY_HOME 的 Category 属性,应用就可以作为 Launcher 来启动。

获得参数 intent 和 aInfo 后,接下来调用 ActivityStackSupervisor 的 startHomeActivity 方法开始以下历程:

ActivityStackSupervisor::startHomeActivity(Intent intent, ActivityInfo aInfo)
ActivityStackSupervisor::startActivityLocked(...)
ActivityStackSupervisor::startActivityUncheckedLocked(...)
ActivityStack::startActivityLocked(...)
ActivityStackSupervisor::resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions)
ActivityStack::resumeTopActivityLocked(ActivityRecord prev, Bundle options)
ActivityStackSupervisor::startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig)

因为在上述步骤2中将会生成 Launcher 的 ActivityRecord 并添加到任务栈中,所以第二次进入 resumeTopActivityLocked 时,会调用 startSpecificActivityLocked 方法来启动 Launcher 的 Activity。由于 Launcher 是第一次运行,因此还没有创建好 Launcher 进程。在启动 Launcher 之前还需要创建一个新的进程,如下所示:

Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, null);

通过 Process 的 start 方法请求 Zygote 创建进程后,在新进程中开始执行 ActivityThread 的 main 方法。

代码路径:frameworks/base/core/java/android/app/ActivityThread.java

public static void main(String[] args) 
    ......

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) 
        sMainThreadHandler = thread.getHandler();
    

    AsyncTask.init();

    if (false) 
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    

    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");

main 方法中有很多值得说的知识点,但和 Launcher 启动有关的是执行 ActivityThread 的 attach 方法,该方法会调用代理类 ActivityManagerProxy 的 attachApplication 方法通知 ActivityManagerService 新进程已经启动成功,可以开始执行应用程序。传入的参数 mAppThread 是一个 ApplicationThread 类的 Binder 对象,用于之后进程间的通信。

Launcher 运行在新创建的进程,而 ActivityManagerService 运行在 system_server 进程,它们之间需要使用 Binder 来进行通信。

通过 Binder 进程间通信机制,ActivityManagerService 收到消息后,其 attachApplication 方法会被调用,接下来执行以下流程:

ActivityManagerService::attachApplicationLocked(IApplicationThread thread, int pid)
ApplicationThreadProxy::bindApplication(...)

通过之前传过来的 mAppThread 对象,调用代理类 ApplicationThreadProxy 的 bindApplication 方法。通过 Binder 通信,在 Launcher 进程中加载 Application 类并执行 onCreate 方法。这也说明,每个虚拟机进程中都会有一个 Application 实例。
接下来继续启动 Activity:

ActivityStackSupervisor::attachApplicationLocked(ProcessRecord app, boolean headless)
ActivityStackSupervisor::realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig)
ApplicationThreadProxy::scheduleLaunchActivity(...)

通过之前传过来的 mAppThread 对象,调用代理类 ApplicationThreadProxy 的 scheduleLaunchActivity 方法。通过 Binder 通信,最终会执行 ActivityThread 中的 handleLaunchActivity 方法,如下所示:

代码路径:frameworks/base/core/java/android/app/ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) 
    ......
    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) 
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);

        ......
    

handleLaunchActivity 中会加载 Launcher 应用程序的 class 文件,并调用 Activity 的 onCreate, onStart, onResume 等生命周期回调方法。
Launcher Activity 的 onCreate 方法中会初始化一个 Load 线程,用于加载所有的 workspace 数据以及应用程序图标。过程如下所示:

LauncherModel::startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags)
LoaderTask::run()
LauncherModel::loadAndBindWorkspace()
LauncherModel::loadAndBindAllApps()

loadAndBindWorkspace 主要可分为 load 和 bind 两个阶段,load 阶段由 loadWorkspace 方法完成,主要是遍历数据库,生成 FolderInfo, LauncherAppWidgetInfo, ShortcutInfo 对象。bind 阶段由 bindWorkspace 方法完成,主要将之前得到的对象与 workspace 进行绑定。
loadAndBindAllApps 也分为 load 和 bind 两个阶段,load 阶段主要通过 PackageManagerService 提供的服务查询所有应用程序的 AppInfo 数据,bind 阶段则根据 AppInfo 在桌面显示应用程序。
至此,Android 启动流程梳理完毕。由于篇幅原因,中间有些内容点到为止,后续文章再继续完善。

参考资料:
1. Android系统默认Home应用程序(Launcher)的启动过程源代码分析
2. Launcher3的启动流程(一)
3. Launcher3的启动流程(二)

以上是关于Android笔记 - Android启动之Launcher启动的主要内容,如果未能解决你的问题,请参考以下文章

Android笔记 - Android启动之Android Framework启动

Android学习笔记之Intent

Android学习笔记之Intent

深入浅出Android之学习笔记

Android学习笔记之AndroidManifest.xml文件解析

Android笔记 - Binder之守护进程servicemanager