文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android 系统启动流分析 & Zygote启动流程分析

2022-06-06 14:00

关注

本文是基于Android 7.1进行分析      

Zygote在Android系统扮演着不可或缺的角色,Android系统的启动首先需要Zygote参与,比如启动SystemService , 还有一个就是孵化应用的进程,比如我们创建一个Activity也是需要Zygote参与.     

Zygote 启动分为两个部分:

1.Native程序涉及文件


system/core/ini/service.cpp 
system/core/rootdir/init.rc
system/core/rootdir/init.zygote64_32.rc
frameworks/base/cmds/app_process/Android.mk
frameworks/base/core/jni/AndroidRuntime.cpp

2.Java程序 涉及文件路径


frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
frameworks/base/services/java/com/android/server/SystemServer.java

我们先看一下系统启动的流程图先有一个大概的了解

一.底层程序

那么Zygote是怎么启动的? 首先是开机的时候会Linux会先启动init进行,这也是手机开机的第一个进程,这个进程启动之后会去加载启动文件init.rc 而init进程的源代码位于 system/core/ini/service.cpp 文件,是由 Service::Start()函数来解释init.rc文件中的命令,而pid_t pid = fork(); 是 0 的时候则返回的是子线程.非0 返回的是父进程.


bool Service::Start() {
    ......省略代码.........
    pid_t pid = fork();
    if (pid == 0) {
        umask(077);
        for (const auto& ei : envvars_) {
            add_environment(ei.name.c_str(), ei.value.c_str());
        }
        for (const auto& si : sockets_) {
            int socket_type = ((si.type == "stream" ? SOCK_STREAM :
                                (si.type == "dgram" ? SOCK_DGRAM :
                                 SOCK_SEQPACKET)));
            const char* socketcon =
                !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();
            int s = create_socket(si.name.c_str(), socket_type, si.perm,
                                  si.uid, si.gid, socketcon);
            if (s >= 0) {
                PublishSocket(si.name, s);
            }
        }
      ......省略代码.........
    return true;
}

我们来查看一下init.rc文件 文件位置在 system/core/rootdir/ 文件夹下 

查看一下文件夹结构


tree rootdir
rootdir
├── Android.mk
├── asan.options
├── asan.options.off.template
├── etc
│   ├── hosts
│   ├── public.libraries.android.txt
│   └── public.libraries.wear.txt
├── fastbootinit
│   ├── Android.mk
│   └── init.rc
├── init-debug.rc
├── init.environ.rc.in
├── init.rc
├── init.usb.configfs.rc
├── init.usb.rc
├── init.zygote32_64.rc
├── init.zygote32.rc
├── init.zygote64_32.rc
├── init.zygote64.rc
└── ueventd.rc
2 directories, 18 files

打开 init.rc如下会发现其中要使用的具体是那个.rc文件 需要${ro.zygote} 决定



import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc

${ro.zygote} 这个字段有两种方式可以查看到 

第一种先编译一下需要选中的版本从下面可以看到ro.zygote=zygote64_32 ,那么毫无疑问我编译系统使用的将会是init.zygote64_32.rc


./out/target/product/msmXXX/root/default.prop:9:ro.zygote=zygote64_32
./out/target/product/msmXXX/root/init.rc:11:import /init.${ro.zygote}.rc

第二种方式 build/target/product/ 下面如果我们编译的是 64位的 ro.zygote=zygote64_32,如果是 minimal 或者 tiny版本用的是 ro.zygote=zygote32


build$ grep "ro.zygote" . -rn
./target/product/core_64_bit.mk:30:PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote64_32
./target/product/core_minimal.mk:118:    ro.zygote=zygote32
./target/product/core_tiny.mk:108:    ro.zygote=zygote32

因我编译的是 64位的所以使用的是 system/core/rootdir/init.zygote64_32.rc 进行的讲解

打开init.zygote64_32.rc 文件


service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

关于上面的代码 我们来逐个分析一下

关键字service告诉init进程创建一个名为"zygote"的进程,这个zygote进程要执行的程序是/system/bin/app_process64.

"class main"表示执行system/bin/app_process64后调用main方法.

socket关键字表示这个zygote进程需要一个名称为"zygote"的socket资源(因为JavaZygote和nativeZygote 使用的是 socke 通讯)

进入烧录好的系统后可以在/dev/socket目录下看到有一个名为zygote的文件 

onrestart关键字表示这个zygote进程重启时需要执行的命令

writepid关键字表示需要重写系统pid。

那么接下来app_process64 可执行程序是在什么地方生成的那?

全局搜索发现是 frameworks/base/cmds/app_process/Android.mk 中有发现,原来app_process64 或者app_process32 是由我们编译的版本决定的,编译的是 app_main.cpp


LOCAL_SRC_FILES:= \
    app_main.cpp
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64

查看 app_main.cpp  中的main 方法我们发现 main函数参数不同 启动的线程也是不同的


int main(int argc, char* const argv[])
{
    .....省略代码......
    while (i < argc) {
        const char* arg = argv[i++];
        //匹配上了参数
        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;
        }
    }
  .....省略代码......
   // 开启 ZygoteInit 
    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.");
        return 10;
    }
}

在 app_main.cpp 首行可以看到 AppRuntime 是内部类继承于 AndroidRuntime.cpp


class AppRuntime : public AndroidRuntime {
}

因此 runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 需要查看  AndroidRuntime类中的 start() 方法

frameworks/base/core/jni/AndroidRuntime.cpp


void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
.........省略代码...........
   //启动system Service
    static const String8 startSystemServer("start-system-server");
.........省略代码...........
    //注册JNI
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
   //启动虚拟机
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);
.........省略代码...........
   //启动 com.android.internal.os.ZygoteInit 的main方法
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
.........省略代码...........
}

由上面的代码我们查看到 在AndroidRuntime.cpp 中启动了Java 虚拟机和system -Service 然后 然后启动了Java虚拟机器调用了

com.android.internal.os.ZygoteInit中的main方法.由此我们进入到了 Java代码层面.

  二.Java程序

下面查看ZygoteInit.java 类中的main方法

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

ZygoteInit中的main方法主要干了6件事:

1.registerZygoteSocket,

2.调用preload加载资源,

3.利用gcAndFinalize初始化gc,

4.启动SystemServer,

5.调用runSelectLoop运行Zygote进程选择的looper,

6.关闭和清理zygote sockets


    public static void main(String argv[]) {
        try {
         ...........省略代码.........
            //1.registerZygoteSocket
            registerZygoteSocket(socketName);
           //2.调用preload加载资源
            preload();
           //3.利用gcAndFinalize初始化gc
            gcAndFinalize();
           //4.启动SystemServer
            if (startSystemServer) {
                startSystemServer(abiList, socketName);
            }
            //5.调用runSelectLoop运行Zygote进程选择的looper
            runSelectLoop(abiList);
            //6.关闭和清理zygote sockets
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

我们现在只看下 //4.启动SystemServer  startSystemServer(abiList, socketName); 来创建一个新的进程来启动SystemServer组件,返回值pid如果是 0的就是子进程 非0就是父进程 .


  private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        ...........省略代码.......
      String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;
      int pid;
        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
            
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            handleSystemServerProcess(parsedArgs);
        }
        return true;
    }

我们看到执行的路径是 com.android.server.SystemServer 类

我们查看一下SystemServer.java类

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


   public static void main(String[] args) {
        new SystemServer().run();
    }

run方法比较大 基本上是 初始化设置一些系统属性、准备MainLooper、初始化system context对象、创建system service manager;启动各种service


private void run() {
        try {
            ........省略代码.......
            //设置一些系统属性
            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
                final String languageTag = Locale.getDefault().toLanguageTag();
                SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }
            ........省略代码.......
            //2、准备MainLooper
            Looper.prepareMainLooper();
            // Initialize native services.
            System.loadLibrary("android_servers");
            ........省略代码.......
            //3、初始化system context
            createSystemContext();
            ........省略代码.......
            //4、创建system service manager
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
        // Start services.
        try {
            ........省略代码.......
            //启动各种service
            startBootstrapServices();
            startCoreServices();
            //joe add here start serevice reoder for fastboot 20180830
            if(SystemProperties.getBoolean("ro.quectel.bootfast", false)){                
                startOtherServices_reOrgnize();
            }else{
		   startOtherServices();
            }
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
        // Loop forever.
        Looper.loop();
    }

其中SystemServer中有  private void startOtherServices() 方法 有mActivityManagerService.systemReady(Runnable)方法

此方法开启的  System UI ,网络状态 等等等.


mActivityManagerService.systemReady(new Runnable() {
            @Override
            public void run() {
                ...........省略代码........
                //开启UI
                try {
                    startSystemUi(context);
                } catch (Throwable e) {
                    reportWtf("starting System UI", e);
                }
                //开启网络
                try {
                    if (networkScoreF != null) networkScoreF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Score Service ready", e);
                }
                try {
                    if (networkManagementF != null) networkManagementF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Managment Service ready", e);
                }
                try {
                    if (networkStatsF != null) networkStatsF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Stats Service ready", e);
                }
                try {
                    if (networkPolicyF != null) networkPolicyF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Network Policy Service ready", e);
                }
                try {
                    if (connectivityF != null) connectivityF.systemReady();
                } catch (Throwable e) {
                    reportWtf("making Connectivity Service ready", e);
                }
}

Zygote简单总结一下:
   1. 系统启动时init进程会创建Zygote进程,Zygote进程会Fork出System进程和创建虚拟机也会创建Fork进程.
   2. Zygote进程会首先创建一个SystemServer进程,SystemServer进程负责启动系统的关键服务,Android应用程序通过ActivityManagerService先调用java层的Zygote服务然后java层的Zygote层通过Socket与底层Zygote进程为这个应用程序创建一个新的进程.

    


作者:ChaoLi_Chen


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯