Zygote
zygote启动脚本
init.zygote.rc文件是 Zygote 进程的启动配置文件。安卓通过init.rc文件来引入(import)相应的 init.zygote.rc文件的。这是一个动态选择的过程,获取 ro.zygote的属性值,根据属性值拼接文件名。
init.rc和init.zygote.rc都位于system/core/rootdir目录下:
bash
/system/core/rootdir⟫ ls init.zygote*
init.zygote32.rc init.zygote64_32.rc init.zygote64.rc
可以看到在system/core/rootdir文件夹下有多个init.zygote.rc文件,那具体是哪个呢?可以看init.rc,在里面搜索zygote字样,可以发现在init.rc中用import导入的是${ro.zygote}.rc,这是一个动态拼接的,根据ro.zygote这个属性:
rc
init.rc
import /system/etc/init/hw/init.${ro.zygote}.rc
然后在命令行中输入adb shell getprop ro.zygote,就可以确定是哪个init.zygote.rc,根据命令输出,这里执行的是init.zygote64_32.rc这个rc文件:
makefile
C:\Users\cmy>adb shell getprop ro.zygote
zygote64_32
zygote启动脚本内容
perl
# init.zygote64_32.rc
import /system/etc/init/hw/init.zygote64.rc
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
socket usap_pool_secondary stream 660 root system
onrestart restart zygote
task_profiles ProcessCapacityHigh MaxPerformance
init.zygote64_32.rc第一行就引入了init.zygote64.rc,所以实际执行链是:
csharp
先执行 init.zygote64.rc
再执行 init.zygote64_32.rc 剩余内容
也就是:
csharp
init.zygote64.rc (定义主zygote)
↓
init.zygote64_32.rc (补 secondary zygote)
最终生效的是两个文件共同组成的结果
perl
# init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
# NOTE: If the wakelock name here is changed, then also
# update it in SystemSuspend.cpp
onrestart write /sys/power/wake_lock zygote_kwl
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart --only-if-running media.tuner
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
关键在init.zygote64.rc第一句: 大概得知Zygote进程名称为zygote,执行程序为app_process64,class name为main。 app_process一般可以通过framework目录下grep app_process。这里要搜索app_process而不是app_process64,因为你搜app_process64搜不到内容,搜app_process才可以。根据网上的资料说搜不到 app_process64,因为 它不是一个单独源码模块名,而是由同一个二进制通过安装阶段生成的符号链接/别名 。在init.zygote32.rc中,默认就是service zygote /system/bin/app_process。马哥视频教的就是init.zygote32.rc,我自己太菜了,不行我也分析这个。
在framework目录下执行grep "app_process" ./ -rn 结果如下:
bash
./base/cmds/app_process/Android.bp:19: name: "app_process"
代码路径:frameworks/base/cmds/app_process/
app_process文件夹中,主入口位于app_main.cpp
shell
frameworks/base/cmds/app_process$ ls
Android.bp app_main.cpp cmds MODULE_LICENSE_APACHE2 NOTICE version-script.txt
app_process中app_main.cpp源码分析
cpp
/* frameworks/base/cmds/app_process/app_main.cpp */
#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif
int main(int argc, char* const argv[])
{
...
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
...
// Parse runtime arguments. Stop at first unrecognized option.
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; //变量zygote设置
niceName = ZYGOTE_NICE_NAME; // ZYGOTE_NICE_NAME为zygote或者zygote64
} 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 = (arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className = arg;
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.empty()) {
...
} else {
...
}
if (!niceName.empty()) {
// 设置进程名
runtime.setArgv0(niceName.c_str(), true /* setProcName */);
}
if (zygote) {
//之前分析的zygote为true,走这里
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (!className.empty()) {
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.");
}
}
zygote进程调用runtime.start("com.android.internal.os.ZygoteInit", args, zygote),因为AppRuntime runtime继承AndroidRuntime,所以需要分析AndroidRuntime的start方法。
AndroidRuntime的start方法
cpp
/* frameworks/base/core/jni/AndroidRuntime.cpp */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//启动java需要的jvm环境,java虚拟机环境
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
// toSlashClassName将com.android.internal.os.ZygoteInit变成com/android/internal/os/ZygoteInit
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
...
} else {
//找className的main方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
...
} else {
// c++调用java的main方法
//关键调用对应的"com.android.internal.os.ZygoteInit"类main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
...
}
上面可以看出app_main主要做的工作就是准备虚拟机环境,让进程运行到了java层的ZygoteInit的main方法。
ZygoteInit的main方法
cpp
/* frameworks/base/core/java/com/android/internal/os/ZygoteInit.java */
public static void main(String[] argv) {
// ZygoteServer对象
ZygoteServer zygoteServer = null;
...
Runnable caller;
try {
...
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])) {
startSystemServer = true;
}
...
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(bootTimingsTraceLog); // 加载资源
...
}
...
//创建SocketServer端
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
// 核心就是forkSystemServer方法
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) {
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);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with fatal exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
static void preload(TimingsTraceLog bootTimingsTraceLog) {
...
preloadClasses();
...
}
/**
* The path of a file that contains classes to preload.
*/
// 预加载class路径
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
// 读取/system/etc/preloaded-classes,其中preloaded-classes可以在framework中用find命令搜索
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
...
}
ZygoteInit.java的main方法中核心就是forkSystemServer方法。根据一路搜索,最终可以定位到frameworks/base/core/jni/com_android_internal_os_Zygote.cpp的zygote::ForkCommon方法。
简单调用
ZygoteInit.java的main调用forkSystemServer ↓ ZygoteInit.java的forkSystemServer调用Zygote.forkSystemServer ↓ frameworks/base/core/java/com/android/internal/os/Zygote.java的forkSystemServer调用nativeForkSystemServer。
private static native int nativeForkSystemServer其中nativeForkSystemServer是native方法,调用cpp。这里搜索nativeForkSystemServer有两种方法: 一种是直接在framework下搜索**
grep "_nativeForkSystemServer(" ./ -rn** ,最好是加下划线,因为cpp中对应的native方法一般都会有下划线。 第二种是,Zygote.java里的native方法,一般对应在Zygote.cpp中,搜索文件可以看到com_android_internal_os_Zygote.cpp,为什么说是这个cpp,看文件名com_android_internal_os_Zygote跟com/android/internal/os/Zygote.java一一对应。↓ frameworks/base/core/jni/com_android_internal_os_Zygote.cpp的com_android_internal_os_Zygote_nativeForkSystemServer调用zygote::ForkCommon ↓ com_android_internal_os_Zygote.cpp的ForkCommon调用linux系统的fork()
cpp
/* frameworks/base/core/jni/com_android_internal_os_Zygote.cpp */
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
bool is_priority_fork,
bool purge) {
...
pid_t pid = fork(); // 最终调用的这里fork()函数,这里是真正创建子进程的地方
if (pid == 0) {
...
} else if (pid > 0) {
...
}
return pid;
}
新知识
一台电脑连接多台设备
当一台电脑通过usb连接两台设备时,进行adb操作会出现歧义:
makefile
C:\Users\cmy>adb devices
List of devices attached
21639818 device
d6876cf4 device
C:\Users\cmy>adb shell
adb.exe: more than one device/emulator 在这里,adb不知道选哪一台设备
方法1
通过adb -s 设备序列号 你要进行的操作。其中s的含义是SERIAL序列号的缩写,用adb --help可以查看
makefile
C:\Users\cmy>adb -s d6876cf4 shell
ZM10:/ $
adb -s d6876cf4 logcat
adb -s d6876cf4 install app.apk
如果你要用 && 进行连续操作,也只需要在第一个操作中加 -s
vbnet
C:\Users\cmy>adb -s d6876cf4 root && adb remount && adb shell
adbd is already running as root
Verity is already disabled
Remounted /system as RW
Remounted /system_ext as RW
Remounted /vendor as RW
Remounted /vendor_dlkm as RW
Remounted /system_dlkm as RW
Remounted /odm as RW
Remounted /product as RW
Remounted /oem as RW
Remounted /vendor/dsp as RW
Remount succeeded
ZM10:/ #
方法2
在当前窗口中设置临时环境变量ANDROID_SERIAL,仅当前窗口有效 ,至于为什么是ANDROID_SERIAL,这个是写死的,可以用adb --help命令查看关于-s的说明。
在Windows的cmd中
bash
设置
set ANDROID_SERIAL=d6876cf4
查看
echo %ANDROID_SERIAL%
在你设置完ANDROID_SERIAL,在当前窗口 执行任何adb操作都不需要加-s了,默认都是ANDROID_SERIAL指定的那个。但是要注意,仅对当前窗口起作用
vbnet
C:\Users\cmy>set ANDROID_SERIAL=d6876cf4
C:\Users\cmy>echo %ANDROID_SERIAL%
d6876cf4
C:\Users\cmy>adb shell
ZM10:/ #
查看当前 Android 系统的所有环境变量
adb shell env