注册

Android 10 启动分析之Zygote篇 (三)

上一篇文章:

# Android 10 启动分析之servicemanager篇 (二)

app_main

在init篇中有提到,init进程会在在Trigger 为late-init的Action中,启动Zygote服务,这篇文章我们就来具体分析一下Zygote服务,去挖掘一下Zygote负责的工作。

Zygote服务的启动入口源码位于 /frameworks/base/cmds/app_process/app_main.cpp,我们将从这个文件的main方法开始解析。

int main(int argc, char* const argv[])
{

//声明AppRuntime类的实例runtime,在AppRuntime类的构造方法中初始化的skia图形引擎
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

...

bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;

++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
//对于64位系统nice_name为zygote64; 32位系统为zygote
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
//是否需要启动system server
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
//启动进入独立的程序模式
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
//niceName 为当前进程别名,区别abi型号
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}

...

}

可以看到,app_main根据启动时传入参数的区别,分为zygote 模式和application模式。

我们可以从init.zygote64_32.rc文件中看到zygote的启动参数为:

-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote

我们接着往下看:

Vector<String8> args;
if (!className.isEmpty()) {
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
// The Remainder of args get passed to startup class main(). Make
// copies of them before we overwrite them with the process name.
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);

if (!LOG_NDEBUG) {
String8 restOfArgs;
char* const* argv_new = argv + i;
int argc_new = argc - i;
for (int k = 0; k < argc_new; ++k) {
restOfArgs.append(""");
restOfArgs.append(argv_new[k]);
restOfArgs.append("" ");
}
ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
}
} else {
// We're in zygote mode.
//初始化Dalvik虚拟机Cache目录和权限
maybeCreateDalvikCache();

if (startSystemServer) {
//附加上start-system-serve 的arg
args.add(String8("start-system-serve 的argr"));
}

char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}

String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);

// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}

if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}

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.");
}

结合传入的启动参数来看,代码将从if语句的else分支继续往下执行,进入zygote模式。至于application模式我们暂时先忽略它,等我们分析app的启动过程时再来说明。

上述代码最后将通过 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);语句,将控制权限转交给AppRuntime类去继续执行。

继续从AppRuntime的start函数看起:

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{

...

// 虚拟机创建及启动,主要是关于虚拟机参数的设置
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);

//注册JNI方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}

/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;

//等价于strArray[0] = "com.android.internal.os.ZygoteInit"
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);

//strArray[1] = "start-system-server";
//strArray[2] = "--abi-list=xxx";
//其中xxx为系统响应的cpu架构类型,比如arm64-v8a.
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}

/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
//将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//找到这个类后就继续找成员函数main方法的Mehtod ID
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
// 通过Jni调用ZygoteInit.main()方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);

ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}

start()函数主要做了三件事情,一调用startVm开启虚拟机,二调用startReg注册JNI方法,三就是使用JNI把Zygote进程启动起来。

ZygoteInit

通过上述分析,代码进入了ZygoteInit.java中的main方法继续执行。从这里开始,就真正的启动了Zygote进程。我们从/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java这个文件继续往下看。

public static void main(String argv[]) {
//ZygoteServer 是Zygote进程的Socket通讯服务端的管理类
ZygoteServer zygoteServer = null;

// 标记zygote启动开始,调用ZygoteHooks的Jni方法,确保当前没有其它线程在运行
ZygoteHooks.startZygoteNoThreadCreation();

//设置pid为0,Zygote进入自己的进程组
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}

Runnable caller;
try {

...

//开启DDMS(Dalvik Debug Monitor Service)功能
RuntimeInit.enableDdms();

//解析app_main.cpp - start()传入的参数
boolean startSystemServer = false;
String zygoteSocketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
//启动zygote时,传入了参数:start-system-server,会进入此分支
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
//启动zygote_secondary时,才会传入参数:enable-lazy-preload
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
//SOCKET_NAME_ARG 为 zygote 或zygote_secondary,具体请参考 init.zyoget64_32.rc文件
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}

// 根据传入socket name来决定是创建socket还是zygote_secondary
final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);

if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}

// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
// 在第一次zygote启动时,enableLazyPreload为false,执行preload
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 加载进程的资源和类
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}

// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false, 0);


Zygote.initNativeState(isPrimaryZygote);

ZygoteHooks.stopZygoteNoThreadCreation();

// 调用ZygoteServer 构造函数,创建socket Server端,会根据传入的参数,
// 创建两个socket:/dev/socket/zygote 和 /dev/socket/zygote_secondary
zygoteServer = new ZygoteServer(isPrimaryZygote);

if (startSystemServer) {
//fork出system server进程
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
// 启动SystemServer
r.run();
return;
}
}

Log.i(TAG, "Accepting command socket connections");

// ZygoteServer进入无限循环,处理请求
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {4
zygoteServer.closeServerSocket();
}
}

// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}

main方法中主要做了以下几件事:

  1. 加载进程的资源和类。
  2. 根据传入socket name来创建socket server。
  3. fork SystemServer 进程。

preload

既然preload方法是负责加载进程的资源和类,那么它究竟加载了哪些资源和哪些类呢,这些资源又位于什么位置呢?

我们先来看看preload方法里具体做了什么:

static void preload(TimingsTraceLog bootTimingsTraceLog) {

beginPreload();
//预加载类
preloadClasses();

cacheNonBootClasspathClassLoaders();
//加载图片、颜色等资源文件
preloadResources();
//加载HAL相关内容
nativePreloadAppProcessHALs();
//加载图形驱动
maybePreloadGraphicsDriver();
// 加载 android、compiler_rt、jnigraphics等library
preloadSharedLibraries();
//用于初始化文字资源
preloadTextResources();
//用于初始化webview;
WebViewFactory.prepareWebViewInZygote();
endPreload();
warmUpJcaProviders();


sPreloadComplete = true;
}

preloadClasses

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


} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally {
...
}
}

可以看到,preloadClasses方法读取/system/etc/preloaded-classes文件的内容,并通过Class.forName初始化类。那么在/system/etc/preloaded-classes文件具体有哪些类呢?

由于内容过多,我这里只截取部分截图让大家看看具体装载是什么类。

image.png

image.png

image.png

从装载列表中,我们可以看到很多熟悉的类,实际上,装载的类都是我们应用程序运行时可能用到的java类。

preloadResources

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


mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, "Failure preloading resources", e);
}
}

从上述代码可以看到,preloadResources加载了特定的图片资源和颜色资源。这些资源的路径又具体在哪里呢?

com.android.internal.R.array.preloaded_drawables的路径位于/frameworks/base/core/res/res/values/arrays.xml中,其他的资源路径也可以类似找到。各位读者可以自行去该路径下去看看所包含的资源文件到底是什么样的。

preloadSharedLibraries

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

preloadSharedLibraries里的内容很简单,主要是加载位于/system/lib目录下的libandroid.so、libcompiler_rt.so、libjnigraphics.so三个so库。


我们不妨想一下,为什么android要在Zygote中将资源先进行预加载,这么做有什么好处?

这个问题留给各位读者去自行思考,在这里便不再回答了。

forkSystemServer

 private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
...


return null;
}

forkSystemServer方法只是fork了一个Zygote的子进程,而handleSystemServerProcess方法构造了一个Runnable对象,创建一个子线程用于启动SystemServer的逻辑。

private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
Os.umask(S_IRWXG | S_IRWXO);

if (parsedArgs.mNiceName != null) {
//nicename 为 system_server
Process.setArgV0(parsedArgs.mNiceName);
}

...

if (parsedArgs.mInvokeWith != null) {
String[] args = parsedArgs.mRemainingArgs;
// 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.mInvokeWith,
parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);

throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
//parsedArgs.mInvokeWith 为null,会进入此分支
createSystemServerClassLoader();
ClassLoader cl = sCachedSystemServerClassLoader;
if (cl != null) {
Thread.currentThread().setContextClassLoader(cl);
}

/*
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, cl);
}

/* should never reach here */
}

继续从ZygoteInit.zygoteInit看起:

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

RuntimeInit.commonInit();
//注册两个jni函数
//android_internal_os_ZygoteInit_nativePreloadAppProcessHALs
//android_internal_os_ZygoteInit_nativePreloadGraphicsDriver
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

RuntimeInit.applicationInit

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
//true代表应用程序退出时不调用AppRuntime.onExit(),否则会在退出前调用
nativeSetExitWithoutCleanup(true);

//设置虚拟机的内存利用率参数值为0.75
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

final Arguments args = new Arguments(argv);

// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);
}

继续看findStaticMain:

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

}

这里通过反射获得了 com.android.server.SystemServer 类中的main方法,并传递给MethodAndArgsCaller用于构造一个Runnable。只要执行此Runnable,就会开始调用com.android.server.SystemServer 类中的main方法。

到此,Zygote的逻辑已经全部执行完毕,android启动进入了SystemServer的阶段。

最后,我们再用一个流程图来总结一下Zygote的业务逻辑:

app_mainAppRuntimeZygoteInit进入Zygote模式创建及启动Dalvik注册Jni方法预加载进程的资源和类Zygote创建socket Server端fork SystemServer子进程载入SystemServer逻辑进入无限循环,处理请求app_mainAppRuntimeZygoteInit

0 个评论

要回复文章请先登录注册