Android 应用启动流程

本文中的native层源码为1.6版本


在这里插入图片描述

1 Zygote简介

虚拟机启动耗时

  • Zygote进程运行时,会初始化Dalvik虚拟机,并启动它。
  • Android的应用程序是由java编写的,不能直接以本地进程的形态运行在Linux上,只能运行在Dalvik虚拟机中。并且每个应用程序都运行在各自的虚拟机中,引用程序每次运行都要重新初始化并启动虚拟机
  • 应用程序每次运行都要重新初始化并启动虚拟机,这个过程会耗费相当长时间,是拖慢应用程序的原因之一

使用Zygote的目的

  • 嵌入式设备拥有的资源非常有限,需要内嵌系统平台提供一个高效的运行环境,来提高设备资源的利用率和使用时间
  • Zygote进程再“孵化”新进程时,能有效的减少系统负担,提高进程“孵化”速度

启动过程

  • init进程是系统启动后运行在用户空间的首个进程
  • init进程启动完系统运行所需的各种Daemon后,启动Zygote进程
  • Zygote进程启动后,Android的服务与应用程序都由Zygote进程启动运行

Linux系统与Android系统创建进程的区别

  • Zygote通过COW(Copy On Write)方式对运行在内存中的进程实现了最大程度的复用,并通过库共享有效地降低了内存的使用量

2 由app_process运行ZygoteInit class

与其他本地服务或Daemon不同的是,Zygote由Java编写,不能直接由init进程启动运行,若想运行Zygote类,必须先生成Dalvik虚拟机,再在Dalvik虚拟机上运行ZygoteInit类,执行这一任务的就是app_process进程

2.1 创建AppRuntime对象

此函数位置: /frameworks/base/cmds/app_process/app_main.cpp

118int main(int argc, const char* const argv[])
119{
130    AppRuntime runtime; //1 创建AppRuntime对象,其父类用于启动和运行虚拟机
131    const char *arg;
132    const char *argv0;
143    int i = runtime.addVmArguments(argc, argv);
145    // Next arg is parent directory
146    if (i < argc) {
147        runtime.mParentDir = argv[i++];
148    }
180}
  • AppRuntime继承自AndroidRunTime,AndroidRuntime用于初始化并与运行Dalvik虚拟机,为运行Andriod应用程序做好准备
  • 在运行Dalvik虚拟机之前,通过Runtime对象,分析环境变量以及运行的参数,并以此作为虚拟机选项
2.2 调用AppRuntime对象
118int main(int argc, const char* const argv[])
119{
151    if (i < argc) {
152        arg = argv[i++];
153        if (0 == strcmp("--zygote", arg)) { //2 判断arg参数是否为“--zygote”
154            bool startSystemServer = (i < argc) ?
155                    strcmp(argv[i], "--start-system-server") == 0 : false;
156            setArgv0(argv0, "zygote");
157            set_process_name("zygote");
158            runtime.start("com.android.internal.os.ZygoteInit", //3 启动虚拟机,并将ZygoteInit类加载到内存中
159                startSystemServer);
160        } else {
				...
172        }
173    } 
180}
2.3 创建Dalvik虚拟机
512void AndroidRuntime::start(const char* className, const bool startSystemServer)
544    property_get("dalvik.vm.checkjni", propBuf, ""); // 1 调用property_get()函数来访问系统中设置的相关值
545    if (strcmp(propBuf, "true") == 0) {
546        checkJni = true;
547    } else if (strcmp(propBuf, "false") != 0) {
548        /* property is neither true nor false; fall back on kernel parameter */
549        property_get("ro.kernel.android.checkjni", propBuf, "");
550        if (propBuf[0] == '1') {
551            checkJni = true;
552        }
553    }

774    if (JNI_CreateJavaVM(&mJavaVM, &env, &initArgs) < 0) { //2 创建并运行虚拟机
775        LOGE("JNI_CreateJavaVM failed\n");
776        goto bail;
777    }

782    if (startReg(env) < 0) { //3 注册本地函数
783        LOGE("Unable to register all android natives\n");
784        goto bail;
785    }

849}

JNI_CreateJavaVM函数原型

3501 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) function

JavaVM** p_vm: 生成的JavaVM类的接口指针
JNIEnv** p_env:JNIEnv类的接口指针,方便访问虚拟机
void* vm_args:已设置的虚拟机选项

2.4 运行ZygoteInit类

创建完VM之后,接着加载要运行的类

512void AndroidRuntime::start(const char* className, const bool startSystemServer)
815    slashClassName = strdup(className);
816    for (cp = slashClassName; *cp != '\0'; cp++)
817        if (*cp == '.')
818            *cp = '/';//1 将 "." 替换成 “/”
819
820    startClass = env->FindClass(slashClassName);//2 在指定路径下查找类名
821    if (startClass == NULL) {
822        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
823        /* keep going */
824    } else {
825        startMeth = env->GetStaticMethodID(startClass, "main", //3 获取指定类下的方法
826            "([Ljava/lang/String;)V");
827        if (startMeth == NULL) {
828            LOGE("JavaVM unable to find main() in '%s'\n", className);
829            /* keep going */
830        } else { 
831            env->CallStaticVoidMethod(startClass, startMeth, strArray);//4 此时程序的执行会转到虚拟机中运行的java程序上
832
833#if 0
834            if (env->ExceptionCheck())
835                threadExitUncaughtException(env);
836#endif
837        }
838    }

3 ZygoteInit类的功能

516    public static void main(String argv[]) {
517        try {
518            registerZygoteSocket(); //1 绑定套接字,接收新Android应用程序运行请求
519            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
520                SystemClock.uptimeMillis());
521            preloadClasses(); //2 加载Android Application Framework
522            preloadResources();
523            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
524                SystemClock.uptimeMillis());
525
526            // Do an initial gc to clean up after startup
527            gc();
528
529            // If requested, start system server directly from Zygote
530            if (argv.length != 2) {
531                throw new RuntimeException(
532                        "ZygoteInit.main expects two arguments");
533            }
534
535            if (argv[1].equals("true")) {
536                startSystemServer();//3 运行SystemServer
537            }
538
539            Log.i(TAG, "Accepting command socket connections");
540
541            if (ZYGOTE_FORK_MODE) {
542                runForkMode();//4 处理新Android应用程序运行请求
543            } else {
544                runSelectLoopMode();
545            }
546
547            closeServerSocket();
548        } catch (MethodAndArgsCaller caller) {
549            caller.run();
550        } catch (RuntimeException ex) {
551            Log.e(TAG, "Zygote died with exception", ex);
552            closeServerSocket();
553            throw ex;
554        }
555    }
3.1 绑定/dev/socket/zygote套接字

绑定套接字的目的是为了接收应用程序创建的请求

69     private static LocalServerSocket sServerSocket;
150    private static void registerZygoteSocket() {
151        if (sServerSocket == null) {
152            int fileDesc;
153            try {
154                String env = System.getenv(ANDROID_SOCKET_ENV);
155                fileDesc = Integer.parseInt(env);
156            } catch (RuntimeException ex) {
157                throw new RuntimeException(
158                        ANDROID_SOCKET_ENV + " unset or invalid", ex);
159            }
160
161            try {
162                sServerSocket = new LocalServerSocket( //1 创建LocalServerSocket对象并赋值给
163                        createFileDescriptor(fileDesc)); //2 获取套接字的文件描述符
164            } catch (IOException ex) {
165                throw new RuntimeException(
166                        "Error binding to local socket '" + fileDesc + "'", ex);
167            }
168        }
169    }
3.2 加载应用程序Framework中类与平台资源
92     private static final String PRELOADED_CLASSES = "preloaded-classes";
233    private static void preloadClasses() {
234        final VMRuntime runtime = VMRuntime.getRuntime();
235
236        InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
237                PRELOADED_CLASSES); //1 获取输入流,用于读取“preloaded-classes”文件中的类

259                BufferedReader br
260                    = new BufferedReader(new InputStreamReader(is), 256);//2 创建BufferedReader,用于读取文件内容
276                        Class.forName(line); //3 动态加载类
328    }
337    private static void preloadResources() {
338        final VMRuntime runtime = VMRuntime.getRuntime();
339
340        Debug.startAllocCounting();
341        try {
342            runtime.gcSoftReferences();
343            runtime.runFinalizationSync();
344            mResources = Resources.getSystem(); //1 获取系统资源加载对象
345            mResources.startPreloading(); //2 开始预加载
346            if (PRELOAD_RESOURCES) {

350                TypedArray ar = mResources.obtainTypedArray( //3 加载drawable资源
351                        com.android.internal.R.array.preloaded_drawables);
352                int N = preloadDrawables(runtime, ar);

357                ar = mResources.obtainTypedArray(//4 加载colorlist资源
358                        com.android.internal.R.array.preloaded_color_state_lists);
359                N = preloadColorStateLists(runtime, ar);
362            }

369    }
370
3.3 运行SystemServer
472    private static boolean startSystemServer()
473            throws MethodAndArgsCaller, RuntimeException {
474        /* Hardcoded command line to start the system server */
475        String args[] = { //1 硬编码来保存SystemServer启动的参数,"com.android.server.SystemServer"用于指定System类
476            "--setuid=1000",
477            "--setgid=1000",
478            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
479            "--capabilities=130104352,130104352",
480            "--runtime-init",
481            "--nice-name=system_server",
482            "com.android.server.SystemServer",
483        }; 
		   ...
500            /* Request to fork the system server process */
501            pid = Zygote.forkSystemServer( //2 创建新进程并运行SystemServer
502                    parsedArgs.uid, parsedArgs.gid,
503                    parsedArgs.gids, debugFlags, null);
		  ...
507
508        /* For child process */
509        if (pid == 0) {
510            handleSystemServerProcess(parsedArgs); //3 在生成的进程中调用com.android.server.SystemServer类中的main()方法
511        }
512
513        return true;
514    }

SystemServer#main()

428    public static void main(String[] args) {
429        // The system server has to run all of the time, so it needs to be
430        // as efficient as possible with its memory usage.
431        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
432
433        System.loadLibrary("android_servers");
434        init1(args);//init1是native函数,将会调用system_init.cpp中声明的jni函数
435    }

将会调用以下jni函数
/frameworks/base/cmds/system_server/library/system_init.cpp

26static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
27{
28    system_init();
29}
30

/frameworks/base/cmds/system_server/library/system_init.cpp#system_init()

52extern "C" status_t system_init()
53{
54    LOGI("Entered system_init()");
55
56    sp<ProcessState> proc(ProcessState::self()); 
57
58    sp<IServiceManager> sm = defaultServiceManager();
59    LOGI("ServiceManager: %p\n", sm.get());
60
61    sp<GrimReaper> grim = new GrimReaper();
62    sm->asBinder()->linkToDeath(grim, grim.get(), 0);
63
64    char propBuf[PROPERTY_VALUE_MAX];
65    property_get("system_init.startsurfaceflinger", propBuf, "1");
66    if (strcmp(propBuf, "1") == 0) {
67        // Start the SurfaceFlinger
68        SurfaceFlinger::instantiate();//1 初始化SurfaceFlinger服务
69    }
70
71    // On the simulator, audioflinger et al don't get started the
72    // same way as on the device, and we need to start them here
73    if (!proc->supportsProcesses()) {
74
75        // Start the AudioFlinger
76        AudioFlinger::instantiate();//2 初始化AudioFlinger服务
77
78        // Start the media playback service
79        MediaPlayerService::instantiate();//3 初始化MediaPlayerService服务
80
81        // Start the camera service
82        CameraService::instantiate();//4 初始化CameraService服务
83    }
84
85    // And now start the Android runtime.  We have to do this bit
86    // of nastiness because the Android runtime initialization requires
87    // some of the core system services to already be started.
88    // All other servers should just start the Android runtime at
89    // the beginning of their processes's main(), before calling
90    // the init function.
91    LOGI("System server: starting Android runtime.\n");
92
93    AndroidRuntime* runtime = AndroidRuntime::getRuntime();
94
95    LOGI("System server: starting Android services.\n");
96    runtime->callStatic("com/android/server/SystemServer", "init2"); //5 本地服务注册完成后,调用System类中的init2()方法
97
98    // If running in our own process, just go into the thread
99    // pool.  Otherwise, call the initialization finished
100    // func to let this process continue its initilization.
101    if (proc->supportsProcesses()) {//6 开启线程用于进程间通讯
102        LOGI("System server: entering thread pool.\n");
103        ProcessState::self()->startThreadPool();
104        IPCThreadState::self()->joinThreadPool();
105        LOGI("System server: exiting thread pool.\n");
106    }
107    return NO_ERROR;
108}

调用SystemServer#init2()方法,在方法中创建线程并启动

437    public static final void init2() {
438        Log.i(TAG, "Entered the Android system server!");
439        Thread thr = new ServerThread();
440        thr.setName("android.server.ServerThread");
441        thr.start();
442    }

ServerThread启动后,将会注册一系列的java层的服务,并开启Looper循环。

3.4 运行新Android应用程序
603    private static void runSelectLoopMode() throws MethodAndArgsCaller {
604        ArrayList<FileDescriptor> fds = new ArrayList();
605        ArrayList<ZygoteConnection> peers = new ArrayList();
606        FileDescriptor[] fdArray = new FileDescriptor[4];
607		    //1 将套接字的描述符加到描述符数组中,程序将使用该描述符处理来自外部的连接请求
608        fds.add(sServerSocket.getFileDescriptor());
609        peers.add(null);
610
611        int loopCount = GC_LOOP_COUNT;
612        while (true) {
613            int index;
614
615            /*
616             * Call gc() before we block in select().
617             * It's work that has to be done anyway, and it's better
618             * to avoid making every child do it.  It will also
619             * madvise() any free memory as a side-effect.
620             *
621             * Don't call it every time, because walking the entire
622             * heap is a lot of overhead to free a few hundred bytes.
623             */
624            if (loopCount <= 0) {
625                gc();
626                loopCount = GC_LOOP_COUNT;
627            } else {
628                loopCount--;
629            }
630
631
632            try {
633                fdArray = fds.toArray(fdArray);
				   //2 selectReadable是一个jni函数,该方法用来监视参数传递过来的文件描述符数组,若描述符目录中存在系那个管时间,则返回其在数组中的索引
634                index = selectReadable(fdArray); 
635            } catch (IOException ex) {
636                throw new RuntimeException("Error in select()", ex);
637            }
638
639            if (index < 0) {
640                throw new RuntimeException("Error in select()");
641            } else if (index == 0) { //3 该部分用来处理的套接字为0的描述符中发生的输入输出事件
642                ZygoteConnection newPeer = acceptCommandPeer();
643                peers.add(newPeer);
644                fds.add(newPeer.getFileDesciptor());
645            } else {
646                boolean done;
647                done = peers.get(index).runOnce();
648
649                if (done) {
650                    peers.remove(index);
651                    fds.remove(index);
652                }
653            }
654        }
655    }

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java#runOnce()

167    boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
173        try {
174            args = readArgumentList(); //1读取请求信息
176        } 
195		   ...
196        int pid;
197
198        try {
199            parsedArgs = new Arguments(args); //2 分析请求信息中的字符串数组
200
201            applyUidSecurityPolicy(parsedArgs, peer);
202            applyDebuggerSecurityPolicy(parsedArgs);
203            applyRlimitSecurityPolicy(parsedArgs, peer);
204            applyCapabilitiesSecurityPolicy(parsedArgs, peer);
205
206            int[][] rlimits = null;
207
208            if (parsedArgs.rlimits != null) {
209                rlimits = parsedArgs.rlimits.toArray(intArray2d);
210            }
211
212            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, //3 创建新建成,最终调用本地fork()函数
213                    parsedArgs.gids, parsedArgs.debugFlags, rlimits);
214        } catch (IllegalArgumentException ex) {
215            logAndPrintError (newStderr, "Invalid zygote arguments", ex);
216            pid = -1;
217        } catch (ZygoteSecurityException ex) {
218            logAndPrintError(newStderr,
219                    "Zygote security policy prevents request: ", ex);
220            pid = -1;
221        }
222
223        if (pid == 0) {
224            // in child
225            handleChildProc(parsedArgs, descriptors, newStderr); //4 用来加载新进程所需要的类,并调用该类的main方法
226            // should never happen
227            return true;
228        } else { /* pid != 0 */
229            // in parent...pid of < 0 means failure
230            return handleParentProc(pid, descriptors, parsedArgs); 
231        }
232    }

参考资料《Android框架揭秘》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值