重学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

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存