|
| 1 | +### Zygote的启动 |
| 2 | + |
| 3 | +如果你没有看过[Android启动过程分析](Android/Launcher.md)的话,建议你先看看那里面讲的东西。 |
| 4 | + |
| 5 | +好了,接着上文所讲,我们来看看zygote进程的源码: |
| 6 | + |
| 7 | +```cpp |
| 8 | +int main(int argc, char* const argv[]) |
| 9 | +{ |
| 10 | + ... // 省略一些不必要的调试日志代码 |
| 11 | + AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); |
| 12 | + // Process command line arguments |
| 13 | + // ignore argv[0] |
| 14 | + argc--; |
| 15 | + argv++; |
| 16 | + // 注意看这里的注释,这里的注释基本上有很多解释。 |
| 17 | + // Everything up to '--' or first non '-' arg goes to the vm. |
| 18 | + // |
| 19 | + // The first argument after the VM args is the "parent dir", which |
| 20 | + // is currently unused. |
| 21 | + // |
| 22 | + // After the parent dir, we expect one or more the following internal |
| 23 | + // arguments : |
| 24 | + // 参数名字 |
| 25 | + // --zygote : Start in zygote mode 以zygote模式启动 |
| 26 | + // --start-system-server : Start the system server. 启动系统服务 |
| 27 | + // --application : Start in application (stand alone, non zygote) mode. 应用模式启动 |
| 28 | + // --nice-name : The nice name for this process. 别名 |
| 29 | + // |
| 30 | + // For non zygote starts, these arguments will be followed by |
| 31 | + // the main class name. All remaining arguments are passed to |
| 32 | + // the main method of this class. |
| 33 | + // |
| 34 | + // For zygote starts, all remaining arguments are passed to the zygote. |
| 35 | + // main function. |
| 36 | + // |
| 37 | + // Note that we must copy argument string values since we will rewrite the |
| 38 | + // entire argument block when we apply the nice name to argv0. |
| 39 | + // |
| 40 | + // As an exception to the above rule, anything in "spaced commands" |
| 41 | + // goes to the vm even though it has a space in it. |
| 42 | + const char* spaced_commands[] = { "-cp", "-classpath" }; // 这里指定了classpath,java启动需要这个。 记住这里 |
| 43 | + // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s). |
| 44 | + bool known_command = false; |
| 45 | + |
| 46 | + int i; |
| 47 | + for (i = 0; i < argc; i++) { |
| 48 | + if (known_command == true) { |
| 49 | + runtime.addOption(strdup(argv[i])); |
| 50 | + // The static analyzer gets upset that we don't ever free the above |
| 51 | + // string. Since the allocation is from main, leaking it doesn't seem |
| 52 | + // problematic. NOLINTNEXTLINE |
| 53 | + ALOGV("app_process main add known option '%s'", argv[i]); |
| 54 | + known_command = false; |
| 55 | + continue; |
| 56 | + } |
| 57 | + |
| 58 | + for (int j = 0; |
| 59 | + j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0])); |
| 60 | + ++j) { |
| 61 | + if (strcmp(argv[i], spaced_commands[j]) == 0) { |
| 62 | + known_command = true; |
| 63 | + ALOGV("app_process main found known command '%s'", argv[i]); |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + if (argv[i][0] != '-') { |
| 68 | + break; |
| 69 | + } |
| 70 | + if (argv[i][1] == '-' && argv[i][2] == 0) { |
| 71 | + ++i; // Skip --. |
| 72 | + break; |
| 73 | + } |
| 74 | + |
| 75 | + runtime.addOption(strdup(argv[i])); |
| 76 | + // The static analyzer gets upset that we don't ever free the above |
| 77 | + // string. Since the allocation is from main, leaking it doesn't seem |
| 78 | + // problematic. NOLINTNEXTLINE |
| 79 | + ALOGV("app_process main add option '%s'", argv[i]); |
| 80 | + } |
| 81 | + |
| 82 | + // Parse runtime arguments. Stop at first unrecognized option. |
| 83 | + bool zygote = false; |
| 84 | + bool startSystemServer = false; |
| 85 | + bool application = false; |
| 86 | + String8 niceName; |
| 87 | + String8 className; |
| 88 | + |
| 89 | + ++i; // Skip unused "parent dir" argument. |
| 90 | + while (i < argc) { |
| 91 | + const char* arg = argv[i++]; |
| 92 | + if (strcmp(arg, "--zygote") == 0) { // 判断当前是否是zygote模式启动 |
| 93 | + zygote = true; |
| 94 | + niceName = ZYGOTE_NICE_NAME; |
| 95 | + } else if (strcmp(arg, "--start-system-server") == 0) { |
| 96 | + startSystemServer = true; |
| 97 | + } else if (strcmp(arg, "--application") == 0) { |
| 98 | + application = true; |
| 99 | + } else if (strncmp(arg, "--nice-name=", 12) == 0) { |
| 100 | + niceName.setTo(arg + 12); |
| 101 | + } else if (strncmp(arg, "--", 2) != 0) { |
| 102 | + className.setTo(arg); |
| 103 | + break; |
| 104 | + } else { |
| 105 | + --i; |
| 106 | + break; |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + .... // 省略不必要的代码 |
| 111 | + if (zygote) { |
| 112 | + runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 最后调用runtime.start。 |
| 113 | + } else if (className) { |
| 114 | + runtime.start("com.android.internal.os.RuntimeInit", args, zygote); |
| 115 | + } else { |
| 116 | + fprintf(stderr, "Error: no class name or --zygote supplied.\n"); |
| 117 | + app_usage(); |
| 118 | + LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); |
| 119 | + } |
| 120 | +} |
| 121 | + |
| 122 | +``` |
| 123 | +
|
| 124 | +那么这个runtime是什么? |
| 125 | +
|
| 126 | +它实质上是个AndroidRuntime对象。 |
| 127 | +
|
| 128 | +它的start源码如下: |
| 129 | +
|
| 130 | +代码位置:`$ANDROID_CODEBASE/frameworks/base/core/jni/AndroidRuntime.cpp` |
| 131 | +
|
| 132 | +```cpp |
| 133 | +/* |
| 134 | + * Start the Android runtime. This involves starting the virtual machine |
| 135 | + * and calling the "static void main(String[] args)" method in the class |
| 136 | + * named by "className". |
| 137 | + * |
| 138 | + * Passes the main function two arguments, the class name and the specified |
| 139 | + * options string. |
| 140 | + */ |
| 141 | +void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) |
| 142 | +{ |
| 143 | + ... // 省略不必要的代码 |
| 144 | + /* start the virtual machine */ |
| 145 | + JniInvocation jni_invocation; |
| 146 | + jni_invocation.Init(NULL); |
| 147 | + JNIEnv* env; |
| 148 | + if (startVm(&mJavaVM, &env, zygote) != 0) { |
| 149 | + return; // 注意这里启动了虚拟机,这里就是Java世界啦! |
| 150 | + } |
| 151 | + onVmCreated(env); // 虚拟机启动的回调 |
| 152 | +
|
| 153 | + ... // 省略不必要的代码 |
| 154 | +} |
| 155 | +``` |
| 156 | + |
| 157 | +日后我们有时间分析虚拟机的启动,这里假设成功启动,我们进入ZygoteInit的启动: |
| 158 | + |
| 159 | +代码位置:`$ANDROID_CODE_BASE/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java` |
| 160 | + |
| 161 | +```java |
| 162 | + @UnsupportedAppUsage |
| 163 | + public static void main(String argv[]) { |
| 164 | + ZygoteServer zygoteServer = null; |
| 165 | + |
| 166 | + // Mark zygote start. This ensures that thread creation will throw |
| 167 | + // an error. |
| 168 | + ZygoteHooks.startZygoteNoThreadCreation(); |
| 169 | + |
| 170 | + // Zygote goes into its own process group. |
| 171 | + try { |
| 172 | + Os.setpgid(0, 0); |
| 173 | + } catch (ErrnoException ex) { |
| 174 | + throw new RuntimeException("Failed to setpgid(0,0)", ex); |
| 175 | + } |
| 176 | + |
| 177 | + Runnable caller; |
| 178 | + try { |
| 179 | + // Report Zygote start time to tron unless it is a runtime restart |
| 180 | + if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { |
| 181 | + MetricsLogger.histogram(null, "boot_zygote_init", |
| 182 | + (int) SystemClock.elapsedRealtime()); |
| 183 | + } |
| 184 | + |
| 185 | + String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; |
| 186 | + TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag, |
| 187 | + Trace.TRACE_TAG_DALVIK); |
| 188 | + bootTimingsTraceLog.traceBegin("ZygoteInit"); |
| 189 | + RuntimeInit.enableDdms(); |
| 190 | + |
| 191 | + boolean startSystemServer = false; |
| 192 | + String zygoteSocketName = "zygote"; |
| 193 | + String abiList = null; |
| 194 | + boolean enableLazyPreload = false; |
| 195 | + for (int i = 1; i < argv.length; i++) { |
| 196 | + if ("start-system-server".equals(argv[i])) { // 前面的这个参数一直被传递到这里。 |
| 197 | + startSystemServer = true; |
| 198 | + } else if ("--enable-lazy-preload".equals(argv[i])) { |
| 199 | + enableLazyPreload = true; |
| 200 | + } else if (argv[i].startsWith(ABI_LIST_ARG)) { |
| 201 | + abiList = argv[i].substring(ABI_LIST_ARG.length()); |
| 202 | + } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { |
| 203 | + zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); |
| 204 | + } else { |
| 205 | + throw new RuntimeException("Unknown command line argument: " + argv[i]); |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); |
| 210 | + |
| 211 | + if (abiList == null) { |
| 212 | + throw new RuntimeException("No ABI list supplied."); |
| 213 | + } |
| 214 | + |
| 215 | + // In some configurations, we avoid preloading resources and classes eagerly. |
| 216 | + // In such cases, we will preload things prior to our first fork. |
| 217 | + if (!enableLazyPreload) { |
| 218 | + bootTimingsTraceLog.traceBegin("ZygotePreload"); |
| 219 | + EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, |
| 220 | + SystemClock.uptimeMillis()); |
| 221 | + preload(bootTimingsTraceLog); // 预加载各类资源 |
| 222 | + EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, |
| 223 | + SystemClock.uptimeMillis()); |
| 224 | + bootTimingsTraceLog.traceEnd(); // ZygotePreload |
| 225 | + } else { |
| 226 | + Zygote.resetNicePriority(); |
| 227 | + } |
| 228 | + |
| 229 | + // Do an initial gc to clean up after startup |
| 230 | + bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); |
| 231 | + gcAndFinalize(); |
| 232 | + bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC |
| 233 | + |
| 234 | + bootTimingsTraceLog.traceEnd(); // ZygoteInit |
| 235 | + // Disable tracing so that forked processes do not inherit stale tracing tags from |
| 236 | + // Zygote. |
| 237 | + Trace.setTracingEnabled(false, 0); |
| 238 | + |
| 239 | + |
| 240 | + Zygote.initNativeState(isPrimaryZygote); |
| 241 | + |
| 242 | + ZygoteHooks.stopZygoteNoThreadCreation(); |
| 243 | + |
| 244 | + zygoteServer = new ZygoteServer(isPrimaryZygote); // 这里会去创建一个serverSocket. |
| 245 | + |
| 246 | + if (startSystemServer) { |
| 247 | + Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 干活的地方出现了!这里就是启动的地方。 |
| 248 | + |
| 249 | + // {@code r == null} in the parent (zygote) process, and {@code r != null} in the |
| 250 | + // child (system_server) process. |
| 251 | + if (r != null) { |
| 252 | + r.run(); |
| 253 | + return; |
| 254 | + } |
| 255 | + } |
| 256 | + |
| 257 | + Log.i(TAG, "Accepting command socket connections"); |
| 258 | + |
| 259 | + // The select loop returns early in the child process after a fork and |
| 260 | + // loops forever in the zygote. |
| 261 | + caller = zygoteServer.runSelectLoop(abiList); |
| 262 | + } catch (Throwable ex) { |
| 263 | + Log.e(TAG, "System zygote died with exception", ex); |
| 264 | + throw ex; |
| 265 | + } finally { |
| 266 | + if (zygoteServer != null) { |
| 267 | + zygoteServer.closeServerSocket(); |
| 268 | + } |
| 269 | + } |
| 270 | + |
| 271 | + // We're in the child process and have exited the select loop. Proceed to execute the |
| 272 | + // command. |
| 273 | + if (caller != null) { |
| 274 | + caller.run(); |
| 275 | + } |
| 276 | + } |
| 277 | +``` |
| 278 | + |
| 279 | +可以发现,ZygoteInit这里面其实并不复杂,完成了两个工作: |
| 280 | + |
| 281 | +- 注册一个Socket |
| 282 | + |
| 283 | + Zygote是一个总管家的角色,因此有新程序需要运行时,系统通过这个socket来通知总管家,并且由他来进行进程的孵化。 |
| 284 | + |
| 285 | +- 预加载各类资源。 |
| 286 | + |
| 287 | + ```java |
| 288 | + static void preload(TimingsTraceLog bootTimingsTraceLog) { |
| 289 | + |
| 290 | + beginPreload(); |
| 291 | + |
| 292 | + preloadClasses(); |
| 293 | + |
| 294 | + preloadResources(); |
| 295 | + |
| 296 | + nativePreloadAppProcessHALs(); |
| 297 | + |
| 298 | + maybePreloadGraphicsDriver(); |
| 299 | + |
| 300 | + preloadSharedLibraries(); |
| 301 | + |
| 302 | + preloadTextResources(); |
| 303 | + // Ask the WebViewFactory to do any initialization that must run in the zygote process, |
| 304 | + // for memory sharing purposes. |
| 305 | + WebViewFactory.prepareWebViewInZygote(); |
| 306 | + endPreload(); |
| 307 | + warmUpJcaProviders(); |
| 308 | + Log.d(TAG, "end preload"); |
| 309 | + |
| 310 | + sPreloadComplete = true; |
| 311 | + } |
| 312 | + ``` |
| 313 | + |
| 314 | + |
| 315 | + |
| 316 | +不难从方法名里面看出加载了哪些东西。举个例子,以`preloadClasses()`为例子,它加载了一些常用的类, 这些类 |
| 317 | + |
| 318 | +被记录在`/system/etc/preload-classes`这个文件里面。 |
| 319 | + |
| 320 | +```java |
| 321 | +android.R$styleable |
| 322 | +android.accessibilityservice.AccessibilityServiceInfo$1 |
| 323 | +android.accessibilityservice.AccessibilityServiceInfo |
| 324 | +android.accounts.Account$1 |
| 325 | +android.accounts.Account |
| 326 | +android.accounts.AccountManager$10 |
| 327 | +android.accounts.AccountManager$11 |
| 328 | +android.accounts.AccountManager$18 |
| 329 | +android.accounts.AccountManager$1 |
| 330 | +android.accounts.AccountManager$20 |
| 331 | +android.accounts.AccountManager$2 |
| 332 | +android.accounts.AccountManager$AmsTask$1 |
| 333 | +android.accounts.AccountManager$AmsTask$Response |
| 334 | +android.accounts.AccountManager$AmsTask |
| 335 | +android.accounts.AccountManager$BaseFutureTask$1 |
| 336 | +android.accounts.AccountManager$BaseFutureTask$Response |
| 337 | +android.accounts.AccountManager$BaseFutureTask |
| 338 | +android.accounts.AccountManager$Future2Task$1 |
| 339 | +android.accounts.AccountManager$Future2Task |
| 340 | +android.accounts.AccountManager |
| 341 | +android.accounts.AccountManagerCallback |
| 342 | +android.accounts.AccountManagerFuture |
| 343 | +android.accounts.AccountsException |
| 344 | +... |
| 345 | +``` |
| 346 | + |
| 347 | +里面记录了上千个类,包含了一些常用的系统资源类, |
| 348 | + |
| 349 | +这个文件由`$ANDROID_CODEBASE/frameworks/base/tools/preload/WritePreloadedClassFile.java`这个文件自动生成,这个就是涉及到文件的读写,感兴趣的自行阅读,不作深入分析。 |
| 350 | + |
| 351 | +#### SystemServer的启动 |
| 352 | + |
| 353 | +还记得有个参数`--start-system-server`么?如果调用的时候还有这个参数的话,那么还要启动SystemServer。它的启动是交由`forkSystemServer()`这个函数来启动,我们稍后分析这个函数。 |
| 354 | + |
| 355 | +我们来考虑这么一个问题,Zygote前期负责启动系统服务,后面还要启动程序(孵化程序),但是,这个玩意只会在`init.rc`里面启动一次,它是怎么完成这两个工作呢?我们推测,`forkSystemServer()`会启动一个专门的进程来承载服务的运行,然后`app_process`的进程就负责孵化(当所有应用程序的爹)。是这样么? |
| 356 | + |
| 357 | +还是得去看看代码: |
| 358 | + |
0 commit comments