盒子
盒子
文章目录
  1. AndroidRuntime
    1. 创建虚拟机
    2. JNI方法注册
    3. 参数、类、方法构建与调用
  2. ZygoteInit
    1. 注册Socket
    2. 预加载
    3. SystemServer
    4. runSelectLoop
    5. processOneCommand
  3. 项目

Android Java Zygote启动

Android init 启动

Android Linux Zygote启动

在之前的文章中我们已经分析到Zygote最后在Linux的init进程中是通过如下代码启动Java层的ZygoteInit。

1
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);

所以我们进入runtime.start()方法看下它的具体实现。

AndroidRuntime

frameworks/base/core/jni/AndroidRuntime.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());

static const String8 startSystemServer("start-system-server");
// Whether this is the primary zygote, meaning the zygote which will fork system server.
bool primary_zygote = false;

/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
primary_zygote = true;
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}

const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /system does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}

const char* artRootDir = getenv("ANDROID_ART_ROOT");
if (artRootDir == NULL) {
LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
return;
}

const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
if (i18nRootDir == NULL) {
LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
return;
}

const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
if (tzdataRootDir == NULL) {
LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
return;
}

//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 1. 创建虚拟机
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);

/*
* Register android functions.
*/
// 2. 使用JNI注册对应的Android Native 方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}

/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;

// 3. 拼接参数,获取ZygoteInit Class 与 main方法id
// 获取 str = new String[options.size() + 1]
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);

// 获取 str[0] = "com.android.internal.os.ZygoteInit"
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);

// 获取 str[1] = "start-system-server"
// 获取 str[2] = "--abi-list=xxxx"
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.
*/

// 获取 "com/android/internal/os/ZygoteInit"
char* slashClassName = toSlashClassName(className != NULL ? className : "");
// 获取ZygoteInit Class
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
// 获取 ZygoteInit中的main方法对应的方法id
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 {
// 4. 调用 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");
}

根据上面的代码注释,小憩将start()方法分为四步:

  1. 创建虚拟机
  2. 通过JNI注册Android Native方法
  3. 拼接参数、获取ZygoteInit Class与其对应的main方法id
  4. 调用ZygoteInit.main()方法,进去Java层

创建虚拟机

通过startVm()来创建虚拟机。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
JavaVMInitArgs initArgs;
char propBuf[PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
char heapminfreeOptsBuf
....

parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");

....

initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;

/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}

return 0;
}

该方法很长,但主要任务就是设置虚拟机的相关参数,具体各个属性的作用就不做分析,感兴趣的可以自行google对应搜索。

JNI方法注册

通过startReg()来注册Android Native方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");

/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);

// 通过JNI注册
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);

//createJavaThread("fubar", quickTest, (void*) "hello");

return 0;
}

主要部分是通过register_jni_procs来注册JNI方法。对应的是gRegJNI

1
2
3
4
5
6
7
8
9
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
...
}

方法很多就不一一列举出来。

举个例子,例如:

1
2
3
4
5
6
7
8
9
10
11
register_com_android_internal_os_ZygoteInit_nativeZygoteInit

int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
methods, NELEM(methods));
}

对应的就是com/android/internal/os/ZygoteInit中的nativeZygoteInit()方法,而nativeZygoteInit()方法通过JNI注册之后,在Linux的具体实现是对应的com_android_internal_os_ZygoteInit_nativeZygoteInit()方法。

1
2
3
4
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}

最后它会调用onZygoteInit()方法,它的具体实现在app_main.cpp中

1
2
3
4
5
6
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}

参数、类、方法构建与调用

在这一步主要通过FindClass()方法来获取对应Java的Class类型,构建对应的String[]类型的参数与ZygoteInit Class。

再通过GetStaticMethodID()方法来获取对应main()方法的方法id,以便为之后调用ZygoteInit.main()方法做准备。

最后在通过CallStaticVoidMethod()来调用ZygoteInit.main()方法,最终进入Java层的ZygoteInit。

从runtime.start()到调用Java层的ZygoteInit.main()的整个过程流程图如下:

ZygoteInit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
public static void main(String argv[]) {
// 创建zygoteServer
ZygoteServer zygoteServer = new ZygoteServer();

ZygoteHooks.startZygoteNoThreadCreation();

// 设置zygote自己的进程group id
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}

final Runnable caller;
try {
// Report Zygote start time to tron unless it is a runtime restart
if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
MetricsLogger.histogram(null, "boot_zygote_init",
(int) SystemClock.elapsedRealtime());
}

String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
RuntimeInit.enableDdms();

// 解析参数,这些参数来自于`Linux`层
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
// 是否需要启动system_server服务
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
// 是否需要懒加载
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
// 获取abi_list
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
// 获取socket名称
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.");
}

// 注册zygote的socket
zygoteServer.registerServerSocketFromEnv(socketName);
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 预加载
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}

// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
// 触发gc
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false, 0);

Zygote.nativeSecurityInit();

// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();

ZygoteHooks.stopZygoteNoThreadCreation();

// 启动 system_server
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, 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");

// 进入循环模式
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}

// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}

终于见到Java代码了,不容易啊~

首先会创建zygoteServer,为Zygote设置自己的进程分组id;然后会解析传递过来的参数,根据参数执行之后的后续操作。

注册Socket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}

try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}

通过registerServerSocketFromEnv来注册socket,使用LocalServerSocket创建本地socket服务,来监听对于的文件描述符fd。

预加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void preload(TimingsTraceLog bootTimingsTraceLog) {
// 预加载位于/system/etc/preloaded-classes文件中的类
preloadClasses();

// 预加载资源,保存drawable与color
preloadResources();

// 预加载OpenGL
preloadOpenGL();

// 预加载共享库,包括android、compiler_rt、jnigraphics
preloadSharedLibraries();

// 预加载 文本连接符资源
preloadTextResources();

// 仅用于zygote进程,用于内存共享的进程
WebViewFactory.prepareWebViewInZygote();

endIcuCachePinning();
warmUpJcaProviders();

sPreloadComplete = true;
}

对于类加载,采用反射机制Class.forName()方法来加载。

对于资源加载,主要是com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在应用程序中以com.android.internal.R.xxx开头的资源,便是此时由Zygote加载到内存的。

在这里预加载目的是为了之后fork出子的进程,同时使用copy on write技术,使得子进程在只读模式下与父进程共用一块内存空间,从而保证子进程能够迅速fork处理,减少数据的拷贝数量。

SystemServer

1
2
3
4
5
6
7
8
9
10
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, 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;
}
}

创建system_server服务,具体实现后续到system_server的时候再分析。

runSelectLoop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

// 保存fd
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);

while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
// 轮询,当pollFds有事件到来则往下执行,否则阻塞在这里
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
// 采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行
// 否则进入continue,跳出本次循环
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}

if (i == 0) {
// 即fds[0],代表的是sServerSocket,则意味着有客户端连接请求
// 则创建ZygoteConnection对象,并添加到fds
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
// i>0,则代表通过socket接收来自对端的数据,并执行相应操作
try {
// 获取链接
ZygoteConnection connection = peers.get(i);
// 执行操作
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
if (command == null) {
throw new IllegalStateException("command == null");
}

return command;
} else {
if (command != null) {
throw new IllegalStateException("command != null");
}

if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
if (!mIsForkChild) {

Slog.e(TAG, "Exception executing zygote command: ", e);

ZygoteConnection conn = peers.remove(i);
conn.closeSocket();

fds.remove(i);
} else {
Log.e(TAG, "Caught post-fork exception in child process.", e);
throw e;
}
} finally {
mIsForkChild = false;
}
}
}
}
}

Zygote采用高效的I/O多路复用机制,保证在没有客户端连接请求或数据处理时休眠,否则响应客户端的请求。

processOneCommand

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;

try {
// 读取参数
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}

// readArgumentList returns null only when it has reached EOF with no available
// data to read. This will only happen when the remote socket has disconnected.
if (args == null) {
isEof = true;
return null;
}

int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;

// 解析参数,并进行转换
parsedArgs = new Arguments(args);

...

fd = zygoteServer.getServerSocketFileDescriptor();

if (fd != null) {
fdsToClose[1] = fd.getInt$();
}

fd = null;

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);

try {
if (pid == 0) {
// 子进程执行
zygoteServer.setForkChild();

zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;

return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
// 父进程执行
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}

通过fork方法来创建子进程,该方法会返回两次结果;如果为0则代表当前需要执行子进程的相关逻辑,非0则是父进程的逻辑。

至此Zygote的启动就完成了。

所以在Java层Zygote主要做的事情为:

  1. 通过registerServerSocketFromEnv来注册socket
  2. 通过preload预加载类、drawable与color资源、openGL、共享库与WebView相关资源
  3. 创建system_server服务
  4. runSelectLoop等待新消息的到来,并创建新进程

Zygote中的一个重要步骤:启动system_server后续再进行分析,敬请期待!

项目

android_startup: 提供一种在应用启动时能够更加简单、高效的方式来初始化组件,优化启动速度。不仅支持Jetpack App Startup的全部功能,还提供额外的同步与异步等待、线程控制与多进程支持等功能。

AwesomeGithub: 基于Github的客户端,纯练习项目,支持组件化开发,支持账户密码与认证登陆。使用Kotlin语言进行开发,项目架构是基于JetPack&DataBinding的MVVM;项目中使用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等流行开源技术。

flutter_github: 基于Flutter的跨平台版本Github客户端,与AwesomeGithub相对应。

android-api-analysis: 结合详细的Demo来全面解析Android相关的知识点, 帮助读者能够更快的掌握与理解所阐述的要点。

daily_algorithm: 每日一算法,由浅入深,欢迎加入一起共勉。

支持一下
赞赏是一门艺术