Java 世界的盘古和女娲 —— Zygote

// 从环境变量中获取 socket 的 fd
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}

try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc); // 设置文件描述符
mServerSocket = new LocalServerSocket(fd); // 创建服务端 socket
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
“Error binding to local socket '” + fileDesc + “'”, ex);
}
}
}

首先从环境变量中获取 socket 的文件描述符 fd,然后根据 fd 创建服务端 LocalServerSocket,用于 IPC 通信。这里的环境变量是在 init 进程创建 Zygote 进程时设置的。

preload()

ZygoteInit.java

static void preload(TimingsTraceLog bootTimingsTraceLog) {

preloadClasses(); // 预加载并初始化 /system/etc/preloaded-classes 中的类

preloadResources(); // 预加载系统资源

nativePreloadAppProcessHALs(); // HAL?

preloadOpenGL(); // 预加载 OpenGL

preloadSharedLibraries(); // 预加载 共享库,包括 android、compiler_rt、jnigraphics 这三个库
preloadTextResources(); // 预加载文字资源
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
// WebViewFactory 中一些必须在 zygote 进程中进行的初始化工作,用于共享内存
WebViewFactory.prepareWebViewInZygote();
warmUpJcaProviders();

sPreloadComplete = true;
}

preload() 方法主要进行一些类,资源,共享库的预加载工作,以提升运行时效率。下面依次来看一下都预加载了哪些内容。

preloadClasses()

ZygoteInit.java

private static void preloadClasses() {

InputStream is;
try {
// /system/etc/preloaded-classes
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn’t find " + PRELOADED_CLASSES + “.”);
return;
}

try {
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256);

int count = 0;
String line;
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith(“#”) || line.equals(“”)) {
continue;
}

try {
// Load and explicitly initialize the given class. Use
// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
// (to derive the caller’s class-loader). Use true to force initialization, and
// null for the boot classpath class-loader (could as well cache the
// class-loader of this class in a variable).
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
Log.w(TAG, "Class not found for preloading: " + line);
} catch (UnsatisfiedLinkError e) {
Log.w(TAG, "Problem preloading " + line + ": " + e);
} catch (Throwable t) {

}
}
} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + “.”, e);
} finally {
IoUtils.closeQuietly(is);

}
}

只保留了核心逻辑代码。读取 /system/etc/preloaded-classes 文件,并通过 Class.forName() 方法逐行加载文件中声明的类。提前预加载系统常用的类无疑可以提升运行时效率,但是这个预加载常用类的工作通常都会很重。搜索整个源码库,在 /frameworks/base/config 目录下发现一份 preloaded-classes 文件,打开这个文件,一共 6558 行,这就意味着要提前加载数千个类,这无疑会消耗很长时间,以增加 Android 系统启动时间的代价提升了运行时的效率。

preloadResources()

ZygoteInit.java

private static void preloadResources() {
final VMRuntime runtime = VMRuntime.getRuntime();

try {
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(ar);
ar.recycle();

ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(ar);
ar.recycle();

if (mResources.getBoolean(
com.android.internal.R.bool.config_freeformWindowManagement)) {
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
N = preloadDrawables(ar);
ar.recycle();
}
}
mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, “Failure preloading resources”, e);
}
}

从源码中可知,主要加载的资源有:

com.android.internal.R.array.preloaded_drawables

com.android.internal.R.array.preloaded_color_state_lists

com.android.internal.R.array.preloaded_freeform_multi_window_drawables

preloadSharedLibraries()

ZygoteInit.java

private static void preloadSharedLibraries() {
Log.i(TAG, “Preloading shared libraries…”);
System.loadLibrary(“android”);
System.loadLibrary(“compiler_rt”);
System.loadLibrary(“jnigraphics”);
}

预加载了三个共享库,libandroid.solibcompiler_rt.solibjnigraphics.so

gcAndFinalize()

ZygoteInit.java

static void gcAndFinalize() {
final VMRuntime runtime = VMRuntime.getRuntime();

/* runFinalizationSync() lets finalizers be called in Zygote,

  • which doesn’t have a HeapWorker thread.
    */
    System.gc();
    runtime.runFinalizationSync();
    System.gc();
    }

forkSystemServer() 之前会主动进行一次 GC 操作。

forkSystemServer()

主动调用 GC 之后,Zygote 就要去做它的大事 —— fork SystemServer 进程了。

ZygoteInit.java

private static Runnable forkSystemServer(String abiList, String socketName,

/* Hardcoded command line to start the system server */
// 启动参数
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”, // 加载类名
};
ZygoteConnection.Arguments parsedArgs = null;

int pid;

try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

boolean profileSystemServer = SystemProperties.getBoolean(
“dalvik.vm.profilesystemserver”, false);
if (profileSystemServer) {
parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}

/* Request to fork the system server process

  • fork system_server 进程
    */
    pid = Zygote.forkSystemServer(
    parsedArgs.uid, parsedArgs.gid,
    parsedArgs.gids,
    parsedArgs.runtimeFlags,
    null,
    parsedArgs.permittedCapabilities,
    parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
    throw new RuntimeException(ex);
    }

/* For child process */
// pid == 0 表示子进程,从这里开始进入 system_server 进程
if (pid == 0) {
if (hasSecondZygote(abiList)) { // 如果有第二个 Zygote
waitForSecondaryZygote(socketName);
}

zygoteServer.closeServerSocket(); // 关闭并释放从 Zygote copy 过来的 socket
return handleSystemServerProcess(parsedArgs); // 完成新创建的 system_server 进程的剩余工作
}

/**

  • 注意 fork() 函数式一次执行,两次返回(两个进程对同一程序的两次执行)。
  • pid > 0 说明还是父进程。pid = 0 说明进入了子进程
  • 所以这里的 return null 依旧会执行
    */
    return null;
    }

从上面的启动参数可以看到,SystemServer 进程的 uidgid 都是 1000,进程名是 system_server ,其最后要加载的类名是 com.android.server.SystemServer 。准备好一系列参数之后通过 ZygoteConnection.Arguments() 拼接,接着调用 Zygote.forkSystemServer() 方法真正的 fork 出子进程 system_server

Zygote.java

public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities);
// Enable tracing as soon as we enter the system_server.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
}
VM_HOOKS.postForkCommon();
return pid;
}

native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);

最后的 fork() 操作是在 native 层完成的。再回到 ZygoteInit.forkSystemServer() 中执行 fork() 之后的逻辑处理:

if(pid == 0){

return handleSystemServerProcess(parsedArgs);
}

return null;

按正常逻辑思维,这两处 return 只会执行一次,其实不然。fork() 函数是一次执行,两次返回。说的更严谨一点是 两个进程对用一个程序的两次执行。当 pid == 0 时,说明现在处于子进程,当 pid > 0 时,说明处于父进程。在刚 fork 出子进程的时候,父子进程的数据结构基本是一样的,但是之后就分道扬镳了,各自执行各自的逻辑。所以上面的代码段中会有两次返回值,子进程 (system_server) 中会返回执行 handleSystemServerProcess(parsedArgs) 的结果,父进程 (zygote) 会返回 null。对于两个不同的返回值又会分别做什么处理呢?我们回到 ZygoteInit.main() 中:

if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
// r == null 说明是在 zygote 进程
// r != null 说明是在 system_server 进程
if (r != null) {
r.run();
return;
}
}

// 循环等待处理客户端请求
caller = zygoteServer.runSelectLoop(abiList);

子进程 system_server 返回的是一个 Runnable,执行 r.run(),然后就直接 return 了。而父进程 zygote 返回的是 null,所以不满足 if 的判断条件,继续往下执行 runSelectLoop 。父子进程就此分道扬镳,各干各的事。

下面就来分析 runSelectLoop()handleSystemServerProcess() 这两个方法,看看 ZygoteSystemServer 这对父子进程继续做了些什么工作。

handleSystemServerProcess

到这里其实已经脱离 Zygote 的范畴了,本准备放在下一篇 SystemServer 源码解析中再介绍,可是这里不写又觉得 Zygote 介绍的不完整,索性就一并说了。

ZygoteInit.java

private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
// set umask to 0077 so new files and directories will default to owner-only permissions.
// umask一般是用在你初始创建一个目录或者文件的时候赋予他们的权限
Os.umask(S_IRWXG | S_IRWXO);

// 设置当前进程名为 “system_server”
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}

final String systemServerClasspath = Os.getenv(“SYSTEMSERVERCLASSPATH”);
if (systemServerClasspath != null) {
// dex 优化操作
performSystemServerDexOpt(systemServerClasspath);
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
boolean profileSystemServer = SystemProperties.getBoolean(
“dalvik.vm.profilesystemserver”, false);
if (profileSystemServer && (Build.IS_USERDEBUG || Build.IS_ENG)) {
try {
prepareSystemServerProfile(systemServerClasspath);
} catch (Exception e) {
Log.wtf(TAG, “Failed to set up system server profile”, e);
}
}
}

if (parsedArgs.invokeWith != null) { // invokeWith 一般为空
String[] args = parsedArgs.remainingArgs;
// If we have a non-null system server class path, we’ll have to duplicate the
// existing arguments and append the classpath to it. ART will handle the classpath
// correctly when we exec a new process.
if (systemServerClasspath != null) {
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = “-cp”;
amendedArgs[1] = systemServerClasspath;
System.arraycopy(args, 0, amendedArgs, 2, args.length);
args = amendedArgs;
}

WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);

throw new IllegalStateException(“Unexpected return from WrapperInit.execApplication”);
} else {
ClassLoader cl = null;
if (systemServerClasspath != null) {
// 创建类加载器,并赋给当前线程
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

Thread.currentThread().setContextClassLoader(cl);
}

/*

  • Pass the remaining arguments to SystemServer.
    */
    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }

/* should never reach here */
}

设置进程名为 system_server,执行 dex 优化,给当前线程设置类加载器,最后调用 ZygoteInit.zygoteInit() 继续处理剩余参数。

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {

// Redirect System.out and System.err to the Android log.
// 重定向 System.out 和 System.err 到 Android log
RuntimeInit.redirectLogStreams();

RuntimeInit.commonInit(); // 一些初始化工作
ZygoteInit.nativeZygoteInit(); // native 层初始化
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); // 调用入口函数
}

重定向 Log,进行一些初始化工作。这部分不细说了,点击文章开头给出的源码链接,大部分都做了注释。最后调用 RuntimeInit.applicationInit() ,继续追进去看看。

RuntimeInit.java

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {


final Arguments args = new Arguments(argv); // 解析参数


// 寻找 startClass 的 main() 方法。这里的 startClass 是 com.android.server.SystemServer
return findStaticMain(args.startClass, args.startArgs, classLoader);
}

这里的 startClass 参数是 com.android.server.SystemServerfindStaticMain() 方法看名字就能知道它的作用是找到 main() 函数,这里是要找到 com.android.server.SystemServer 类的 main() 方法。

protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;

try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}

Method m;
try {
// 寻找 main() 方法
m = cl.getMethod(“main”, new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}

int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}

/*

  • This throw gets caught in ZygoteInit.main(), which responds
  • by invoking the exception’s run() method. This arrangement
  • clears up all the stack frames that were required in setting
  • up the process.
  • 返回一个 Runnable,在 Zygote 的 main() 方法中执行器 run() 方法
  • 之前的版本是抛出一个异常,在 main() 方法中捕获
    */
    return new MethodAndArgsCaller(m, argv);
    }

找到 main() 方法并构建一个 Runnable 对象 MethodAndArgsCaller 。这里返回的 Runnable 对象会在哪里执行呢?又要回到文章开头的 ZygoteInit.main() 函数了,在 forkSystemServer() 之后,子进程执行 handleSystemServerProcess() 并返回一个 Runnable 对象,在 ZygoteInit.main() 中会执行其 run() 方法。

再来看看 MethodAndArgsCallerrun() 方法吧!

static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;

/** argument array */
private final String[] mArgs;

public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}

public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}

就一件事,执行参数中的 method。这里的 method 就是 com.android.server.SystemServermain() 方法。到这里,SystemServer 就要正式工作了。

其实在老版本的 Android 源码中,并不是通过这种方法执行 SystemServer.main() 的。老版本的 MethodAndArgsCallerException 的子类,在这里会直接抛出异常,然后在 ZygoteInit.main() 方法中进行捕获,捕获之后执行其 run() 方法。

SystemServer 的具体分析就放到下篇文章吧,本篇的主角还是 Zygote

看到这里,Zygote 已经完成了一件人生大事,孵化出了 SystemServer 进程。但是作为 “女娲” ,造人的任务还是停不下来,任何一个应用进程的创建还是离不开它的。ZygoteServer.runSlectLoop() 给它搭好了和客户端之前的桥梁。

runSelectLoop

ZygoteServer.java

Runnable runSelectLoop(String abiList) {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();

// mServerSocket 是之前在 Zygote 中创建的
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;
}
try {
// 有事件来时往下执行,没有时就阻塞
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {

最近我根据上述的技术体系图搜集了几十套腾讯、头条、阿里、美团等公司21年的面试题,把技术点整理成了视频(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分

相关阅读docs.qq.com/doc/DSmxTbFJ1cmN1R2dB
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;
}
try {
// 有事件来时往下执行,没有时就阻塞
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {

[外链图片转存中…(img-SWIytzCg-1724658357305)]

最近我根据上述的技术体系图搜集了几十套腾讯、头条、阿里、美团等公司21年的面试题,把技术点整理成了视频(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分

[外链图片转存中…(img-9ku2ji48-1724658357305)]

相关阅读docs.qq.com/doc/DSmxTbFJ1cmN1R2dB

  • 26
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值