Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1d10973

Browse files
author
ubuntulover
committed
add zygote analyze
1 parent d6e0c76 commit 1d10973

File tree

3 files changed

+419
-12
lines changed

3 files changed

+419
-12
lines changed

Android/Launcher.md

Lines changed: 58 additions & 11 deletions
Large diffs are not rendered by default.

Android/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@
1010

1111
[Android的UI主线程---ActivityThread分析](Android/ActivityThread.md)
1212

13-
[Android系统启动过程分析](Android/Launcher.md)
13+
[Android系统启动过程分析](Android/Launcher.md)
14+
15+
[Android的天字一号进程Zygote](Android/Zygote.md)

Android/Zygote.md

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
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

Comments
 (0)