1。概要
Android
システム内では、 DVM
(Dalvik
仮想マシン)やART
システムのサービスプロセスsystem_server
、アプリケーションプロセスはすべてZygote
プロセスによって作成されます(また、プロセスによって開発されるNative
プログラム、つまりC/C++
プログラムもinit
プロセスによって作成され、起動されます)。Zygote
プロセスはインキュベーターとも呼ばれ、fork(复制进程)
アプリケーションプロセスとsystem_server
プロセスは の形で作成されます。プロセスはまたはZygote
を開始するときに作成するため、アプリケーションプロセスと渡して作成されたプロセスは内部的にまたは のインスタンスコピーを取得できます。DVM
ART
fork
system_server
DVM
ART
Zygote
プロセスは、init
プロセスの開始時に作成されます。最初のZygote
プロセスの名前は ではなくZygote
、 で定義されたapp_process
名前です/frameworks/base/cmds/app_process/Android.mk
。Zygote
プロセスが開始されると、Linux
システム配下のシステムpctrl
は と呼ばれapp_process
、その名前は に変更されますZygote
。
Zygote
モデルですC/S
。Zygote
プロセスはサーバーとして、Socket
メソッドを通じて他のプロセスと通信します。ここでの「他のプロセス」とは主にシステム サービス プロセスを指しますsystem_server
。
Linux
システムではfork
、関数を呼び出して子プロセスを作成する場合、親プロセスのメモリはコピーされませんが、親プロセスと子プロセスはメモリ空間を共有しており、メモリコピーは子プロセスまたは子プロセスが実行されたときにのみ実行されます。親プロセスはメモリ データを変更するため、親プロセスと子プロセスは独自のメモリ空間を持ちます。それまでは、読み取り専用としてのみ共有されます。
コピーオンライト ( copy-on-write
): データが変更されるまでメモリ空間は実際には割り当てられません。これは、データのコピーを遅らせたり、回避したりする可能性がある手法です。これはプログラムのパフォーマンスの最適化であり、不必要なコピーを避けることが目的です。
Zygote
インキュベーターとして、一部のリソースを事前にロードできるため、fork
生成された子プロセスは再ロードせずにこれらのリソースを直接使用できます。たとえば、system_server
プロセスは、Zygote
プロセス内の関数、共有ライブラリ、共通クラス、テーマ リソースを直接使用できますJNI
。
Zygote
プロセスの起動では次のことが行われます。
- メソッドを呼び出し
AppRuntime/AndroidRuntime.start
、Java
仮想マシンを作成し、JNI
そのためのメソッドを登録します。 JNI
メソッドを呼び出して、レイヤーZygoteInit.main
からフレームワークレイヤーNative
に入りますJava
。- プロセスを開始します
system_server
。 ZygoteServer
サーバー側でリクエストを作成しSocket
、ZygoteServer.runSelectLoop
メソッドを通じてリクエストを待機することによりAMS
、新しいアプリケーション プロセスを作成します。
以下にZygote
起動時のタイミング図を示します。
2Zygote
起動スクリプト
init プロセスを開始するプロセスでは、init
プロセスがファイルを解析し、フィールドで指定されたプロセスをinit.rc
作成してロードすることが記載されており、プロセスはこの方法でプロセスによってロードされます。ファイル内の type ステートメントを使用して、初期化言語 ( ) によって記述された起動スクリプトを導入します。service
Zygote
init
init.rc
Import
Zygote
Android
Android Init Language
// /system/core/rootdir/init.rc
import /init.environ.rc
import /init.usb.rc
import /init.${
ro.hardware}.rc
import /vendor/etc/init/hw/init.${
ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${
ro.zygote}.rc // ${ro.zygote} 由厂商定义,与平台无关
init.rc
固定のファイルが直接インポートされるのではなく、ro.zygote
内容に応じて異なるファイルがインポートされることがわかります。
からは1 ビット プログラムのAndroid 5.0
サポートを開始したため、 1 ビットと 1 ビットには違いがあるため、属性を使用して異なる起動スクリプトの使用を制御し、異なるバージョンのプロセスが開始されるようにします。異なるバージョンのプロセスが開始されます。次の値があります。64
Zygote
32
64
ro.zygote
Zygote
Zygote
Zygote
ro.zygote
4
init.zygote32.rc
:Zygote
プロセスに対応する実行プログラムはapp_process
(ピュア32 bit
モード) です。init.zygote32_64.rc
: 2 つのZygote
プロセス (zygote
とzygote_secondary
) を開始し、対応する実行プログラムはapp_process32
(メイン モード)、app_process64
;init.zygote64.rc
:Zygote
プロセスに対応する実行プログラムはapp_process64
(ピュア64 bit
モード) です。init.zygote64_32.rc
: 2 つのZygote
プロセス (zygote
とzygote_secondary
) を開始し、対応する実行プログラムはapp_process64
(メイン モード)、app_process32
;
これらのZygote
起動スクリプトはsystem/core/rootdir
次のディレクトリに配置されます。
64
ビットプロセッサを例にとると、init.zygote64_32.rc
コードは次のようになります。
スクリプトには 2 つの type ステートメントがあり、2 つのプロセスが開始されることService
を示しています。1 つはメイン モードとして という名前で実行プログラムは であり、もう 1 つはセカンダリ モードとして という名前で実行プログラムは です。他のスクリプト ファイルも同様です。Zygote
zygote
app_process64
zygote_secondary
app_process32
たとえばinit.zygote64_32.rc
、起動ファイルのアドレスは/system/bin/app_process64
(上図) で、app_process64
対応するコードは/frameworks/base/cmds/app_process
のディレクトリにあります。
まず、以下を見てくださいAndroid.mk
。
// /frameworks/base/cmds/app_process/Android.mk
LOCAL_PATH:= $(call my-dir)
....
app_process_src_files := \
app_main.cpp \
...
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
...
上記のコードからわかるように、 または のいずれであってもapp_prcess
、app_prcess32
対応app_prcess64
するソース ファイルは ですapp_main.cpp
。
3Zygote
プロセス起動プロセス
init
Zygote
プロセスは主にapp_main.cpp
ファイル内の関数を呼び出すことによって開始されmain
、その中でプロセスは次のメソッドAppRuntime
を呼び出すことによってstart
開始されますZygote
。
// /frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
...
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
// 1
// 如果当前运行在Zygote进程中,则将zygote设置为true
zygote = true; // 2
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
// 3
// 如果当前运行在system_server进程中,则将startSystemServer设置为true
startSystemServer = true; // 4
}
...
}
...
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
// 如果运行在zygote进程中
if (zygote) {
// 5
runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 6
} 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.");
}
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
Zygote
プロセスはfork
自らを介してサブプロセスを作成し、Zygote
プロセスとそのサブプロセスの両方が関数app_main.cpp
のmain
関数に入ることができるようにするためmain
、関数内で現在どのプロセスが実行されているかを区別するために、関数にパラメータが含まれているかどうかを1
判断します。コメント が含まれている場合は、関数がプロセス内で実行されていることを意味し、コメントはに設定されます。同様に、コメントにパラメータが含まれているかどうかを判断し、含まれている場合は関数試行中であることを意味し、コメントにを設定します。arg
--zygote
main
Zygote
2
zygote
true
3
arg
--start-system-server
main
system_server
4
startSystemServer
true
コメントで がであれ5
ば、プロセス内で現在実行中であることを意味し、コメントの関数が呼び出されます。から継承され、メソッドをオーバーライドしなかったので、に入力されたプロセスのコードは次のとおりです。zygote
true
zygote
6
AppRuntime
start
AppRuntime
AndroidRuntime
start
Zygote
AndroidRutime
// /frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
/* start the virtual machine 启动Java虚拟机 */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
// 1
return;
}
onVmCreated(env);
/*
* Register android functions. 为Java虚拟机注册JNI方法
*/
if (startReg(env) < 0) {
// 2
ALOGE("Unable to register all android natives\n");
return;
}
...
// 从app_main的main函数得知className为com.android.internal.os.ZygoteInit
classNameStr = env->NewStringUTF(className); // 3
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);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
* 将className的"."替换为"/"
*/
char* slashClassName = toSlashClassName(className != NULL ? className : ""); // 4
// 找到 zygoteInit
jclass startClass = env->FindClass(slashClassName); // 5
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
// 找到ZygoteInit的main函数
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V"); // 6
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
// 通过JNI调用ZygoteInit的main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray); // 7
#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");
}
コメント1
内の関数を呼び出して仮想マシンstartVm
を作成しJava
、コメント内の関数2
を呼び出して仮想マシンを登録します。注釈内のの値は渡されるパラメータであり、その値は です。コメントの関数を使用して に置換し、置換後の値を に代入し、 に従ってコメントの位置を検索し、 を見つけた後にコメントのメソッドを呼び出します。最後に、コメントでメソッドが呼び出されます。なぜここを使うのか?メソッドは言語で記述されているため、現在実行中のロジックは にあり、 を介して呼び出す必要があります。このようにして、レイヤーからフレームレイヤーに入ります。startReg
Java
JNI
3
className
com.android.internal.os.ZygoteInit
4
toSlashClassName
className
.
/
com/android/internal/os/ZygoteInit
slashClassName
5
slashClassName
ZygoteInit
ZygoteInit
6
ZygoteInit.main
7
JNI
ZygoteInit.main
JNI
ZygoteInit.main
Java
Native
JNI
Java
Zygote
Native
Java
メソッドJNI
を呼び出した後、フレームワーク層に入ります。その前に、コードはフレームワーク層に入りません。つまり、フレームワーク層が作成されました。メソッドのコードは次のとおりです:ZygoteInit.main
Zygote
Java
Java
Zygote
Java
ZygoteInit.main
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
// ZygoteServer是Zygote进程的Socket通讯服务端的管理类
ZygoteServer zygoteServer = null;
...
Runnable caller;
try {
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog); // 1
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
...
zygoteServer = new ZygoteServer(isPrimaryZygote); // 2
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 3
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList); // 4
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}
...
}
コメントは1
クラスとリソースをプリロードします。コメントにより、新しいアプリケーション プロセスの作成要求に応答するチャネルがエンドに2
作成されます。コメントでプロセスを開始すると、システム サービスもプロセスによって開始されます。このメソッドはコメント時に呼び出され、新しいプロセスを作成するリクエストを待ちます。Server
Socket
ActivityManagerService
Zygote
3
system_server
system_server
4
ZygoteServer.runSelectLoop
AMS
上記から、このメソッドは主に 2 つのことを行うことがわかります。ZygoteInit.main
4
- クラスとリソースをプリロードします。
- 作成
Server
側は、新しいアプリケーション プロセスを作成する要求Socket
に応答するために使用されます。ActivityManagerService
system_server
プロセスを開始すると、システム サービスもsystem_server
開始されます。ActivityManagerService
新しいアプリケーションプロセスを作成するリクエストを待っています。