在《Android 源码 启动 zygote service 流程分析》我们已经知道 zygote service 是在 Init 进程的 service_start 方法启动的。接下来就会运行 /system/bin/app_process,代表 zygote 运行。
在前一节的分析已知 dynamic_args 参数为 NULL,所以最终会调用 execve 运行子进程。
system/core/init/init.cpp
void service_start(struct service *svc, const char *dynamic_args)
{
......
pid_t pid = fork();
if (pid == 0) {
......
if (!dynamic_args) {
......
} else {
char *arg_ptrs[INIT_PARSER_MAXARGS+1];
int arg_idx = svc->nargs;
char *tmp = strdup(dynamic_args);
char *next = tmp;
char *bword;
/* 复制静态参数 */
memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));
while((bword = strsep(&next, " "))) {
arg_ptrs[arg_idx++] = bword;
if (arg_idx == INIT_PARSER_MAXARGS)
break;
}
arg_ptrs[arg_idx] = NULL;
execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
}
_exit(127);
}
......
}
execve 定义在头文件 unistd.h 中。
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
在父进程中 fork 一个子进程,在子进程中调用 exec 函数启动新的程序。exec 函数一共有六个,其中 execve 为内核级系统调用,其他(execl、execle、execlp、execv 和 execvp)都是调用 execve 的库函数。
execve() 用来执行参数 filename 字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。
如果执行成功则函数不会返回,执行失败则直接返回 -1,失败原因存于 errno 中。
接下来运行程序:out/target/product/hammerhead/system/bin/app_process,它是 app_main.cpp 编译而来的二进制产物。
在 app_main main 方法中创建了运行时 AppRuntime,接着准备了运行时参数,最后调用了其 start 方法启动 ZygoteInit Java 类。
frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
......
// 创建 AppRuntime
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// 处理命令行参数
// 忽略 argv[0]
argc--;
argv++;
int i;
for (i = 0; i < argc; i++) {
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
runtime.addOption(strdup(argv[i]));
}
// 解析运行时参数
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // 跳过未使用的“父目录”参数
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;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
......
} else {
// 处于 zygote 模式
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
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);
// 将所有剩余参数传递给 zygote main() 方法
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
......
} else {
......
}
}
创建 AppRuntime 对象,将参数传递到父类构造器 AndroidRuntime 进行初始化。
frameworks/base/cmds/app_process/app_main.cpp
namespace android {
......
class AppRuntime : public AndroidRuntime
{
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL)
{
}
......
};
}
AndroidRuntime 类定义在头文件 android_runtime/AndroidRuntime.h 中,最后调用 start 方法启动 com.android.internal.os.ZygoteInit。
frameworks/base/include/android_runtime/AndroidRuntime.h
namespace android {
class AndroidRuntime
{
public:
AndroidRuntime(char* argBlockStart, size_t argBlockSize);
......
void start(const char *classname, const Vector<String8>& options, bool zygote);
.....
}
下面是其实现,位于 AndroidRuntime.cpp 中。
start 方法的作用:
启动Android运行时。这涉及启动虚拟机并在 “className” 命名的类中调用 “static void main(String [] args)” 方法。向 main 函数传递两个参数,即类名和指定的选项字符串。
frameworks/base/core/jni/AndroidRuntime.cpp
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
// 预分配足够的空间来容纳大量选项。
mOptions.setCapacity(20);
assert(gCurRuntime == NULL); // one per process
gCurRuntime = this;
}
......
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);
/*
* 注册 android 函数
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* 使用包含参数的 String 数组调用 main()。目前,有两个参数,即类名和选项字符串。
* 创建一个数组来保存它们。
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
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);
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);
}
/*
* 启动 VM。该线程成为 VM 的主线程,直到 VM 退出后才返回。
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
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");
}
接下来就开始运行 zygote service,进入了 Java 的世界!在主函数中 zygote 服务实现了本地 socket 服务端监听,同时也启动了 system server 进程。这是重中之重的工作!
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public class ZygoteInit {
......
public static void main(String argv[]) {
try {
RuntimeInit.enableDdms();
// 分析器相关:开始
SamplingProfilerIntegration.start();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = 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)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
// 注册 socket 服务端
registerZygoteSocket(socketName);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 加载资源
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// 分析器相关:结束
SamplingProfilerIntegration.writeZygoteSnapshot();
// 启动后进行初始 gc 清理
gcAndFinalize();
// 禁用跟踪,以便 fork 的进程不会从 Zygote 继承过时的跟踪标记
Trace.setTracingEnabled(false);
if (startSystemServer) {
// 启动 SystemServer
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
......
}
最后老规矩,画时序图总结。