Android问道--系统启动的流程

 

Android系统启动流程

Android启动和Android的很多系统组件相关联,如应用启动流程,四大组件的原理,AMS,ClassLoager

Android系统中用户空间启动的第一个进程是init,进程号为1

init进程是Android系统启动的一个关键步骤,有很多重大职责,init是多个源文件共同组成的,文件位于源码system/core/init

Android启动流程前几步

  1. 启动电源和系统启动

    当电源按下后引导芯片代码从ROM开始执行,加载BootLoader到RAM中

  2. 引导程序BootLoader

    作用为拉起系统OS并运行

  3. Linux内核启动

    完成内核系设置(设置缓存,被保护存储器,计划列表,加载驱动)后,寻找init.rc文件,启动init进程

  4. init进程启动

    初始化和启动属性服务

init的main函数

位于system/core/init/init.cpp

作用:

  • 在开始的时候创建和挂载启动所需的文件目录
  • property_init属性初始化
  • start_property_servic启动属性服务
  • signal_handler_init设置子信号处理函数,用来防止init进程的子进程变成僵尸进程,系统在子进程暂停和终止的时候发出SIGCHLD信号,signal_handler_init函数就是接收该信号的.如果init的子进程停止了,该函数还可以通过调用handle_signal函数来移除僵尸进程和保活

什么是init.rc

是一个配置文件,由Android Init Language编写的脚本,路径位于system/core/rootdir

该脚本由5种类型的语句组成

  • action行动
  • command命令
  • service服务
  • option操作
  • import导入

举例

init.rc

on init
    sysclktz 0

    # Mix device-specific information into the entropy pool
    copy /proc/cmdline /dev/urandom
    copy /system/etc/prop.default /dev/urandom

    symlink /proc/self/fd/0 /dev/stdin
    symlink /proc/self/fd/1 /dev/stdout
    symlink /proc/self/fd/2 /dev/stderr

    # Create energy-aware scheduler tuning nodes
    mkdir /dev/stune/foreground
    mkdir /dev/stune/background
    mkdir /dev/stune/top-app
    mkdir /dev/stune/rt

其中on init 是action类型的语句

on <触发器>

<触发以后执行的命令>

init.zygote64.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

这一段是service类型的语句

service <执行程序路径> <执行参数>

<对于service的修饰,影响什么时候,如何启动service>

这一段service的含义为通知init创建名为zygote的进程

属性服务

类似Windows平台上的注册表管理器,注册表的内容使用键值对记录使用信息,这样的话电脑重启后还能根据注册表记录进行初始化工作

init进程启动时会启动属性服务,并且给属性服务分配内存,用来存储属性

system/core/init/property_service.cppproperty_init方法中使用__system_property_area_init()方法来初始化属性内存区域

start_property_service方法中创建了一个非阻塞的socket

  property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                    0666, 0, 0, NULL);

同时也使用listen(property_set_fd, 8);对创建出来是socket进行监听

这样创建的Socket就成为了server,也就是属性服务listen函数的第二个参数为8.意味着可以同时为8个想要设置属性的用户提供服务

使用register_epoll_handler(property_set_fd, handle_property_set_fd);将该server放入了epoll中,使用epoll来监听socket,当数据到来的时候,init进程会调用handle_property_set_fd来进行处理

tips:新的linux内核中,epoll是用来替换select的,是linux内核为了处理大批量的文件描述符进行改进的poll,是一个多路复用的IO接口poll的增强版,epoll显著提高了程序在大量并发连接中只有少量活跃情况下的CPU使用率

handle_property_set_fd函数的作用:

  • Android7中只是用来处理客户端请求
  • Android8中的源码添加了 handle_property_set(socket, prop_value, prop_value, true);来做进一步封装处理

handle_property_set函数功能:

  • 检查系统属性的种类( if (android::base::StartsWith(name, "ctl.")) 如果以ctl.开头就是控制属性)
  • 检查客户端权限
  • 设置控制属性

系统属性分为两种类型,一种是普通属性,一种是控制属性,控制属性用来执行一些命令,开机动画就是使用了控制属性

之后调用property_set函数,该函的作用为

  • 判断属性是否合法 if (!is_legal_property_name(name))
  • 从属性存储空间查找该属性prop_info* pi = (prop_info*) __system_property_find(name.c_str());
  • 如果属性存在并且不是以ro.开头(只读)android::base::StartsWith(name, "ro.")
  • 属性存在就更新数值__system_property_update(pi, value.c_str(), valuelen)
  • 属性如何不存在就添加属性int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen)
  • 如果属性是persist.开头,进行相应处理 write_persistent_property(name.c_str(), value.c_str());

init启动总结

  • 创建和挂载启动所需的文件目录
  • 初始化和启动属性服务
  • 解析init.rc配置文件并启动Zygote进程

Zygote进程启动过程

Zygote是init进程启动时创建的进程

什么是Zygote

DVM或ART,应用程序进程和系统关键服务的ServiceServer进程都是由Zogote来进行创建的,所以Zygote也叫孵化器,通过fock(复制)命令来创建应用程序进程和SystemServer进程

Zygote进程启动的时候会创建DVM或ART,所以fock创建出来的进程可以在内部获取一个DVM或ART的副本

Zygote启动脚本

路径位于system/core/rootdir

在init.rc中使用Import来引入Zygote启动脚本import /init.${ro.zygote}.rc,这些脚本也同样是Android Init Languare编写的

init.rc并没有直接引用一个固定的文件,是根据属性ro.zygote的内容来引用不同的文件,这里使用ro.zygote属性是是用来控制使用不用的zygote脚本,多个脚本主要是分为32位环境和64位环境的区别,一共有4个init.zygote.rc文件

四个文件分别是init.zygote32.rc仅支持32位模式 init.zygote32_64.rc主模式为32位,辅模式为64位 init.zygote64.rc仅支持64位 init.zygote64_32.rc主模式为64位,辅模式为32位

双模式下的脚本会启动两个Zygote进程,一个作为主模式,一个是辅模式

Zygote启动过程

init启动Zygote主要是调用app_main.cpp的main函数中的AppRuntime的start方法来启动的

app_main.cpp位于frameworks/base/cmds/app_process

Zygote是通过fock自身来创建子进程的,所以Zygote和他的子线程都能执行app_main.cpp的main函数,所以在main函数中要区分当前运行在哪个进程,会执行以下判断

if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }	

后续会判断zygote变量的值,如果==true就会执行runtime.start("com.android.internal.os.ZygoteInit", args, zygote);进行AppRuntime的start

runtime.start会调用位于frameworks/base/core/jniAndroidRuntime.cpp中的void AndroidRuntime::start方法,这个方法拉起了JVM,从C++层到了Java层,整体流程为

  • startVm(&mJavaVM, &env, zygote) 启动JVM虚拟机
  • startReg(env) 为虚拟机注册JNI方法
  • classNameStr = env->NewStringUTF(className); 得到className 也就是ZygoteInit对应的包名路径,即调用runtime.start方法时传递的第一个参数
  • char* slashClassName = toSlashClassName(className); 将className路径的.替换为/
  • jclass startClass = env->FindClass(slashClassName);找到ZygoteInit
  • jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V"); 找到ZygoteInit类的main方法
  • env->CallStaticVoidMethod(startClass, startMeth, strArray); 使用JNI调用ZygoteInit的main方法

这里调用到了ZygoteInit的main方法,ZygoteInit.java这个文件位于frameworks/base/core/java/com/android/internal/os

ZygoteInit的main主要做了四件事

  • 创建了一个Server端的Socket zygoteServer.registerServerSocket(socketName);该服务端用于等待AMS(ActivityManagerService)请求Zygote创建新的Application进程

    • 调用registerServerSocket同级目录的ZygoteService.java方法首先拼接了Socket的名称 final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
    • 得到Socket的环境变量值 String env = System.getenv(fullSocketName);
    • 将环境变量转化为FD文件描述符的参数 fileDesc = Integer.parseInt(env);
    • 创建文件描述符对象并设置参数FileDescriptor fd = new FileDescriptor();fd.setInt$(fileDesc);
    • 创建服务端socket mServerSocket = new LocalServerSocket(fd);
    • 等SystemServer进程启动后,会在这个服务端的Socket上等待AMS请求创建新的Application进程
  • 预加载类和资源 preload(bootTimingsTraceLog);

  • 启动SystemServer进程,系统服务会由SystemServer进程启动 startSystemServer(abiList, socketName, zygoteServer);

    • startSystemServer方法中首先创建了args数组用来保存启动SystemSystem的启动参数

      String args[] = {
      			//用户ID
                  "--setuid=1000", 
          		//用户组ID
                  "--setgid=1000",
          		//所拥有的用户组
                  "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
                  "--capabilities=" + capabilities + "," + capabilities,
          		//进程的代号
                  "--nice-name=system_server",
                  "--runtime-args",
          		//启动的类名
                  "com.android.server.SystemServer",
              };
      
    • 将args数组封装为Arguments对象 parsedArgs = new ZygoteConnection.Arguments(args);

    • 调用Zygote的复制systemServer方法 pid = Zygote.forkSystemServer(),内部会调用naviteForkSystemServer这个JNI方法来创建一个SystemServer子进程

    • 如果得到的pid为0,就证明当前运行在子线程里面,就进行相应的校正

       if (pid == 0) {
                  if (hasSecondZygote(abiList)) {
                      waitForSecondaryZygote(socketName);
                  }
          
                  zygoteServer.closeServerSocket();
                  handleSystemServerProcess(parsedArgs);
              }
      
  • 等待AMS请求创建新的Application进程zygoteServer.runSelectLoop(abiList);

    • 将registerServerSocket注册出来的socket的文件描述符字段添加到fds列表中fds.add(mServerSocket.getFileDescriptor());
    • 使用无限循环等待AMS的消息
    • 通过遍历将fds复制到pollFds中StructPollfd[] pollFds = new StructPollfd[fds.size()];for (int i = 0; i < pollFds.length; ++i)
    • 对pollFds进行遍历for (int i = pollFds.length - 1; i >= 0; --i)
    • 之后判断if (i == 0) 说明Zygote和AMS建立了连接
    • 通过acceptCommandPeer得到了ZygoteConnection 的实例,并且添加到了连接列表peers中ZygoteConnection newPeer = acceptCommandPeer(abiList);peers.add(newPeer);
    • ZygoteConnection的文件描述符添加到fds中,使他能接收到AMS发送来的请求
    • 如果判断if (i != 0) 说明AMS向Zygote发送了创建应用进程的请求
    • 调用ZygoteConnection的runOnce函数来创建一个新的应用程序进程 boolean done = peers.get(i).runOnce(this);
    • 创建成功后将该连接从列表中销毁peers.remove(i);fds.remove(i);

Zygote进程启动总结

Zygote进程启动做了如下几件事

  • 创建AppRuntime并调用start方法,启动Zygote进程
  • 创建JVM并为JVM注册JNI方法
  • 通过JNI调用ZygoteInit的Main函数进入Zygote的Java框架
  • 使用registerZygoteSocket创建服务端Socket,并使用runSelectLoop方法等待AMS的请求来创建新的Application
  • 启动SystemServer进程

SystemServer的处理过程

SystemServer进程主要用于创建系统服务,AMS,WMS(WindowManagerService),PMS(PackageManagerService)都是由其创建的

SystemServer是由Zygote启动和处理的,在ZygoteInit.java中startSystemServer启动了SystemServer进程

SystemServer进程复制于Zygote进程,因此也得到Zygote进程创建的Socket,该Socket对SystemServer进程无用,所以关闭该Socket,然后调用handleSystemServerProcess来启动SystemServer进程

handleSystemServerProcess中创建了PathClassLoadercl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);,然后执行了ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);

在ZygoteInit方法中,调用了nativeZygoteInit方法,这是一个JNI函数,调用CPP层启动了Binder线程池,这样SystemServer进程就可以使用Binder和其他进程通信了,之后使用RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);进入了SystemServer的Main方法

启动Binder线程池

nativeZygoteInit是一个Native方法,他对应的JNI文件位于frameworks/base/core/jni/AndroidRuntime.cpp

以下代码让我们知道nativeZygoteInit方法对应的是com_android_internal_os_ZygoteInit_nativeZygoteInit这个C++函数

int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

com_android_internal_os_ZygoteInit_nativeZygoteInit这个函数只执行了一段代码 gCurRuntime->onZygoteInit();

gCurRuntime的类型是AndroidRuntime* (AndroidRuntime指针) 具体是指向了AndroidRuntime的子类AppRuntime,这个对象在app_main.cpp中定义,在onZygoteInit()函数中主要是执行了proc->startThreadPool();启动了一个Binder进程池

进入SystemServer的main方法

ZygoteInit中启动了Binder线程池后,紧接着就进入了SystemServer RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);

RuntimeInit类位于frameworks/base/core/java/com/android/internal/os

applicationInit方法中主要调用了invokeStaticMain(args.startClass, args.startArgs, classLoader);方法

  1. 通过反射得到了SystemServer的实例cl = Class.forName(className, true, classLoader);

  2. 找到System的SystemServer的Main方法m = cl.getMethod("main", new Class[] { String[].class });

  3. 抛出异常throw new Zygote.MethodAndArgsCaller(m, argv);这个异常如果发生,位于ZygoteInit的Main方法会捕捉错误,然后执行run,需要这样做的原因是抛出异常的处理会清除所有设置过程需要的堆栈帧,让SystemServer的main方法看起来像是SystemServer进程的入口方法.Zygote启动SystemServer进程后,SystemServer已经做了很多的工作,这些工作都是调用main方法前做的

    catch (Zygote.MethodAndArgsCaller caller) {
                caller.run();
            }
    

MethodAndArgsCaller是Zygote类的静态内部类,在该类的run方法中,主要执行mMethod.invoke(null, new Object[] { mArgs });

调用了invoke方法,SystemServer的main方法就会被动态调用,然后成功进入main方法中

解析SystemServer进程

SystemServer类位于frameworks\base\services\java\com\android\server

在main方法中,只执行了new SystemServer().run();创建了一个新的SystemServer实例,并调用run方法

run方法的流程

  1. 创建消息Looper Looper.prepareMainLooper();
  2. 加载动态库System.loadLibrary("android_servers");
  3. 创建系统ContextcreateSystemContext();
  4. 启动引导服务(ActivityManagerService,PowerManagerService,PackageManagerService)startBootstrapServices();
  5. 启动核心服务(DropBoxManagerService日志相关,BatteryService,UsageStateService,WebViewUpdateService)startCoreServices();
  6. 启动其他服务(CameraService,AlarmManagerService,VrManagerService)startOtherServices();

官方将系统服务分成了三种类型,分别是引导服务,核心服务其他服务,这些服务的父类都是SystemService

这些系统服务的启动逻辑都是相似的,使用PowerManagerService来举例说明

使用mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);来启动该服务

mSystemServiceManager是SystemServiceManager的实例,该类位于frameworks\base\services\core\java\com\android\server调用该类中的startService方法

public void startService(@NonNull final SystemService service) {
        // 注册Service,将service添加到了存储SystemService类型的ArrayList
        mServices.add(service);
        long time = System.currentTimeMillis();
        try {
			//启动Service,
            service.onStart();
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        }
        warnIfTooLong(System.currentTimeMillis() - time, service, "onStart");
    }

除了这种方法启动,也可以通过直接调用Service的main函数来启动服务,以PackageManagerService为例,其启动服务是执行了mPackageManagerService = PackageManagerService.main(mSystemContext, installer,mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);

PackageManagerService位于frameworks\base\services\core\java\com\android\server\pm

public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // 自检初始设置
        PackageManagerServiceCompilerMapping.checkProperties();
		//创建PackageManagerService实例
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserPackages();
    	//将PackageManagerService的实例注册到ServiceManager中
        ServiceManager.addService("package", m);
        return m;
    }

ServiceManager是用来管理系统中的各种System,用于系统C/S架构中的Binder通信机制,如果客户端要使用某个Service,就需先去ServiceManager查找相关信息,然后根据相关系信息和Service所在的进程建立通信,然后客户端就能使用Service了

SystemServer总结

  1. 启动Binder线程池,让线程之间能够通信
  2. 创建SystemServiceManager,用来对系统服务进行创建,启动和生命周期管理
  3. 启动各种系统服务

Launcher的启动

系统启动的最后一步是启动一个应用程序来显示系统中已安装的应用程序,该应用就叫做Launcher,Launcher在启动过程中会请求PackageManagerService,返回系统中已经安装的应用程序的信息,并且将显示在桌面上,这样用户点击图标就可以启动相应的应用程序

Launcher的作用主要有两个

  • 作为启动器,用来启动应用程序
  • 作为桌面,用于显示和管理应用程序的快捷方法和桌面小组件

Launcher启动过程介绍

startOtherService -> SystemServer -> systemReady -> AMS -> resumeFocusedStack -> ActivityStackSupervisor -> resumeTopActivity -> ActivityStack -> resumeTopActivityInnerLocked -> ActivityStack -> resumHomeStackTask -> ActivityStackSupervisor -> startHomeActivityLocked -> AMS

启动Launcher的入口为AMS的systemReady方法,在SystemServer的startOtherServices方法中调用,也就是启动其他系统服务的时候调用

mActivityManagerService.systemReady会执行回调执行 mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);

systemReady方法位于ActivityManagerService类中 位于frameworks\base\services\core\java\com\android\server\am,在该方法中调用了 mStackSupervisor.resumeFocusedStackTopActivityLocked();

resumeFocusedStackTopActivityLocked方法位于ActivityStackSupervisor类中,和AMS位于同一级目录,,在该方法中执行了判断

if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }

调用了targetStack参数的resumeTopActivityUncheckedLocked方法,该参数是一个ActivityStack对象位于AMS同级路径下,ActivityStack对象是用来描述Activity堆栈的

resumeTopActivityUncheckedLocked方法中调用了result = resumeTopActivityInnerLocked(prev, options);

resumeTopActivityInnerLocked方法很长,关键部分为return isOnHomeDisplay() && mStackSupervisor.resumeHomeStackTask(prev, "prevFinished");

在resumeHomeStackTask方法中调用了AMS中的方法return mService.startHomeActivityLocked(mCurrentUser, myReason);

    boolean startHomeActivityLocked(int userId, String reason) {
        //判断系统的运行模式,还有mTopAction的值,如果工厂模式等于低级工厂模式并且mTopAction == null,直接返回false
        //mFactoryTest代表系统运行的模式,运行模式有三种,非工厂模式,低级工厂模式,高级工厂模式
        //mTopAction用来描述第一个被启动的Activity组件的Action,默认值为Intent.ACTION_MAIN
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            return false;
        }
		//创建Launcher启动需要的Intent
        Intent intent = getHomeIntent();
        ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
        if (aInfo != null) {
            intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
            aInfo = new ActivityInfo(aInfo);
            aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
            ProcessRecord app = getProcessRecordLocked(aInfo.processName,
                    aInfo.applicationInfo.uid, true);
			//判断符合Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME的活动是否已经启动
            if (app == null || app.instr == null) {
                intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
                final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
                final String myReason = reason + ":" + userId + ":" + resolvedUserId;
                //如果没有启动,就启动该应用程序,也就是Launcher
                mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }

	//获得Launcher的Intent
    Intent getHomeIntent() {
		//创建Intent,将mTopAction和mTopData传入
        Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
        intent.setComponent(mTopComponent);
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        //如果系统运行的不是低工厂模式,将分类设置为Intent.CATEGORY_HOME
        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
            intent.addCategory(Intent.CATEGORY_HOME);
        }
        return intent;
    }

为什么需要Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME,因为Launcher的AndroidManifast文件标签匹配了Action为Intent.ACTION_MAIN,Category为Intent.CATEGORY_HOME

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.MONKEY"/>
            </intent-filter>

启动Launcher的时候执行了mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);这样一个方法,mActivityStarter是ActivityStarter对象的实例化,位于AMS同级目录下

在startHomeActivityLocked方法中,将Launcher放入了HomeStack中,HomeStack是在ActivityStackSupervisor中定义的用来存储Launcher的变量,之后调用startActivityLocked方法来启动Launcher,最后会进入Launcher的OnCreate生命周期,到此为止,Launcher完成了启动

Launcher中应用图标的显示过程

我们从Launcher的onCreate方法入手 位于packages\apps\Launcher3\src\com\android\launcher3\Launcher.java

  • 获得LauncherAppState的实例LauncherAppState app = LauncherAppState.getInstance(this);

  • 调用LauncherAppState的setLauncher方法,将this(Launcher对象)传进去mModel = app.setLauncher(this);

    • 在setLauncher方法中调用了LauncherModel的initialize方法mModel.initialize(launcher);

    • public void initialize(Callbacks callbacks) {
          	//callbacks就是传入的launcher
              synchronized (mLock) {
                  Preconditions.assertUIThread();
                  mHandler.cancelAll();
      			//将launcher封装成弱引用对象
                  mCallbacks = new WeakReference<>(callbacks);
              }
          }
      
  • 调用了LauncherModel的startLoader方法 mModel.startLoader(getCurrentWorkspaceScreen());

    • 在类中创建了具有消息循环的线程HandlerThread @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
    • 在类中创建了一个Handler并且将刚刚创建的HandlerThread的Lopper传递进去 @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper()); handler的作用在于向HandlerThread发送消息
    • 在startLoader方法中创建了一个LoaderTask mLoaderTask = new LoaderTask(mApp.getContext(), synchronousBindPage); 之后将LoaderTask发送给了HandlerTask sWorker.post(mLoaderTask);
    • LoaderTask是LauncherModel的内部类,它实现了Runable接口,当LoaderTask描述的信息被处理时,会调用其run方法
      • 加载工作区信息 loadWorkspace();
      • 绑定工作区信息 bindWorkspace(mPageToBindFirst);
      • 加载系统已经安装的应用程序信息 loadAllApps();
      • Launcher是用工作区的形式来显示系统安装的应用程序的快捷图标的,每个工作区都是用来描述一个抽象桌面的,它由N个屏幕组成,每个屏幕又分为N个单元格,每个单元格显示一个应用程序的快捷图标
      • loadAllApps方法中调用了callbacks.bindAllApplications(added);,之前分析过LauncherModel.initialize的时候已经将Launcher转换为了mCallbacks,这里的callbacks.bindAllApplications其实就是Launcher.bindAllApplications
      • Launcher.bindAllApplications中调用了mAppsView.setApps(apps); mAppsView是AllAppsContainerView类型的,我们在这里将包含应用信息的列表apps传进去(AllAppsContainerView位于packages\apps\Launcher3\src\com\android\launcher3\allapps)
      • setApps方法中调用了mApps.setApps(apps); mApps是一个AlphabeticalAppsList类型的对象
  • 最后我们来看一下AllAppsContainerViewonFinishInflate方法,该方法会在AllAppsContainerView加载完XML布局的时候调用

    • 找到AllAppsRecyclerView来显示App列表 mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
    • 将App信息设置进去 mAppsRecyclerView.setApps(mApps);
    • 设置适配器mAppsRecyclerView.setAdapter(mAdapter);

到此位置我梳理完成了Launcher的启动流程

启动流程总结

  1. 启动电源以及系统启动

    当电源按下的时候,引导芯片代码从预定的地方和开始执行,加载引导程序BootLoader到RAM,然后执行

  2. 引导程序BootLoader

    BootLoader是在Android操作系统开始运行前的一个小程序,主要作用是把系统OS拉起来并运行

  3. Linux内核启动

    当内核启动时,设置内存,被保护存储器,计划列表,加载驱动,当内核完成系统设置时,会在系统中寻找init.rc文件,并启动init进程

  4. init进程启动

    初始化和启动属性服务,并启动Zygote进程

  5. Zygote进程启动

    创建Java虚拟机并为Java虚拟机注册JNI方法,创建服务端的Socket,启动SystemServer进程

  6. SystemServer进程启动

    启动Binder线程池和SystemServiceManager,并启动各种系统服务

  7. Launcher启动

    被SystemServer启动的AMS会启动Launcher,启动Launcher后会将已安装应用的快捷图标显示到界面上

整个启动的流程图如下所示

graph TD;
	BootLoader --> LinuxKernel;
	LinuxKernel --> init;
	init --> Zygote;
	Zygote --> SystemServer;
	SystemServer --> WMS,PWS等其他系统服务;
	SystemServer --> ActivityManagerService;
	ActivityManagerService-->Launcher;