深入理解android卷1 第4章:深入理解Zygote
第4章:深入理解Zygote
核心主题:Android系统的孵化器 - Zygote进程
关键知识点速查
1. Zygote概述
作用:
- 所有Java应用进程的父进程
- 预加载Framework类和资源,加速应用启动
- 通过fork()机制孵化应用进程
- 启动SystemServer进程
启动时机:
init进程解析init.rc → 启动Zygote → app_process进程启动 → ZygoteInit.main()
名称由来:Zygote(受精卵),寓意所有应用进程都从它分裂而来
2. Zygote的启动流程
完整流程:
init进程
↓ 解析init.rc
service zygote /system/bin/app_process ...
↓ fork+exec
app_process进程
↓
AppRuntime.start()(C++层)
↓ 启动虚拟机
AndroidRuntime::start()
↓ 通过JNI调用Java层
ZygoteInit.main()(Java层)
↓
├── preloadClasses() // 预加载Framework类
├── preloadResources() // 预加载系统资源
├── registerZygoteSocket() // 创建Socket服务端
├── startSystemServer() // 启动SystemServer
└── runSelectLoop() // 进入循环等待
3. init.rc中的Zygote配置
32位Zygote:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
64位+32位双Zygote(Android 5.0+):
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
socket zygote stream 660 root system
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
socket zygote_secondary stream 660 root system
关键选项说明:
--zygote:以Zygote模式启动--start-system-server:启动后fork SystemServer--socket-name=zygote:Socket名称socket zygote stream 660 root system:创建Unix Domain Socketonrestart:Zygote重启时重启依赖的服务(因为所有进程都是它fork的)
4. 预加载机制
4.1 预加载类(preloadClasses)
加载清单:/system/etc/preloaded-classes(约4000+个类)
核心类包括:
android.app.*(Activity、Service等)android.view.*(View、ViewGroup等)android.widget.*(TextView、Button等)android.os.*(Handler、Looper等)java.lang.*、java.util.*(Java基础类)
代码实现:
// ZygoteInit.java
private static void preloadClasses() {
InputStream is = ZygoteInit.class.getClassLoader()
.getResourceAsStream("preloaded-classes");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = br.readLine()) != null) {
// 跳过注释和空行
if (line.startsWith("#") || line.trim().isEmpty()) continue;
try {
// 加载类到内存
Class.forName(line, true, null);
} catch (ClassNotFoundException e) {
Log.w(TAG, "Class not found for preloading: " + line);
}
}
}
为什么要预加载?
- 加速应用启动:应用fork后直接使用,无需再次加载
- 节省内存:通过COW机制,所有进程共享这部分内存
4.2 预加载资源(preloadResources)
加载内容:
- 系统drawable资源
- 颜色值(colors)
- 布局文件缓存
代码实现:
private static void preloadResources() {
final Resources resources = Resources.getSystem();
// 预加载drawable
preloadDrawables(resources);
// 预加载color
preloadColorStateLists(resources);
}
private static void preloadDrawables(Resources resources) {
int[] drawables = {
com.android.internal.R.drawable.btn_default,
com.android.internal.R.drawable.btn_check,
// ... 更多系统drawable
};
for (int id : drawables) {
resources.getDrawable(id, null);
}
}
4.3 预加载共享库(preloadSharedLibraries)
加载的so库:
libandroid.solibcompiler_rt.solibjnigraphics.solibwebviewchromium_loader.so
private static void preloadSharedLibraries() {
System.loadLibrary("android");
System.loadLibrary("compiler_rt");
System.loadLibrary("jnigraphics");
}
预加载时机图:
ZygoteInit.main()
↓
preloadClasses() // 耗时最长(~1-2秒)
↓
preloadResources() // 耗时中等(~500ms)
↓
preloadSharedLibraries() // 耗时短(~100ms)
↓
registerZygoteSocket()
5. Socket通信机制
5.1 Socket服务端创建
代码实现:
// ZygoteInit.java
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
// 从环境变量获取Socket的fd(由init进程创建)
String env = System.getenv(fullSocketName);
int fileDesc = Integer.parseInt(env);
// 创建LocalServerSocket
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
sServerSocket = new LocalServerSocket(fd);
}
}
Socket路径:/dev/socket/zygote(Unix Domain Socket)
为什么使用LocalSocket而不是网络Socket?
- 同一主机内通信更高效
- 无需网络协议栈开销
- 支持传递文件描述符
5.2 客户端连接(AMS侧)
连接代码:
// ZygoteProcess.java(AMS中使用)
public static class ZygoteState {
private final LocalSocket socket;
ZygoteState(String socketName) throws IOException {
socket = new LocalSocket();
socket.connect(new LocalSocketAddress(socketName,
LocalSocketAddress.Namespace.RESERVED));
this.writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()), 256);
this.reader = new DataInputStream(socket.getInputStream());
}
}
5.3 消息格式
请求消息示例(启动Activity):
--runtime-args
--setuid=10086
--setgid=10086
--target-sdk-version=30
--nice-name=com.eufy.security
com.android.internal.os.ZygoteInit
--application
com.eufy.security.MainActivity
参数说明:
--runtime-args:后续参数为运行时参数--setuid/setgid:应用的UID/GID(10000+)--target-sdk-version:目标SDK版本--nice-name:进程名称- 最后是启动类名
响应消息:
pid=12345 // fork出的子进程PID
6. 应用进程的孵化流程
6.1 完整流程图
应用冷启动
↓
AMS收到启动请求
↓
Process.start()
↓
ZygoteProcess.start()
↓ 通过Socket发送请求
Zygote.runSelectLoop()
↓ 接收到连接
Zygote.acceptCommandPeer()
↓ 读取参数
ZygoteConnection.processOneCommand()
↓ 解析参数
Zygote.forkAndSpecialize()
↓ 调用native方法
nativeForkAndSpecialize()(C++)
↓ 调用Linux系统调用
fork()
↓ 分裂为两个进程
父进程(Zygote) 子进程(应用进程)
↓ ↓
返回pid到AMS handleChildProc()
↓
RuntimeInit.zygoteInit()
↓
ZygoteInit.zygoteInit()
↓
ActivityThread.main()
↓
应用进程启动完成
6.2 核心代码分析
Zygote主循环:
// ZygoteInit.java
private static void runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<>();
ArrayList<ZygoteConnection> peers = new ArrayList<>();
// 将ServerSocket的fd加入监听列表
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
// 使用poll()等待事件
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;
}
Os.poll(pollFds, -1); // 阻塞等待
for (int i = pollFds.length - 1; i >= 0; i--) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
// ServerSocket有新连接
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDescriptor());
} else {
// 已有连接发来数据
boolean done = peers.get(i).runOnce(this);
if (done) {
// 处理完毕,移除连接
peers.remove(i);
fds.remove(i);
}
}
}
}
}
fork()并设置子进程属性:
// Zygote.java
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName,
int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote,
String instructionSet, String appDataDir) {
// 执行GC,减少COW的内存占用
ZygoteHooks.preFork();
// 调用native方法fork
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName,
fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir);
if (pid == 0) {
// 子进程
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
ZygoteHooks.postForkChild(runtimeFlags, instructionSet);
} else {
// 父进程(Zygote)
ZygoteHooks.postForkCommon();
}
return pid;
}
C++层的fork实现(关键部分):
// com_android_internal_os_Zygote.cpp
static jint nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, ...) {
// 1. fork前准备(停止线程池等)
PreFork();
// 2. 调用Linux的fork()系统调用
pid_t pid = fork();
if (pid == 0) {
// 子进程
// 3. 设置子进程属性
setgid(gid);
setuid(uid);
setgroups(gids);
// 4. 设置SELinux上下文
setcon(seInfo);
// 5. 设置进程名
setproctitle(niceName);
// 6. 挂载应用数据目录
MountAppData(appDataDir);
// 7. fork后处理(重启线程池等)
PostForkChild(env);
} else if (pid > 0) {
// 父进程(Zygote)
PostForkParent(env);
}
return pid;
}
6.3 Copy-On-Write(写时复制)机制
原理:
fork()后:
Zygote进程(父进程) 应用进程(子进程)
↓ ↓
虚拟内存(页表) 虚拟内存(页表)
↓ 映射 ↓ 映射
同一块物理内存(只读权限)
↓
子进程尝试写入
↓ 触发缺页异常(Page Fault)
内核复制该页到新物理页
↓
子进程写入新物理页
优势:
- 节省内存:预加载的类和资源在多个进程间共享
- 加速fork:无需复制所有内存,只复制页表
- 按需分配:只在写入时才真正复制
实测数据:
- Zygote进程内存:约80MB(预加载内容)
- fork新进程耗时:约10-50ms(远快于从头加载)
- 新进程初始内存:约10-20MB(私有内存,共享内存不计)
6.4 子进程处理流程
handleChildProc()代码:
// ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd) {
// 关闭从父进程继承的Socket
closeSocket();
// 设置进程名
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
if (parsedArgs.invokeWith != null) {
// 使用指定的命令启动(调试模式)
WrapperInit.execApplication(parsedArgs.invokeWith, ...);
} else {
// 正常启动
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null);
}
}
RuntimeInit.zygoteInit():
// RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
// 重定向System.out/err到Android日志系统
commonInit();
// 启动Binder线程池
nativeZygoteInit();
// 调用应用的main方法(ActivityThread.main())
applicationInit(targetSdkVersion, argv, classLoader);
}
ActivityThread.main():
// ActivityThread.java
public static void main(String[] args) {
// 准备主线程Looper
Looper.prepareMainLooper();
// 创建ActivityThread实例
ActivityThread thread = new ActivityThread();
thread.attach(false); // 绑定到AMS
// 进入消息循环
Looper.loop();
// 不应该走到这里
throw new RuntimeException("Main thread loop unexpectedly exited");
}
7. 启动SystemServer
forkSystemServer()流程:
// ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName) {
// 准备参数
String args[] = {
"--setuid=1000", // UID=1000(system用户)
"--setgid=1000", // GID=1000
"--setgroups=1001,1002,1003...", // 加入多个用户组
"--capabilities=" + capabilities, // 赋予系统能力
"--nice-name=system_server", // 进程名
"--runtime-args",
"com.android.server.SystemServer", // 启动类
};
ZygoteConnection.Arguments parsedArgs =
new ZygoteConnection.Arguments(args);
// fork SystemServer进程
int pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids, parsedArgs.runtimeFlags,
null, parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
if (pid == 0) {
// 子进程(SystemServer)
if (hasSecondZygote(abiList)) {
// 等待zygote_secondary启动
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs);
}
return true;
}
为什么SystemServer要单独fork?
- 权限不同:SystemServer是system用户(UID=1000),应用是普通用户
- 生命周期不同:SystemServer系统启动即创建,应用按需创建
- 职责不同:SystemServer托管系统服务,应用运行用户代码
8. Zygote64位和32位
为什么需要两个Zygote?(Android 5.0+)
Zygote64 (app_process64) Zygote32 (app_process32)
↓ ↓
64位虚拟机(ART64) 32位虚拟机(ART32)
↓ ↓
fork 64位应用 fork 32位应用
↓ ↓
运行64位native库(.so) 运行32位native库(.so)
应用如何选择Zygote?
// Process.java
public static final ProcessStartResult start(String processClass, ...) {
// 根据ABI确定使用哪个Zygote
if (useZygote64) {
return startViaZygote(processClass, ..., "zygote");
} else {
return startViaZygote(processClass, ..., "zygote_secondary");
}
}
判断依据:
- AndroidManifest.xml中的
android:use32bitAbi - 应用包含的native库(.so文件)架构
- 系统默认(64位设备优先使用64位)
查看应用使用的Zygote:
adb shell ps -ef | grep zygote
# 输出示例
root 123 1 ... zygote64
root 124 1 ... zygote
system 456 123 ... system_server # PPID=123,由zygote64 fork
u0_a86 789 123 ... com.eufy.security # 64位应用
u0_a87 890 124 ... com.example.app32 # 32位应用
架构图
init进程 (PID=1)
↓ 解析init.rc
service zygote /system/bin/app_process ...
↓ fork+exec
app_process进程
├── C++层: AppRuntime::start()
│ ├── 启动虚拟机(ART/Dalvik)
│ └── 调用Java层main()
│
└── Java层: ZygoteInit.main()
├── preloadClasses() // 预加载4000+类
├── preloadResources() // 预加载系统资源
├── registerZygoteSocket() // 创建/dev/socket/zygote
├── startSystemServer() // fork SystemServer进程
│ └── SystemServer.main()
│ └── 启动60+系统服务
│
└── runSelectLoop() // 进入消息循环
↓ 监听Socket连接
↓ AMS请求fork应用
↓
forkAndSpecialize()
├── fork() // Linux系统调用
├── setuid/setgid // 设置UID/GID
└── handleChildProc() // 子进程处理
└── ActivityThread.main()
└── 应用启动完成
重要概念
1. Zygote的特殊性
- 进程名:zygote(64位)、zygote_secondary(32位)
- 父进程:init(PPID=1)
- 启动时机:系统启动early boot阶段
- 永不退出:进入无限循环,系统运行期间一直存在
- 崩溃后果:所有应用进程被杀(因为父进程消失),系统重启
2. 预加载的意义
内存视角:
Zygote预加载(80MB)
↓ fork()
应用进程1(COW共享80MB + 私有10MB)
应用进程2(COW共享80MB + 私有15MB)
应用进程3(COW共享80MB + 私有12MB)
如果不预加载:
应用进程1(独立加载80MB + 私有10MB = 90MB)
应用进程2(独立加载80MB + 私有15MB = 95MB)
应用进程3(独立加载80MB + 私有12MB = 92MB)
节省内存:277MB - 117MB = 160MB(3个应用的情况)
启动速度视角:
- 预加载方案:fork耗时约10-50ms
- 不预加载方案:加载类耗时约1000-2000ms
- 加速效果:20-200倍
3. fork()的安全机制
UID/GID隔离:
Zygote进程
↓ fork()
应用进程1(UID=10086,com.eufy.security)
应用进程2(UID=10087,com.example.app)
应用进程3(UID=10088,com.third.app)
- 每个应用分配唯一的UID(10000起始)
- UID不同的应用无法访问彼此的数据目录
- 实现应用沙箱隔离
SELinux上下文:
// fork后设置SELinux标签
setcon("u:r:untrusted_app:s0:c86,c256,c512,c768");
- 限制应用的系统调用权限
- 限制文件访问权限
- 增强安全性
4. Socket vs Binder
为什么Zygote使用Socket而不是Binder?
- 时机问题:Zygote启动时ServiceManager还未启动,无法使用Binder
- fork安全:Binder在多线程环境下fork不安全(子进程只继承调用fork的线程)
- 简单可靠:LocalSocket通信简单,适合进程创建场景
Binder线程池启动时机:
Zygote fork应用进程
↓ 子进程
handleChildProc()
↓
RuntimeInit.zygoteInit()
↓
nativeZygoteInit() // 这里才启动Binder线程池
↓
应用可以使用Binder通信
关键代码位置
| 功能 | 文件路径 |
|---|---|
| Zygote入口(Java) | frameworks/base/core/java/com/android/internal/os/ZygoteInit.java |
| Zygote实现(Java) | frameworks/base/core/java/com/android/internal/os/Zygote.java |
| Socket连接处理 | frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java |
| Runtime初始化 | frameworks/base/core/java/com/android/internal/os/RuntimeInit.java |
| C++层实现 | frameworks/base/core/jni/com_android_internal_os_Zygote.cpp |
| AppRuntime | frameworks/base/cmds/app_process/app_main.cpp |
| 客户端(AMS侧) | frameworks/base/core/java/android/os/ZygoteProcess.java |
| init.rc配置 | system/core/rootdir/init.zygote64_32.rc |
实战要点
1. 查看Zygote进程
# 查看Zygote进程
adb shell ps | grep zygote
# 输出示例
root 123 1 ... zygote64
root 124 1 ... zygote
# 查看子进程
adb shell ps | grep " 123 " # PPID=123的进程
2. 查看预加载类列表
adb shell cat /system/etc/preloaded-classes | head -20
# 输出示例
android.app.Activity
android.app.ActivityThread
android.app.Application
android.content.Context
android.view.View
android.view.ViewGroup
android.widget.TextView
...
3. 监控Zygote启动过程
adb logcat | grep Zygote
# 输出示例
Zygote : Preloading classes...
Zygote : ...preloaded 4873 classes in 1234ms.
Zygote : Preloading resources...
Zygote : ...preloaded 312 resources in 234ms.
Zygote : Accepting command socket connections
4. 查看应用fork日志
adb logcat | grep "Start proc"
# 输出示例
ActivityManager: Start proc 12345:com.eufy.security/u0a86 for activity {com.eufy.security/.MainActivity}
5. 测量应用启动时间
# 冷启动测量
adb shell am start -W com.eufy.security/.MainActivity
# 输出
Starting: Intent { act=android.intent.action.MAIN ... }
Status: ok
Activity: com.eufy.security/.MainActivity
ThisTime: 256 # Activity启动耗时
TotalTime: 1234 # 从fork到Activity显示的总耗时
WaitTime: 1240 # 包含AMS处理时间
6. 模拟Zygote崩溃
# 杀死Zygote进程(需要root权限)
adb shell su -c "kill -9 $(pidof zygote)"
# 结果:
# 1. 所有应用进程被杀(父进程消失)
# 2. init进程重启Zygote
# 3. Zygote重新预加载
# 4. 系统恢复正常(但所有应用需重新启动)
7. 查看进程内存分布(COW验证)
# 查看进程内存映射
adb shell cat /proc/$(pidof com.eufy.security)/smaps | grep -A 15 "classes.dex"
# 输出示例
7f1234000-7f5678000 r--s ... /system/framework/boot.art
Size: 67584 kB
Rss: 45120 kB # 实际占用物理内存
Pss: 2256 kB # 按比例分摊的内存(共享内存/共享进程数)
Shared_Clean: 45120 kB # 干净的共享内存(从Zygote继承)
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB # 写时复制产生的内存
性能优化
1. 减少预加载耗时
官方优化手段:
- 并行预加载类(多线程)
- 延迟加载非关键类
- 使用预编译(AOT)减少JIT耗时
厂商定制优化:
// 自定义预加载类列表(去掉不常用的类)
# vendor/overlay/frameworks/base/core/res/res/raw/preloaded-classes
# 从4873个类减少到3000个类
# 预加载时间从1.2秒减少到0.8秒
2. 优化fork耗时
减少Zygote内存占用:
- 减少预加载内容
- 使用mmap映射文件(不占用内存)
- 及时GC(fork前调用gc())
代码示例:
// Zygote.java
static int forkAndSpecialize(...) {
// fork前执行GC,减少COW内存占用
ZygoteHooks.preFork(); // 内部调用gc()
int pid = nativeForkAndSpecialize(...);
// ...
}
3. 应用启动优化
利用预加载机制:
- 使用系统预加载的类(避免重复加载)
- 避免Application中执行耗时操作
- 延迟初始化非关键组件
反例:
// Application.onCreate()中执行耗时操作(会阻塞应用启动)
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// ❌ 不要在这里初始化大型库
HugeLibrary.init(this); // 耗时500ms
}
}
正确做法:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// ✅ 异步初始化
new Thread(() -> HugeLibrary.init(this)).start();
}
}
快速回忆检查点
- Zygote是所有Java应用进程的父进程?
- Zygote通过init.rc配置启动?
- Zygote预加载4000+类和系统资源?
- Zygote使用LocalSocket而不是Binder通信?
- fork()使用Copy-On-Write机制节省内存?
- SystemServer由Zygote fork创建?
- Android 5.0+有64位和32位两个Zygote?
- 应用进程的UID从10000开始分配?
与T87A0项目的关联
应用场景
1. 应用启动优化
// EufySecurityApplication.java
public class EufySecurityApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// 了解Zygote机制后的优化:
// 1. 避免在Application中初始化大型库(会阻塞启动)
// 2. 利用系统预加载的类(如Handler、AsyncTask)
// 3. 异步初始化非关键组件
// 异步初始化SDK
ThreadPoolExecutor executor = ...;
executor.execute(() -> {
IoTSDK.init(this);
VideoPlaybackSDK.init(this);
});
}
}
2. 进程管理
// 了解Zygote机制后,理解多进程架构
// AndroidManifest.xml
<service
android:name=".service.DownloadService"
android:process=":download" /> // 独立进程,单独fork
// 优势:
// - 独立内存空间(不影响主进程)
// - 独立生命周期(可单独重启)
// - 隔离崩溃(下载服务崩溃不影响主进程)
3. 内存优化
// 利用COW机制优化内存
// 1. 静态常量在多进程间共享(从Zygote继承)
public class Constants {
// ✅ 静态常量,所有进程共享,不占用私有内存
public static final String API_URL = "https://api.eufy.com";
public static final int TIMEOUT = 30000;
}
// 2. 避免在静态变量中缓存大对象(会触发COW)
public class ImageCache {
// ❌ 静态缓存,写入时触发COW,增加内存占用
private static Map<String, Bitmap> sCache = new HashMap<>();
}
4. 调试技巧
# 查看EufySecurity的进程信息
adb shell ps | grep eufy
# 输出示例
u0_a86 12345 123 ... com.eufy.security # 主进程,PPID=123(zygote64)
u0_a86 12346 123 ... com.eufy.security:download # 下载进程
# 查看内存分布(验证COW)
adb shell dumpsys meminfo com.eufy.security
# Native Heap: 10 MB (私有内存)
# Dalvik Heap: 15 MB (私有内存)
# Code: 45 MB (共享内存,从Zygote继承)
# Graphics: 8 MB (私有内存)
理解应用启动流程
用户点击EufySecurity图标
↓
Launcher发送启动Intent
↓
AMS收到请求
↓
AMS通过Socket连接Zygote
↓
Zygote fork应用进程
├── setuid(10086) // EufySecurity的UID
└── setProcessName("com.eufy.security")
↓
子进程启动ActivityThread
↓
绑定到AMS(attach)
↓
AMS调度启动MainActivity
↓
Application.onCreate()
↓
Activity.onCreate()
↓
应用界面显示
排查启动问题
慢启动分析:
# 1. 查看启动耗时
adb shell am start -W com.eufy.security/.MainActivity
# ThisTime: 1500ms ← 如果超过1秒,需要优化
# 2. 抓取启动trace
adb shell am start -P startup.trace com.eufy.security/.MainActivity
adb pull /data/local/tmp/startup.trace
# 使用Android Studio Profiler分析
# 3. 查看Application初始化耗时
adb logcat | grep "EufySecurityApplication"
崩溃分析:
# 如果应用启动后立即崩溃
adb logcat | grep "AndroidRuntime"
# 常见错误:
# - ClassNotFoundException:预加载类未包含,需要手动加载
# - UnsatisfiedLinkError:native库加载失败
# - SecurityException:权限不足(SELinux拒绝)
关联章节
- 第3章:深入理解init - Zygote的启动依赖init进程
- 第5章:深入理解SystemServer - SystemServer由Zygote fork创建
- 卷2第9章:深入理解AMS - AMS通过Zygote启动应用进程
推荐阅读
官方文档:
- Android源码:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java - Linux手册:
man 2 fork(fork系统调用)
深入文章:
- 《深入理解Android内核设计思想》第7章
- 《Android系统源代码情景分析》第6章
- Gityuan博客:Android系统启动-Zygote篇
相关主题:
- Copy-On-Write机制
- Linux进程管理
- Binder vs Socket选择
- Android应用沙箱机制
更多推荐



所有评论(0)