按下电源键到启动Home应用过程详解(三)

一: 这篇将分析手机从加电那一刻到Home应用启动的过程,如下图简要描述了启动过程
启动过程

system_server在开启核心服务的时候,其中有一个服务是ActivityManagerService,简称AMS; 主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,在系统进程到ready阶段的时候,AMS将会通过zygote启动Home应用

二:关于1号进程和0好进程进程
init进程是Android用户空间的1号进程,在linux中也存在0号进程;

当内核被加载到内存后,首先就会有完成内核初始化的函数start_kernel()从无到有的创建一个内核线程swap,并设置其PID为0,即进程0;它也叫闲逛进程;进程0执行的是cpu_idle()函数,该函数仅有一条hlt汇编指令,就是在系统闲置时用来降低电力的使用和减少热的产生。同时进程0的PCB叫做init_task,在很多链表中起了表头的作用。

init进程从不终止,用来创建和监控操作系统外层的所有进程的活动。

三:关于init进程
3.1 源码位置
system/core/init目录,其入口函数为system/core/init/init.c的main函数中

3.1 inti.c中main函数主要作用
- 创建基本文件系统目录并挂在文件系统
- 初始化内核Log系统
- 解析并触发inti.c配置文件中的各种action,service和command
- 属性服务的处理

3.2 init.c中main函数中相关方法的解释

mkdir(“/dev”, 0755)
创建文件目录命令,第一个为文件创建位置,第二个参数表示文件组操作权限
Linux 系统中采用三位十进制数表示权限,如0755, 0644.
0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限;
0644->即用户具有读写权限,组用户和其它用户具有只读权限;

mount(“devpts”,“/dev/pts”,”devpts”,0,NULL)
linux 的理念就是everything is file
挂载是指将一个设备(通常是存储设备)挂接到一个已存在的目录上。 我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的目录上, 然后通过访问这个目录来访问存储设备。
mount用法

四:关于init.rc的简要分析

4.1 该配置文件由Android初始化语言定义;
该配置文件由不同的Section组成,每一个Section都有不同的Action(行动)或者Service(服务),我们可以用On来声明一个Action;用service来声明一个Service;每一个Action或者Service都有若干Command(命令),每一个Command都有若干Trigger(触发条件); 这里的Service都是init进程的子进程,由关键字service,服务名和服务对应的命令的路径,命令的参数和Option(可选项,主要作为服务启动的配置参数)组成,代表在初始化阶段启动的程序

4.2 关于Android初始化语言中的Option中重要参数解读
-critical 核心服务,在一定时间内退出多次,将导致系统重启到revovery mode
-disable 开机时禁止此服务,但可以手动启动它

4.3 关于如何查看Command是在哪里执行

  • 在init_parser.c中,定义了一个keyword_info的宏,在这个文件中有很多KEYWORD的函数,执行Command就是执行这些函数
On early-init
    write /  .....
    start /  ..... 

on定义了一个Action,write和start则是对应的Command,对应执行的函数为do_write和do_start

五:关于在init进程中启动的Service

5.1 在init.c的main函数中,执行到action_for_each_trigger(“boot”….),在触发boot Action的过程中,将要启动的Service与Command关联起来

5.2 init把Service作为一个进程,用Command通过fork的方式启动的,这样所有Service就是init的子进程了;由init启动的Service主要有ueventd,servicemanager,zygote,install,bootanim等,我们称这些Service为守护进程服务

5.3 这里的Service与Android开发中的service组件是否为同一个概念
不是,这里的Service是服务的概念,不同于Android开发过程的service组件;这里的Service多由C++实现;

5.4 属性服务的启动,即内置Action的启动

5.4.1 什么是属性服务
Linux系统启动的时候,由init初始化并开启属性服务;提供了一个系统属性共享内存区,用于存储全局系统设置信息。

属性服务的文件多是prop的文件格式;
Android的属性系统是一种特殊的Action,这种Action以”on property:”为前缀;

 在android 系统中,为统一管理系统的属性,设计了一个统一的属性系统。每个属性都有一个名称和值,他们都是字符串格式。属性被大量使用在Android系统中,用来记录系统设置或进程之间的信息交换。属性是在整个系统中全局可见的。每个进程可以get/set属性。在编译的过程中会将各种系统参数汇总到build.proc 以及default.proc 这两个文件中,主要属性集中在build.proc中。系统在开机后将读取配置信息并构建共享缓冲区,加快查询速度。另外一个方面,SettingsProvider会在系统第一次初始化时(刷机第一次启动)后,将从Defaults.xml中读取数据然后写入数据库Settings.db 目录。并构建一个缓冲系统供其他应用查询。
属性服务详解

5.4.2 关于属性系统中创建的Socket
这个socket主要用于客户端和服务端的通信,便于操作属性系统的key-value;
- 这里的服务端我们可以将其抽象理解为在inti.c中的start_property_service函数,在这个函数中,创建一个服务端的socket,类似于servicesocket,并在0666端口进行监听;
- 这里的客户端主要在system/core/libcutils/properties.c的property_ set的函数中,在一系列处理之后,会创建客户端的Socket,并连接服务端;

六: Home应用是如何启动的
- zygote中通过fork系统调用创建system_server进程
- system_server进程创建各种服务,如ActivityManagerService,PackageManagerService
- 系统服务启动后会注册到ServiceManager中,用于Binder通信;
- ActivityManagerService进入systemReady状态

6.1 关于Zygote
他是一个守护进程服务,所有其他的Dalvik虚拟机进程都是通过zygote fork出来的,这样便可以共享虚拟机内存和框架层资源;

6.2 关于Zygote的配置
在linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的。

在系统启动脚本init.rc文件中,我们可以看到启动Zygote进程的脚本命令:
service zygote /system/bin/app_process
上述脚本表示要启动一个进程,名称为zygote, 可执行文件为/system/bin/app_process, –Xzygote /system/bin –zygote –start-system-server这些是传给zygote的参数;

app_process对应的源码在frameworks/base/cmds/app_process目录下,其入口函数main在文件app_main.cpp中

6.3 关于zygote启动位置的一些疑问
- 既然zygote是在init.rc中定义的守护进程,那为什么不在init中直接启动,而是在app_process中完成加载?
- 这是因为zygote不同于其他的守护进程,他是由Java语言实现,不能通过init进程的fork方式启动,因此需要在app_process完成加载工作;

6.4 关于app_main.cpp的main方法的解释

int main(int argc, char* const argv[])
{
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

   ...

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

这段函数主要作用是:

  • 调用AppRuntime类的start方法

6.5 查看AppRuntime类的start方法
AppRuntime的实现代码在app_main.cpp中

/*
 * Start the Android runtime.  This involves starting the virtual machine
 * and calling the "static void main(String[] args)" method in the class
 * named by "className".
 *
 * Passes the main function two arguments, the class name and the specified
 * options string.
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());

    static const String8 startSystemServer("start-system-server");

    /*
     * 'startSystemServer == true' means runtime is obsolete and not run from
     * init.rc anymore, so we print out the boot start event here.
     */
    for (size_t i = 0; i < options.size(); ++i) {
        if (options[i] == startSystemServer) {
           /* track our progress through the boot sequence */
           const int LOG_BOOT_PROGRESS_START = 3000;
           LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,  ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
        }
    }

    const char* rootDir = getenv("ANDROID_ROOT");
    if (rootDir == NULL) {
        rootDir = "/system";
        if (!hasDir("/system")) {
            LOG_FATAL("No root directory specified, and /android does not exist.");
            return;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    //查看onVmCreated方法体可以看出这是一个空方法体,采用多态形式实际上调用的是AppRuntime的onVmCreated方法
    onVmCreated(env);

该方法主要做了如下工作
- 创建Dalvik虚拟机 startVm(&mJavaVM, &env, zygote)
- 注册JNI方法 startReg(env)

6.6 startVm(&mJavaVM, &env, zygote)
- 通过属性系统获取虚拟机配置信息,设置虚拟机参数
- 调用JNI_CreateJavaVM创建虚拟机
我们可以通过dalvik/docs/dexopt/html查看虚拟机详细信息;或者通过adb shell dalvikvm查看

6.7 startReg(env)
- 正如之前说的日志系统,Java层可以不用加载so变实现native方法调用,其实正是这里采用的注册方法关联了Native方法和JNI实现方法
- startReg方法主要调用register_jni_procs方法。register_jni_procs方法传入RegJNIRec类型,通过查看类型的定义

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),

使用REG_JNI宏,将函数名传给RegJNIRec, 这些函数最终都调用了RegisterMethodsOrDie方法完成JNI注册;关于RegisterMethodsOrDie方法,在前面的文章中已经有了讲解
Android运行时注册的共享库为libandroid_runtime.so; 在虚拟机创建的过程中已经完成加载,其他虚拟机是通过zygote fork的方式创建,则会共享libandroid_runtime.so

6.8 CallStaticVoidMethod(startClass, startMeth, strArray);
- 在AppRuntime类的start方法中最终会调用CallStaticVoidMethod方法,该方法是个JNI函数,其调用的是ZygoteInit的main方法;此时Java的代码正式出现;
- CallStaticVoidMethod的声明在jni.h中,但是你却找不到他的实现;其实CallStaticVoidMethod的方法是使用宏来定义的;同样的在jni.h中,我们可以看见

#define CALL_STATIC_TYPE_METHODA(_jtype, _jname)                            \
    __NDK_FPABI__                                                           \
    _jtype CallStatic##_jname##MethodA(jclass clazz, jmethodID methodID,    \
        jvalue* args)                                                       \
    { return functions->CallStatic##_jname##MethodA(this, clazz, methodID,  \
        args); }

这里我们就不做过多研究,只要知道最终调用的是调用的是ZygoteInit的main方法即可

6.9 ZygoteInit.java的main方法

    public static void main(String argv[]) {
        //为zygote进程创建一个Server socket
        ZygoteServer zygoteServer = new ZygoteServer();

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
        /*setpgid(int pid, int pgid)
        函数作用:将pid进程的进程组ID设置成pgid,创建一个新进程组或加入一个已存在的进程组*/
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        try {
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
            RuntimeInit.enableDdms();
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
//Registers a server socket for zygote command connections
            zygoteServer.registerServerSocket(socketName);
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            /*
            preload方法主要做
            1:加载/system/etc/preloaded-classes文件制定的class,preloaded-classes文件内容主要由WritePreloadedClassFile.java生成
            2:加载框架层的资源文件,以便进程共享;这里加载了com.android.internal.R.array.preloaded_drawables 和 com.android.internal.R.array.preloaded_color_state_lists
这两个资源定义在frameworks\base\core\res\res\values\Arrays.xml中;
Arrays.xml里面定义的资源最终会被生成到framework-res.apk中,这样其他进程就可以共享资源了,使用方法为:android:background="@android:drawable/ic_menu_help"          
            */
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
            gcAndFinalize();
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();

            // Set seccomp policy
            Seccomp.setPolicy();

            ZygoteHooks.stopZygoteNoThreadCreation();

            if (startSystemServer) {
     /**
     * Prepare the arguments and fork for the system server process.
     * zygote通过folk方式创建system_server进程,其方法为Zygote.forkSystemServer;forkSystemServer方法系统会检查system server进程是否启动成功,如果启动失败,则导致zygote重启;system server负责构建Native System Service和Java System Service,如果启动失败,整个java 世界也无从谈起
     */
                startSystemServer(abiList, socketName, zygoteServer);
            }

            Log.i(TAG, "Accepting command socket connections");
            zygoteServer.runSelectLoop(abiList);

            zygoteServer.closeServerSocket();
        } catch (Zygote.MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            zygoteServer.closeServerSocket();
            throw ex;
        }
    }

我们看下registerServerSocket的实现

    /**
     * Registers a server socket for zygote command connections
     *
     * @throws RuntimeException when open fails
     */
    void registerServerSocket(String socketName) {
        if (mServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                mServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

在这里使用了LocalServerSocket.java,如上调用LicalServerSocket.java的构造函数

   /**
     * Create a LocalServerSocket from a file descriptor that's already
     * been created and bound. listen() will be called immediately on it.
     * Used for cases where file descriptors are passed in via environment
     * variables
     *
     * @param fd bound file descriptor
     * @throws IOException
     */
    public LocalServerSocket(FileDescriptor fd) throws IOException
    {
        impl = new LocalSocketImpl(fd);
        impl.listen(LISTEN_BACKLOG);
        localAddress = impl.getSockAddress();
    }

至此,我们已经为zygot创建了一个类型为LocalServerSocket的socket

  • 参考zygoteinit.java main方法里面的注释,我们简单对该方法做个整理

    6.9.1 new ZygoteServer对象,ZygoteServer类主要作用是新建zygote进程的server socket

    6.9.2 调用ZygoteServer对象的registerServerSocket的方法,生成LocalServerSocket类型的server socket,其应该为unix上的socket,并监听50端口

    6.9.3 调用preload方法,该方法将
    -调用preloadClasses方法,预加载/system/etc/preloaded-classes文件里面的类
    -调用preloadResources方法,预加载com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists资源文件,这两个资源定义在frameworks\base\core\res\res\values\Arrays.xml中;
    Arrays.xml里面定义的资源最终会被生成到framework-res.apk中,这样其他进程就可以共享资源了,使用方法为:android:background=”@android:drawable/ic_menu_help”

    6.9.4 调用startSystemServer方法,该方法调用过程如下

    1) 通过fork的方式开启system_server进程,forkSystemServer方法系统会检查system server进程是否启动成功,如果启动失败,则导致zygote重启;system server负责构建Native System Service和Java System Service,如果启动失败,整个java 世界也无从谈起

          pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);

2)调用handleSystemServerProcess方法,该方法主要调用ZygoteInit.zygoteInit方法

   public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        //重定向log系统
        RuntimeInit.redirectLogStreams();
        //一些初始化设置
        RuntimeInit.commonInit();
        //nativeZygoteInit为native方法,其在AndroidRuntime.cpp总,有具体实现;最终调用到AppRuntime的onZygoteInit方法,该方法开启了system_server的binder通信通道
        ZygoteInit.nativeZygoteInit();
        //applicationInit将调用invokeStaticMain方法,invokeStaticMain方法将采用反射的方式获取frameworks\base\services\java\com\android\server、SystemServer.java,然后得到main方法,注意此处并没有调用main方法;并抛出MethodAndArgsCaller异常;该异常在zygoteinit.java的main函数中有捕获,当main方法捕获到该异常之后,调用该异常的run方法,传入的参数是SystemServer.java的main方法,此时才是真正执行main方法的地方;这样做的好处是跳出调用栈,直接返回到zygoteinit的main方法中
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

7.0 SystemServer.java main方法详解

    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
public SystemServer() {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
        // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
    }

    private void run() {
        try {           
            ......
            // Prepare the main looper thread (this thread).
            Looper.prepareMainLooper();
            // Initialize native services.加载android_servers库
            System.loadLibrary("android_servers");
            // Check whether we failed to shut down last time we tried.
            // This call may not return.
            performPendingShutdown();

            // Initialize the system context.创建system的context
            createSystemContext();

            // Create the system service manager.创建SystemServiceManager,SystemServer进程主要是用来构建系统各种service服务的,而SystemServiceManager就是这些服务的管理对象。
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            //将SystemServiceManager对象保存SystemServer进程中的一个数据结构中。
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }

        // Start services.
        try {
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
            startBootstrapServices();// 主要用于启动系统Boot级服务 
            startCoreServices();//主要用于启动系统核心的服务
            startOtherServices();//主要用于启动一些非紧要或者是非需要及时启动的服务
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
......

        // Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

我们主要分析一下该run方法,在该方法中会涉及到启动Home App

1)设置系统时间,时区
2)设置系统属性
3)加载android_servers.so
4 ) 调用createSystemContex方法,创建sytem的context;
activityThread.getSystemContext()返回的是ContextImpl对象,ContextImpl继承自Context

        private void createSystemContext() {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
    }

5)创建SystemServiceManager对象,(SystemServer进程主要是用来构建系统各种service服务的,而SystemServiceManager就是这些服务的管理对象;)创建完对象之后调用LocalServices.addService添加到LocalServices.java的一个ArrayMap中

6) 调用startBootstrapServices开启boot级service
在启动service之前先介绍下SystemServiceManager对象的startService方法
该方法传入class类型,通过反射的方式拿到传入类的实例,拿到对应类实例之后,将其添加到ArrayList类型的mServices中进行生命周期管理,并同时调用该实例的onStart方法

    // Services that should receive lifecycle events.
    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();

现在来看下 startBootstrapServices方法的执行流程
a: 通过 SystemServiceManager.startService(Installer.class)创建Install的systemservice,Install是系统安装apk时的一个服务类;
b: 通过 SystemServiceManager.startService方法开启ActivityManagerService,并为其设置SysServiceManager和Installer

        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();     mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);

c: 开启PowerManagerService 该类用来管理电源
d: 开启LightsService,该类用来管理LED和背光
e: 开启DisplayManagerService,显示管理服务DisplayManagerService,支持多种显示类型的多个显示器的镜像显示,包括内建的显示类型(本地)、HDMI显示类型以及支持WIFI Display 协议( MIRACAST),实现本地设备在远程显示器上的镜像显示。
f: 开启UserManagerService
g: 开启PackageManagerService,这个不是通过startservice启动,而是通过如下启动

        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();

7)调用startCoreServices启动系统核心的服务

    private void startCoreServices() {
        // Tracks the battery level.  Requires LightService.
        mSystemServiceManager.startService(BatteryService.class);

        // Tracks application usage stats.
        mSystemServiceManager.startService(UsageStatsService.class);
        mActivityManagerService.setUsageStatsManager(
                LocalServices.getService(UsageStatsManagerInternal.class));

        // Tracks whether the updatable WebView is in a ready state and watches for update installs.
        mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
    }

a. 调用startservice开启BatteryService
b. 调用startservice开启UsageStatsService
c. 调用startservice开启WebViewUpdateService

8)调用startOtherServices() 主要用于启动一些非紧要或者是非需要及时启动的服务

8.0 如何显示Home App的
在上面的讲解中,我们调用了startOtherServices方法,该方法将调用mActivityManagerService.systemReady方法,告诉系统已经好了,可以显示Home App了

// We now tell the activity manager it is okay to run third party
// code.  It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
// started launching the initial applications), for us to complete our
// initialization.
        mActivityManagerService.systemReady(new Runnable() {
            @Override
            public void run() {
                Slog.i(TAG, "Making services ready");
                ......
                try {
                    startSystemUi(context);
                } catch (Throwable e) {
                    reportWtf("starting System UI", e);
                }
               ......
            }
        });

systemReady方法将调用startHomeActivityLocked启动Home App

startHomeActivityLocked(currentUserId, "systemReady");
    boolean startHomeActivityLocked(int userId, String reason) {
        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                && mTopAction == null) {
            // We are running in factory test mode, but unable to find
            // the factory test app, so just sit around displaying the
            // error message and don't try to start anything.
            return false;
        }
        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);
                mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
            }
        } else {
            Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
        }

        return true;
    }

由于launcher是一个apk,在之前的packagemanagerserver已经对其进行解析,因此可以获得对应的intent信息,接着调用ActivityStarter.java startHomeActivityLocked方法,该方法调用startActivityLocked方法

    void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
        mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
        //activity的启动方式
        startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
                null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
                null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
                0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
                0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
                false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
                null /*container*/, null /*inTask*/);
        if (mSupervisor.inResumeTopActivity) {
            // If we are in resume section already, home activity will be initialized, but not
            // resumed (to avoid recursive resume) and will stay that way until something pokes it
            // again. We need to schedule another resume.
            mSupervisor.scheduleResumeTopActivities();
        }
    }

在startActivityLocked有一个重要的方法如下

rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,

该方法主要作用是在启动activity的时候,PMS会去找清单文件,是否有注册的Activity;

该方法实际上调用的是PackageManagerService(PMS)的resolveIntent方法,

    @Override
    public ResolveInfo resolveIntent(Intent intent, String resolvedType,
            int flags, int userId) {
        ...
            final ResolveInfo bestChoice =
                    chooseBestActivity(intent, resolvedType, flags, query, userId);
            return bestChoice;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

chooseBestActivity方法会根据priority优先级来判断来选择最好的一个activity,这个priority会在launcher 的manifest.xml中进行配置;当查询到这个activity之后,Launcher App就被启动起来,接着完成activity的启动过程,即进行activity相应生命周期的流程,展示UI;

在ActivityStarter.java中的startActivityLocked方法中,会调用startActivityUnchecked方法

这个方法处理了Activity的启动模式,比如是否需要新建一个任务栈,栈里面是否需要复用已经存在的Activity实例等等。而且启动模式还要配合flag,比如说NEW_TASK等。并且在清单文件里面的启动模式的配置要优先于flags

在startActivityUnchecked方法体内部有如下关键代码

        ActivityStack.logStartActivity(
                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
        mTargetStack.mLastPausedActivity = null;

        sendPowerHintForLaunchStartIfNeeded(false /* forceSend */);

        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);

ActivityStack是activity的栈的管理类;调用ActivityStack类的startActivityLocked之后;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值