Zygote的启动之二ZygoteInit

Android 3XCN.com站长2023年8月5日 am8:00发布12个月前更新
0
导航号,我的单页导航
目录

前言

Android系统中,所有的应用程序以及SystemServer都是由Zygote进程孕育(fork)出来的。接上文,上文介绍从Native世界进入了Java世界。而且java世界的大门就是ZygtoeInit.java。这次我们看ZygtoeInit中处理了哪些功能。

Android P

正文

涉及文件

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
frameworks\base\core\jni\com_android_internal_os_Zygote.cpp
frameworks\base\core\jni\com_android_internal_os_ZygoteInit.cpp

Zygote的启动之二ZygoteInit

接上一篇《Zygote的启动之一app_main》,启动了com.android.internal.os.ZygoteInit进入了Java的世界,

runtime.start("com.android.internal.os.ZygoteInit", args, zygote);

args中的参数

{"start-system-server", "--abi-list=arm64-v8a", "--socket-name=zygote", "--enable-lazy-preload"}

进入ZygoteInit.java世界,启动的依旧是main()函数。

public static void main(String argv[]) {
    //[1]创建ZygoteServer
    ZygoteServer zygoteServer = new ZygoteServer();
    final Runnable caller;
    try {
        for (int i = 1; i < argv.length; i++) {
            //是否有start-system-server参数,有就需要启动startSystemServer
            if ("start-system-server".equals(argv[i])) {
                //是否启动SystemServer
                startSystemServer = true;
            } else if ("--enable-lazy-preload".equals(argv[i])) {
                //是否延迟加载
                enableLazyPreload = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                //32位 --abi-list=armeabi-v7a,armeabi
                //64位 --abi-list=arm64-v8a
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                //设置socket名
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }
        //[2]注册socket
        zygoteServer.registerServerSocketFromEnv(socketName);
        //懒惰预加载,enableLazyPreload=true;
        if (!enableLazyPreload) {
            //这里暂时不走
            preload(bootTimingsTraceLog);
        } else {
            Zygote.resetNicePriority();
        }
        //[3]提前加载Resources
        preloadResources();
        //提前加载文本Resources
        preloadTextResources();
        //主动GC
        gcAndFinalize();
        //我这64位时startSystemServer= true
        if (startSystemServer) {
            //[4]创建SystemServer
            Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
            if (r != null) {
                r.run();
                return;
            }
        }
        //[5]循环中。对于zygote不会退出,至于fork的子进程,是会退出的
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        throw ex;
    } finally {
        //关闭socket
        zygoteServer.closeServerSocket();
    }
    if (caller != null) {
        caller.run();
    }
}

上面主要是如下功能:

  1. 创建ZygoteServer

  2. 注册socket

  3. 预加载资源

  4. 创建SystemServer

  5. runSelectLoop()一直循环处理

下面就简单的走一下流程。

创建ZygoteServer

ZygoteServer zygoteServer = new ZygoteServer();

功能很简单,就是创建ZygoteServer对象,后面需要。

注册socket

zygoteServer.registerServerSocketFromEnv(socketName);

也就是处理功能都是ZygoteServer类。

socketName就是之前init.zygote64_32.rc中配置的。

64位socketName:zygote
32位socketName:zygote_secondary

就是注册了对应的socket,后面用于通信

void registerServerSocketFromEnv(String socketName) {
    if (mServerSocket == null) {
        //略
         FileDescriptor fd = new FileDescriptor();
         fd.setInt$(fileDesc);
         //创建mServerSocket
         mServerSocket = new LocalServerSocket(fd);
         mCloseSocketFd = true;
    }
}

预加载资源

//enableLazyPreload= true
if (!enableLazyPreload) {
	//暂时不走这里,后面会加载
    preload(bootTimingsTraceLog);
} else {
    Zygote.resetNicePriority();
}
//提前加载Resources
preloadResources();
//提前加载文本Resources
preloadTextResources();

提前加载系统相关的资源,这也是为啥开发中推荐优先用系统资源文件。

预加载的资源是存在framework-res.apk中。

forkSystemServer()

if (startSystemServer) {
	// fork SystemServer,并返回一个 Runnable
    Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
    if (r != null) {
        r.run();
        return;
    }
}

这里是创建出SystemServer进程,然后后面找到main()入口函数,进行启动SystemServer.java

private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer){
	//略
	//配置uid,gid,group等参数
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server", //进程名
        "--runtime-args",
        "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
        "com.android.server.SystemServer", //启动类
    };
    int pid;
    try {
		//参数转换
        parsedArgs = new ZygoteConnection.Arguments(args);
        ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
        ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
		//默认为false
        boolean profileSystemServer = SystemProperties.getBoolean(
                "dalvik.vm.profilesystemserver", false);
		//fork一个进程,就是创建SystemServer
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.runtimeFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }
    //子进程
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }
		//关闭子进程的socket
        zygoteServer.closeServerSocket();
		//处理SYstemServer进程
        return handleSystemServerProcess(parsedArgs);
    }
    return null;
}

进入handleSystemServerProcess

handleSystemServerProcess()
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
    if (parsedArgs.niceName != null) {
    	//设置进程名为system_server
        Process.setArgV0(parsedArgs.niceName);
    }
    //加载SystemServer类的路径
    final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
	//systemServerClasspath不为空
	if (systemServerClasspath != null) {
        performSystemServerDexOpt(systemServerClasspath);
		//profileSystemServer = false
        boolean profileSystemServer = SystemProperties.getBoolean(
                "dalvik.vm.profilesystemserver", false);
		//略
    }
	//parsedArgs.invokeWith = null
    if (parsedArgs.invokeWith != null) {
	  //不走这
    } else {
        ClassLoader cl = null;
        if (systemServerClasspath != null) {
        	//创建ClassLoader
            cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
            Thread.currentThread().setContextClassLoader(cl);
        }
		//进入ZygoteInit.zygoteInit()
        return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }
}

systemServerClasspath存储的内容

/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/wifi-service.jar:/system/framework/com.android.location.provider.jar:/system/framework/car-frameworks-service.jar
zygoteInit()
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader){
	//略
	//native方法
    ZygoteInit.nativeZygoteInit();
	//进入applicationInit,返回Runnable
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
applicationInit()

此时进入了RuntimeInit.java中,我们看applicationInit()

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {
	//略
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}
findStaticMain()

看名字就是找到类的启动入口。

根据前面,知道className传入的是com.android.server.SystemServer

protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {
    Class<?> cl;
    try {
		//加载com.android.server.SystemServer类
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
    }
    Method m;
    try {
		//查找main函数
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
    }
    int modifiers = m.getModifiers();
	//判断是否有static和public修饰
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                "Main method is not public and static on " + className);
    }
    //MethodAndArgsCaller就是一个Runnable
    return new MethodAndArgsCaller(m, argv);
}

最终就创建的一个Runnable。

MethodAndArgsCaller
 static class MethodAndArgsCaller implements Runnable {
     private final Method mMethod;
     private final String[] mArgs;
     public MethodAndArgsCaller(Method method, String[] args) {
         mMethod = method;
         mArgs = args;
     }

     public void run() {
         try {
			//Method = com.android.server.SystemServer的main函数
             mMethod.invoke(null, new Object[] { mArgs });
         } catch (IllegalAccessException ex) {
			//略
		}
     }
 }

上面我们知道,fork出SystemServer之后,进行了null判断,然后启动了run()

这里用了反射

# Method = com.android.server.SystemServer的main函数
mMethod.invoke(null, new Object[] { mArgs });

到这里就算启动了com.android.server.SystemServer,并进入了main()。

疑惑
if (startSystemServer) {
	// fork SystemServer,并返回一个 Runnable
    Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
    if (r != null) {
    	//这里进入了MethodAndArgsCaller的run()
        r.run();
        //哈哈这里return
        return;
    }
}

上面fork出SystemServer后,r不为null,也就是执行了下面代码

if (r != null) {
    r.run();
    return;
}

这里竟然直接return了,那后面代码不执行?

其实不是,这个就需要看Linux中的fork的原理。上面return的只是子进程(SystemServer进程)程序,而父类进程还是会继续往下执行。也就是进入了runSelectLoop()

runSelectLoop()

//循环中。
caller = zygoteServer.runSelectLoop(abiList);

对于父进程,也就是Zygote的会进入循环中;对于子进程SystemServer在上面会return,其他子进程,会返回caller,然后退出。

Runnable runSelectLoop(String abiList) {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
	//mServerSocket是之前创建的socket
    fds.add(mServerSocket.getFileDescriptor());
    peers.add(null);
	//死循环
    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        for (int i = pollFds.length - 1; i >= 0; --i) {
		    //采用I/O多路复用机制,当客户端发出连接请求或者数据处理请求时,则执行continue
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            if (i == 0) {
				//有socket客户端连接上,创建一个新的ZygoteConnection
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
				//添加socket的描述符
                fds.add(newPeer.getFileDesciptor());
            } else {
                try {
				  //客户端发送了请求
                    ZygoteConnection connection = peers.get(i);
				  //这里创建了一个Runnable,是不是子进程,这里会设置
                    final Runnable command = connection.processOneCommand(this);
                    if (mIsForkChild) {
						//如果在子进程,就返回Runnable
                        return command;
                    } else {
					  //判断是否需要关闭socket
                        if (connection.isClosedByPeer()) {
                            connection.closeSocket();
                            peers.remove(i);
                            fds.remove(i);
                        }
                    }
                }
            }
        }
    }
}

runSelectLoop()是个死循环,也就是Zygote是一直存在并处理对应事物的。主要做了如下事

  1. 添加之前创建的socket并获取请求消息

  2. 进入死循环读取请求消息

  3. i == 0时,有新客户端,创建新的ZygoteConnection

  4. i != 0时,处理客户端发送的请求,如果是子进程,就返回Runnable

processOneCommand()

下面就介绍一下,当收到新的子进程创建流程。

Runnable processOneCommand(ZygoteServer zygoteServer) {
    try {
		//从socket读取命令
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }
	//如果没有读取到命令,socket可能断了,
    if (args == null) {
        isEof = true;
        return null;
    }
	//创建Arguments对象,这里会解析args中的命令
    parsedArgs = new Arguments(args);
	//根据参数值进行处理
    if (parsedArgs.abiListQuery) {
        handleAbiListQuery();
        return null;
    }
	//handlePreload也就是之前没有预加载的
    if (parsedArgs.preloadDefault) {
        handlePreload();
        return null;
    }
	//略
	//	fork进程
	pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
            parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
            parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
            parsedArgs.instructionSet, parsedArgs.appDataDir);
    try {
        if (pid == 0) {//如果是子线程,进入这里
            zygoteServer.setForkChild();
            zygoteServer.closeServerSocket();
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            //handleChildProc
            return handleChildProc(parsedArgs, descriptors, childPipeFd,
                    parsedArgs.startChildZygote);
        } else { //如果是父进程,走这里
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            handleParentProc(pid, descriptors, serverPipeFd);
            return null;
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

这里主要如下工作

  1. readArgumentList()从socket读取命令

  2. Arguments解析读取的命令并执行对应的功能

  3. 根据parsedArgs的信息进行fork进程

  4. 处理子进程并返回Runnable

readArgumentList()

主要是从socket中读取命令

private String[] readArgumentList()throws IOException {
    int argc;
    try {
		//socket读取一行命名
        String s = mSocketReader.readLine();
        if (s == null) {
            return null;
        }
        argc = Integer.parseInt(s);
    } catch (NumberFormatException ex) {
        Log.e(TAG, "invalid Zygote wire format: non-int at argc");
        throw new IOException("invalid wire format");
    }
    if (argc > MAX_ZYGOTE_ARGC) {
        throw new IOException("max arg count exceeded");
    }
    String[] result = new String[argc];
    for (int i = 0; i < argc; i++) {
		//读取出所有的命令
        result[i] = mSocketReader.readLine();
        if (result[i] == null) {
            throw new IOException("truncated request");
        }
    }
    return result;
}
Arguments
//创建Arguments对象,这里会解析args中的命令
parsedArgs = new Arguments(args);
Arguments(String args[]) throws IllegalArgumentException {
    parseArgs(args);
}

最终是调用parseArgs()解析命令,很长,略过,就是对命令解析并对parsedArgs的属性进行赋值。

handlePreload()

根据之前parsedArgs中解析的命令,执行对应的功能。我这里以handlePreload()为例。

if (parsedArgs.preloadDefault) {
    handlePreload();
    //返回null,也就是处理完后就不会继续执行后面的代码
    return null;
}
private void handlePreload() {=
    try {
		//判断是否有预加载过,如果有就调过,没有就执行preload()
        if (isPreloadComplete()) {
            mSocketOutStream.writeInt(1);
        } else {
            preload();
            mSocketOutStream.writeInt(0);
        }
    } catch (IOException ioe) {
        throw new IllegalStateException("Error writing to command socket", ioe);
    }
}

isPreloadComplete()返回true的前提是有执行过preload()中调用的ZygoteInit.preload(),后面会看到。

preload()
protected void preload() {
    ZygoteInit.lazyPreload();
}

哈哈 进入ZygoteInit.java

ZygoteInit.lazyPreload()
public static void lazyPreload() {
    Preconditions.checkState(!sPreloadComplete);
    preload(new TimingsTraceLog("ZygoteInitTiming_lazy", Trace.TRACE_TAG_DALVIK));
}
ZygoteInit.preload()
static void preload(TimingsTraceLog bootTimingsTraceLog) {
	//只做了一件事,preloadClasses
    preloadClasses();
	//sPreloadComplete这里赋值为true
    sPreloadComplete = true;
}

preloadClasses()看函数名就名,预加载类,就是提前加载一些类而已。

forkAndSpecialize()

这根据中parsedArgs的信息,然后fork一个新的进程。我们关注pid,不关心怎么fork。

如果pid=0,表示子进程,走处理子进程流程,返回Runnable

如果pid!=0,表示父进程,走处理父进程的流程,返回null

handleChildProc()
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
        FileDescriptor pipeFd, boolean isZygote) {
	//关闭socket通信
    closeSocket();
	//设置进程名
    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }
	//一般这里为invokeWith = null
	//除非parsedArgs解析socket命令行中有对应的命令,略过,看下面
    if (parsedArgs.invokeWith != null) {
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(),
                pipeFd, parsedArgs.remainingArgs);
        throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
    } else {
		//isZygote = false,就是parsedArgs.startChildZygote
        if (!isZygote) {
			//走这里。又回到了ZygoteInit类
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                    null /* classLoader */);
        } else {
            return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }
}
ZygoteInit.zygoteInit()
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
	//RuntimeInit初始化相关
    RuntimeInit.redirectLogStreams();
    RuntimeInit.commonInit();
	//native方法
    ZygoteInit.nativeZygoteInit();
	//执行applicationInit
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

zygoteInit()也是不干活的,真正处理进入RuntimeInit

RuntimeInit.applicationInit()
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {
    nativeSetExitWithoutCleanup(true);
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
	//找到static的main入口
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

也是不干活的,哈哈,这个跟上面启动com.android.server.SystemServer是找到static的mian入口一样的流程了?

最后都一样,findStaticMain()返回Runnable,然后启动run(),通过反射直接进入main()入口,也就是算启动了进程。

到这里,就基本走完了一圈,zygote也一直循环,等待着新的命令进行fork出新的进程。

参考文章

  1. Android Zygote进程的启动流程简单分析

  2. 《深入理解Android卷1(邓凡平)》

  3. zygote启动过程

  4. Android系统启动-综述

版权声明 1、 本站名称 91易搜
2、 本站网址 https://www.91es.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权请留言
4、 本站禁止发布或转载任何违法的相关信息,如有发现请向站长举报
导航号,我的单页导航

暂无评论

评论审核已启用。您的评论可能需要一段时间后才能被显示。

暂无评论...