重学Android之Framework层应用程序进程创建流程

2024-06-20 03:08

本文主要是介绍重学Android之Framework层应用程序进程创建流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android系统启动完成后,会启动第一Android应用Launcher。之后在用户操作下启动其他的应用程序。这两个流程大体一致,本文主要分析启动Launcher的启动流程。

Android系统源码版本:9.0.0_r3

整体流程图如下:

Zygote启动及应用进程创建流程

Zygote启动流程

Android Kernel启动后启动第一个进程init,init将解析init.*.rc文件启动进程zygote。

/system/core/rootdir/init.zygote32_64.rc

1 service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
2    class main
3    priority -20
4    user root
5    group root readproc reserved_disk
6    socket zygote stream 660 root system
7    onrestart write /sys/android_power/request_state wake
8    onrestart write /sys/power/state on
9    onrestart restart audioserver
10    onrestart restart cameraserver
11    onrestart restart media
12    onrestart restart netd
13    onrestart restart wificond
14    writepid /dev/cpuset/foreground/tasks
15
16 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
17    class main
18    priority -20
19    user root
20    group root readproc reserved_disk
21    socket zygote_secondary stream 660 root system
22    onrestart restart zygote
23    writepid /dev/cpuset/foreground/tasks

init启动的程序app_process32或app_process64 跟--zygote参数表明启动的是zygote进程。这里的app_process32app_process64表示32位zygote进程和64位zygote进程,用于兼容包含so库为32位的应用启动。其实在Android环境中我们是可以用app_proccess*去运行一个Dalvik格式的java字节码文件,就像在台式机上用java运行字节码一样。
zygote启动之后将完成ART虚拟机的创建工作并运行com.android.internal.os.ZygoteInit。关键内容如下所示

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

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

在com.android.internal.os.ZygoteInit中会完成Android环境中Framework关键Java类文件的加载工作。创建本地套接字用ZygoteServer管理,通过fork调用创建子进程system_server进程。开启本地套接字ZygoteServer的监听功能即运行runSelectLoop方法监听是否有新套接字或读写事件发生。

/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

750    public static void main(String argv[]) {
751        ZygoteServer zygoteServer = new ZygoteServer();
752//.....删除不相干代码
832            if (startSystemServer) {
833                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
834
835                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
836                // child (system_server) process.
837                if (r != null) {
838                    r.run();
839                    return;
840                }
841            }
842
843            Log.i(TAG, "Accepting command socket connections");
844
845            // The select loop returns early in the child process after a fork and
846            // loops forever in the zygote.
847            caller = zygoteServer.runSelectLoop(abiList);
848        } catch (Throwable ex) {
849            Log.e(TAG, "System zygote died with exception", ex);
850            throw ex;
851        } finally {
852            zygoteServer.closeServerSocket();
853        }
854
855        // We're in the child process and have exited the select loop. Proceed to execute the
856        // command.
857        if (caller != null) {
858            caller.run();
859        }
860    }

在这里本地套接字即UDS(Unix Domain Socket),其实就是一种进程间通信方式,像Nginx,MySQL中都UDS用来做进程间通信。Android进程间通信方式比Linux多了Binder这种进程间通信方式。本文不会详细讲解Binder,只要知道Binder其实就是用于两个不同进程间通信即可,跟管道、信号量、UDS没有本质的不同。

system_server进程启动流程

system_server进程将调用com.android.server.SystemServer,SystemnServer将启动各个重要的服务,代码如下

/frameworks/base/services/java/com/android/server/SystemServer.java

 // Start services.
427        try {
428            traceBeginAndSlog("StartServices");
429            startBootstrapServices();
430            startCoreServices();
431            startOtherServices();
432            SystemServerInitThreadPool.shutdown();
433        } catch (Throwable ex) {
434            Slog.e("System", "******************************************");
435            Slog.e("System", "************ Failure starting system services", ex);
436            throw ex;
437        } finally {
438            traceEnd();
439        }

启动的服务有ActivityManagerService、WindowManagerService、PackageManagerService、InputManagerService、BluetoothManagerService等服务类。
其中PackageManagerService将完成对手机上已安装的应用程序的解析,如解析Apk安装位置、Manifest信息,资源文件、类文件路径等。

system_server启动完毕后调用AMS的systemReady方法,发送启动Launcher的Intent,PMS将找到Launcher的安装路径,调用AMS的startProcess。startProcess经过一系列调用最终使用UDS与zygote进程通信,发送相应的命令,让zygote创建子进程。AMS将返回的子进程pid和与之关联app信息放入mPidsSelfLocked成员变量中。代码如下

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

4530    private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
4531            long expectedStartSeq, boolean procAttached) {
4532       //省略很多代码....
4598        synchronized (mPidsSelfLocked) {
4599            this.mPidsSelfLocked.put(pid, app);
4600            if (!procAttached) {
4601                Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
4602                msg.obj = app;
4603                mHandler.sendMessageDelayed(msg, usingWrapper
4604                        ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
4605            }
4606        }
4607        checkTime(app.startTime, "startProcess: done updating pids map");
4608        return true;
4609    }

应用进程启动流程

在这里ZygoteServer的本地套接字监听到有消息到来时将fork一个新的子进程,这新的子进程就继承了zygote进程的资源如已经创建好的ART虚拟机,这样能够加快应用的创建启动。
关键代码如下

/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

123    Runnable processOneCommand(ZygoteServer zygoteServer) {
124        String args[];
125        Arguments parsedArgs = null;
126        FileDescriptor[] descriptors;
127
128        try {
129            args = readArgumentList();
130            descriptors = mSocket.getAncillaryFileDescriptors();
131        } catch (IOException ex) {
132            throw new IllegalStateException("IOException on command socket", ex);
133        }
134//删除不相关代码...
146        parsedArgs = new Arguments(args);
147
148        
231
232        fd = null;
233
234        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
235                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
236                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
237                parsedArgs.instructionSet, parsedArgs.appDataDir);//删除不相关代码...
238
240            if (pid == 0) {
241                // in child
242                zygoteServer.setForkChild();
243
244                zygoteServer.closeServerSocket();
245                IoUtils.closeQuietly(serverPipeFd);
246                serverPipeFd = null;
247
248                return handleChildProc(parsedArgs, descriptors, childPipeFd,
249                        parsedArgs.startChildZygote);
250            } else {
251                // In the parent. A pid < 0 indicates a failure and will be handled in
252                // handleParentProc.
253                IoUtils.closeQuietly(childPipeFd);
254                childPipeFd = null;
255                handleParentProc(pid, descriptors, serverPipeFd);
256                return null;
257            }
258     
262    }

在子进程中将解析其他进程(system_server)发过来的参数,运行指定的类。通常这个类就是ActivityThread,这个子进程就是我们新启动的应用进程,当前这个进程还不知道要到哪里去加载应用程序对应字节码和资源文件。当ActivityThread启动后将与system_server 进行进程间通信(Binder),调用AMS相关函数。代码如下:

/frameworks/base/core/java/android/app/ActivityThread.java

6478    private void attach(boolean system, long startSeq) {
6479        sCurrentActivityThread = this;
6480        mSystemThread = system;
6481        if (!system) {
6482            ViewRootImpl.addFirstDrawHandler(new Runnable() {
6483                @Override
6484                public void run() {
6485                    ensureJitEnabled();
6486                }
6487            });
6488            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
6489                                                    UserHandle.myUserId());
6490            RuntimeInit.setApplicationObject(mAppThread.asBinder());
6491            final IActivityManager mgr = ActivityManager.getService();
6492            try {
6493                mgr.attachApplication(mAppThread, startSeq);
6494            } catch (RemoteException ex) {
6495                throw ex.rethrowFromSystemServer();
6496            }

在6493行 ActivityThread调用mgr.attachApplication,由于Binder机制将调用AMS的attachApplication方法。

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @Override
7932    public final void attachApplication(IApplicationThread thread, long startSeq) {
7933        synchronized (this) {
7934            int callingPid = Binder.getCallingPid();
7935            final int callingUid = Binder.getCallingUid();
7936            final long origId = Binder.clearCallingIdentity();
7937            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
7938            Binder.restoreCallingIdentity(origId);
7939        }
7940    }

attachApplication方法中将获取正在启动进程的pid,通过pid在mPidsSelfLocked(或者通过startSeq在mPendingStarts)中查找到要启动程序的信息,将要启动程序的信息通过Binder进程间通信(即IApplicationThread相关方法)发送给应用进程,由应用进程去加载相应的类。

应用进程加载完成后告知AMS,AMS将控制应用进程启动Activity,此后AMS下达命令,应用进程执行,执行完成后告知AMS。应用进程就像一个提线木偶一样受到AMS的制约。(现在的插件化技术,就是Hook掉对应的接口,欺骗AMS完成插件中四大组件的加载,即常说的欺上瞒下)

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

  private final boolean attachApplicationLocked(IApplicationThread thread,
7573            int pid, int callingUid, long startSeq) {
7574
7575        // Find the application record that is being attached...  either via
7576        // the pid if we are running in multiple processes, or just pull the
7577        // next app record if we are emulating process with anonymous threads.
7578        ProcessRecord app;
7579        long startTime = SystemClock.uptimeMillis();
7580        if (pid != MY_PID && pid >= 0) {
7581            synchronized (mPidsSelfLocked) {
7582                app = mPidsSelfLocked.get(pid);
7583            }
7584        } else {
7585            app = null;
7586        }
7587
7588        // It's possible that process called attachApplication before we got a chance to
7589        // update the internal state.
7590        if (app == null && startSeq > 0) {
7591            final ProcessRecord pending = mPendingStarts.get(startSeq);
7592            if (pending != null && pending.startUid == callingUid
7593                    && handleProcessStartedLocked(pending, pid, pending.usingWrapper,
7594                            startSeq, true)) {
7595                app = pending;
7596            }
7597        }
7598
7599        if (app == null) {
7600            Slog.w(TAG, "No pending application record for pid " + pid
7601                    + " (IApplicationThread " + thread + "); dropping process");
7602            EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
7603            if (pid > 0 && pid != MY_PID) {
7604                killProcessQuiet(pid);
7605                //TODO: killProcessGroup(app.info.uid, pid);
7606            } else {
7607                try {
7608                    thread.scheduleExit();
7609                } catch (Exception e) {
7610                    // Ignore exceptions.
7611                }
7612            }
7613            return false;
7614        }

总结

Android启动过程中init进程创建zygote进程,zygote进程创建system_server进程作为系统的核心服务进程,同时创建本UDS服务端监听请求的到来。每当需要创建普通应用进程时,通过UDS与zygote进程通信,由zygote进程fork出新的应用进程。这样做的好处是,zygote进程中ART已经创建好,能很快创建好进程需要的环境。

整个Android系统是由多个服务进程组成,如zygote、system_server、 servicemanager、surfaceflinger(在Android2.3版本及之前surfaceflinger在system_server进程中创建,不是独立进程)等。各个服务进程间通过binder机制进行进程间通信,协调各个应用程序有序的使用系统资源。
如屏幕要绘制的图形的都会交给surfaceflinger去完成渲染。可以想象如果每一个程序都能独立往屏幕上绘制图形,这么多程序一起绘制,屏幕显示将会一团糟。

有些服务进程(如surfaceflinger)对应的程序完全由C++实现,不包含Java代码,就不需要创建ART环境,这类服务通常都是独立启动。包含Java代码的进程(如system_server、com.android.systemui、大多数普通应用程序等)通常使用zygote通过fork创建。

这篇关于重学Android之Framework层应用程序进程创建流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1076932

相关文章

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创

mysql外键创建不成功/失效如何处理

《mysql外键创建不成功/失效如何处理》文章介绍了在MySQL5.5.40版本中,创建带有外键约束的`stu`和`grade`表时遇到的问题,发现`grade`表的`id`字段没有随着`studen... 当前mysql版本:SELECT VERSION();结果为:5.5.40。在复习mysql外键约

Window Server创建2台服务器的故障转移群集的图文教程

《WindowServer创建2台服务器的故障转移群集的图文教程》本文主要介绍了在WindowsServer系统上创建一个包含两台成员服务器的故障转移群集,文中通过图文示例介绍的非常详细,对大家的... 目录一、 准备条件二、在ServerB安装故障转移群集三、在ServerC安装故障转移群集,操作与Ser

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Window Server2016 AD域的创建的方法步骤

《WindowServer2016AD域的创建的方法步骤》本文主要介绍了WindowServer2016AD域的创建的方法步骤,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、准备条件二、在ServerA服务器中常见AD域管理器:三、创建AD域,域地址为“test.ly”

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Python实现NLP的完整流程介绍

《Python实现NLP的完整流程介绍》这篇文章主要为大家详细介绍了Python实现NLP的完整流程,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 编程安装和导入必要的库2. 文本数据准备3. 文本预处理3.1 小写化3.2 分词(Tokenizatio

Python在固定文件夹批量创建固定后缀的文件(方法详解)

《Python在固定文件夹批量创建固定后缀的文件(方法详解)》文章讲述了如何使用Python批量创建后缀为.md的文件夹,生成100个,代码中需要修改的路径、前缀和后缀名,并提供了注意事项和代码示例,... 目录1. python需求的任务2. Python代码的实现3. 代码修改的位置4. 运行结果5.