在《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;
}
}
......
}
最後老規矩,畫時序圖總結。