版权归作者所有,如有转发,请注明文章出处:cyrus-studio.github.io/blog/
APP 启动流程
app 启动流程大概如下:
arduino
发起进程(startActivity/startService...)
↓
↓(Binder方式)
↓
system_server进程(Process.start)
↓
↓(Socket方式)
↓
Zygote进程(ZygoteInit.runSelectLoop())
↓
新建进程(ActivityThread.main)
ActivityThread.main() 是 Android 应用进程的入口函数。
1. 应用 → AMS(Binder)
由 ActivityManager.getService() 返回的 Binder 接口对象调用系统服务:
scss
// 应用进程
ContextImpl.startActivity()
└── Instrumentation.execStartActivity()
└── ActivityManager.getService().startActivity() ← AIDL Binder 跨进程
└── ActivityManagerService.startActivity()
通过 AIDL 实现 Binder 跨进程通信,连接系统服务。
关于 Android 中 AIDL 实现 Binder 跨进程通信 可以参考:Android中的Service与进程间通信(IPC)详解
AMS 接口实现:
2. AMS/system_server → zygote(Socket)
startActivity 最终调用到 Process.start 方法
less
475 /**
476 * State associated with the zygote process.
477 * @hide
478 */
479 public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
480
481 /**
482 * Start a new process.
520 */
521 public static ProcessStartResult start(@NonNull final String processClass,
522 @Nullable final String niceName,
523 int uid, int gid, @Nullable int[] gids,
524 int runtimeFlags,
525 int mountExternal,
526 int targetSdkVersion,
527 @Nullable String seInfo,
528 @NonNull String abi,
529 @Nullable String instructionSet,
530 @Nullable String appDataDir,
531 @Nullable String invokeWith,
532 @Nullable String packageName,
533 @Nullable String[] zygoteArgs) {
534 return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
535 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
536 abi, instructionSet, appDataDir, invokeWith, packageName,
537 /*useUsapPool=*/ true, zygoteArgs);
538 }
ZygoteProcess.start() 中调用 startViaZygote 方法。
使用本地 UNIX socket 通信(通常路径为 /dev/socket/zygote),发送 fork 参数到 zygote socket:
scss
// system_server 进程
ZygoteProcess.startViaZygote(...) // 使用 socket 连接 zygote
Zygote 接收 socket 后 fork 出新的应用进程:
scss
// zygote 进程
ZygoteServer.runSelectLoop() // 接收 socket 请求
整个通信过程大概如下:
scss
┌────────────────────────┐
│ ActivityManagerService │
└────────┬───────────────┘
│
▼
┌──────────────────────┐
│ ZygoteProcess.start()│
└────────┬─────────────┘
│ Connect
▼
┌───────────────────────────────────┐
│ LocalSocket("/dev/socket/zygote") │
└────────┬──────────────────────────┘
│
▼
┌─────────────────────────────┐
│ ZygoteServer.runSelectLoop()│
└────────┬────────────────────┘
│ Fork
▼
┌──────────────────────┐
│ 子进程 (App进程) │
└──────────────────────┘
3. 新建进程(ActivityThread.main)
从 Zygote 进程 fork APP进程 调用路径大概如下:
scss
ZygoteInit.runSelectLoop()
└── ZygoteServer.runSelectLoop()
└── ZygoteConnection.processOneCommand()
└── Zygote.forkAndSpecialize()
└── if (pid == 0) // 说明是子进程
└── ZygoteInit.zygoteInit()
└── RuntimeInit.applicationInit()
└── Class.forName("android.app.ActivityThread")
└── ActivityThread.main()
ActivityThread.main() 是 APP进程 的入口点,其主要职责是为应用创建主线程(UI线程),并初始化应用的运行环境。
scss
public static void main(String[] args) {
// 开始性能追踪,记录"ActivityThreadMain"阶段耗时
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// 安装系统调用拦截器,为后续权限或行为控制做准备。
AndroidOs.install();
// 禁用 CloseGuard(资源泄露日志警告),避免日志污染
CloseGuard.setEnabled(false);
// 初始化当前用户的环境变量(如目录结构)
Environment.initForCurrentUser();
// 设置默认用户证书存储目录
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// 设置进程名(显示在 ps/top 中)
Process.setArgV0("<pre-initialized>");
// 为主线程准备 Looper(消息循环器)
Looper.prepareMainLooper();
// 解析参数中是否有进程启动序列号(用于追踪性能)
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
// 创建 ActivityThread 实例(应用主线程控制器)
ActivityThread thread = new ActivityThread();
// 启动应用:绑定 AMS,初始化 Application、Context、LoadedApk 等
thread.attach(false, startSeq);
// 设置主线程的 Handler(用于接收消息)
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// (调试可选)开启日志记录主线程消息
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// 结束性能追踪
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 启动主线程消息循环(正式开始事件派发)
Looper.loop();
// 如果主线程意外退出,抛出异常
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Zygote
Zygote 是 Android 系统中所有 Java 应用进程的"父进程",它通过 fork 自己 来高效创建新进程。
而 Zygote 本身并不主动创建进程,而是通过接收 AMS(SystemServer)通过 UNIX 本地 socket 发来的"启动进程"请求 来执行 fork()。
Zygote socket 的创建过程
在 Zygote 进程启动时调用 ZygoteInit.main(),创建 ZygoteServer 并执行 runSelectLoop
ini
ZygoteServer zygoteServer = new ZygoteServer(/* isPrimaryZygote= */ true);
// 监听 socket 请求
zygoteServer.runSelectLoop(abiList);
zygoteServer.runSelectLoop() 是 Zygote 进程的主循环方法,它的作用大概如下:
java
// com.android.internal.os.ZygoteServer.java
Runnable runSelectLoop(String abiList) {
...
while (true) {
// 1. 监听 socket
ZygoteConnection connection = peers[i];
...
// 2. 有连接请求时,读取消息
ZygoteConnection conn = acceptCommandPeer(...);
...
// 3. 解析并处理请求(如 fork 子进程)
Runnable command = conn.processOneCommand();
...
if (command != null) {
return command; // 子进程进入 ActivityThread.main()
}
}
}
ZygoteServer 构造函数中创建监听 socket(路径通常是 /dev/socket/zygote):
arduino
178 /**
179 * @hide for internal use only.
180 */
181 public static final String PRIMARY_SOCKET_NAME = "zygote";
182
183 /**
184 * @hide for internal use only.
185 */
186 public static final String SECONDARY_SOCKET_NAME = "zygote_secondary";
ini
148 ZygoteServer(boolean isPrimaryZygote) {
149 mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
150
151 if (isPrimaryZygote) {
152 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
153 mUsapPoolSocket =
154 Zygote.createManagedSocketFromInitSocket(
155 Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
156 } else {
157 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
158 mUsapPoolSocket =
159 Zygote.createManagedSocketFromInitSocket(
160 Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
161 }
162
163 fetchUsapPoolPolicyProps();
164
165 mUsapPoolSupported = true;
166 }
对应设备上的路径是:
bash
/dev/socket/zygote
这由 init.rc 脚本配置系统启动时自动创建。
进入 adb shell 执行 ls -alh /dev/socket 可以看到 zygote 文件
perl
wayne:/ # ls -alh /dev/socket
total 0
...
srw-rw---- 1 root system 0 2025-04-21 00:14 zygote
srw-rw---- 1 root system 0 2025-04-21 00:14 zygote_secondary
-
s 是 srw------- 中的第一个字符,表示这是一个 socket 文件。
-
rw 表示这个 socket 是可读写的(给拥有者)。
UNIX 本地 socket 就像是一个可以读写的临时文件,用于在两个进程之间传输数据。
客户端发起连接:ZygoteProcess.startViaZygote
当系统需要启动新进程时,ActivityManagerService → ProcessList → ZygoteProcess.startViaZygote():
scss
ZygoteProcess.start() →
ZygoteProcess.startViaZygote() →
ZygoteProcess.openZygoteSocketIfNeeded() →
ZygoteProcess.attemptConnectionToPrimaryZygote() →
ZygoteState.connect(address, usapPoolAddress) →
zygoteSessionSocket.connect(zygoteSocketAddress)
Zygote 接收命令 → 执行 fork
Zygote 在 runSelectLoop() 中监听 socket:
ini
// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
...
while (true) {
...
if (readyFd == mZygoteSocket.getFileDescriptor()) {
// 有新的连接,创建新连接对象
ZygoteConnection newConnection = acceptCommandPeer(abiList);
mPeers.add(newConnection);
mZygoteSocketFDs.add(newConnection.getFileDescriptor());
} else {
// 已有连接的数据处理
ZygoteConnection connection = mPeers.get(index);
final Runnable command = connection.processOneCommand(this);
...
}
}
}
然后在 processOneCommand 方法中处理 socket 请求。
最终调用:
ini
pid = Zygote.forkAndSpecialize(...)
创建新的子进程。
ActivityThread
ActivityThread 是 Android 应用进程的 主线程(UI 线程)管理类,它是系统在启动你的 App 时,创建和调度 Application 和 Activity 的关键组件。
ActivityThread 的作用:
作用 | 说明 |
---|---|
启动 Application | 创建 Application 实例并调用 onCreate() |
启动 Activity | 创建并回调每个 Activity 的 onCreate() 等 |
管理 Binder 通信 | 和系统进程(AMS、PMS 等)通信的代理 |
设置类加载器 | 为当前应用设置合适的 ClassLoader |
保持主线程运行 | 初始化 Looper.prepareMainLooper()、Looper.loop() |
sCurrentActivityThread
ActivityThread 类中静态字段 sCurrentActivityThread 是当前 APP 的 ActivityThread 实例
sCurrentActivityThread 字段在 thread.attach(false, startSeq); 被调用时完成初始化

通过 ActivityThread 的静态方法 currentActivityThread 可以拿到 sCurrentActivityThread
csharp
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
handleBindApplication
当 Zygote fork 出新进程后,这个进程(即你的 App)会启动并运行 ActivityThread.main(),随后 系统会通过 Binder 调用 ApplicationThread.bindApplication(),然后由主线程调用 handleBindApplication()。
scss
system_server 进程
│
├─ ActivityManagerService.attachApplication()
│ (通过 Binder 调用 App 进程的 ApplicationThread)
│
└──► ApplicationThread.bindApplication()
(内部类 → ActivityThread.ApplicationThread)
↓
ActivityThread.sendMessage(H.BIND_APPLICATION)
↓
ActivityThread.handleBindApplication()
handleBindApplication() 是 App 进程启动后最关键的初始化步骤,负责完成 Application 创建、Context 初始化、资源加载等操作。
scss
private void handleBindApplication(AppBindData data) {
// 设置进程名
Process.setArgV0(data.processName);
// 设置默认的AppContext环境
android.ddm.DdmHandleAppName.setAppName(data.processName, UserHandle.myUserId());
// 设置调试相关信息(例如是否开启调试)
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
// 安装类加载器(将APK的dex加载进来)
final LoadedApk packageInfo = getPackageInfo(data.info, data.compatInfo, Context.CONTEXT_INCLUDE_CODE);
// 创建 ContextImpl 实例
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
// 设置Instrumentation(用于后续生命周期事件的调试或监控)
mInstrumentation = new Instrumentation();
// 安装ContentProvider(Application.onCreate之前执行)
installContentProviders(app, data.providers);
// 在 makeApplication() 中,系统通过反射创建了 Application 实例,并调用了 attachBaseContext() 将 ContextImpl 赋给它,为之后调用 onCreate() 提供完整运行环境。
Application app = data.info.makeApplication(...);
// 调用 Application.onCreate()
mInstrumentation.callApplicationOnCreate(app);
// 保存 Application 实例
mInitialApplication = app;
// 注册广播接收器、Instrumentation、以及其他服务等
...
}
mClassLoader
ActivityThread 通过 mPackages 缓存所有已加载的应用包信息(LoadedApk 对象),每个 LoadedApk 封装了当前 App 的 mClassLoader,用于动态加载该应用的类和资源。
ActivityThread、mPackages、LoadedApk、mClassLoader 之间的关系
javascript
ActivityThread(整个App主进程管理器)
└── mPackages: Map<String, WeakReference<LoadedApk>>(已加载的 APK 缓存表)
↓
LoadedApk(当前应用的APK加载表示)
↓
mClassLoader(当前的类加载器)
mPackages
LoadedApk 中的 mClassLoader
Looper、MessageQueue、Handler
Looper 是一个"消息循环器",用于循环读取 MessageQueue 中的消息,并分发给目标 Handler 处理。
-
每个线程只能有一个 Looper。
-
主线程默认创建了 Looper 并调用了 Looper.loop()。
MessageQueue 是 "消息队列",用于存储 Handler 发送过来的消息。
-
消息按时间顺序排列。
-
Looper 会不断从中取出消息执行。
Handler 是"消息的发送和处理者"。
-
用来发送消息或任务到 MessageQueue。
-
当 Looper 取到消息后,会回调该消息对应的 Handler 的 handleMessage() 方法。
三者一起构成了 Android 的异步消息机制,是实现 UI 更新、线程通信、定时任务的基础。
如果没有它们:
-
子线程直接更新 UI,会导致 异常崩溃。
-
没有机制将任务从子线程安全地"切换"到主线程。
整体结构图:
scss
Looper.loop()
↓
MessageQueue.next() ←(epoll_wait 阻塞)
↑ ↑
│ └── ← 唤醒 ← 插入新消息 Handler.post()/sendMessage()
│
└── 有消息 → 返回 Message → 交给 Handler 处理
Looper.loop()
在 ActivityThread.main 函数中调用 Looper.loop() 后,会不断地:
-
等待消息队列(MessageQueue)中的任务
-
有消息(如生命周期调用、Handler消息、点击事件)立刻醒来执行
-
没消息就阻塞休息(不消耗 CPU)
从 Looper.loop() 到 native epoll_wait()
scss
Looper.loop()
↓
MessageQueue.next()
↓
nativePollOnce() (JNI)
↓
android_os_MessageQueue.cpp
↓
Looper::pollOnce()
↓
epoll_wait()
1. Looper.loop() 中的 MessageQueue.next()
这是整个事件循环的核心。这里的 queue.next():
-
会阻塞当前线程
-
等待新的消息进入 MessageQueue
-
等有消息时返回 Message,由 Handler 执行
java
public static void loop() {
// 获取当前线程的 Looper 实例,主线程默认会创建 Looper.prepareMainLooper()
final Looper me = myLooper();
// 获取消息队列 MessageQueue,内部通过 native 层 epoll 实现阻塞等待消息
final MessageQueue queue = me.mQueue;
// 主线程事件循环
for (;;) {
// 从消息队列中取出下一个 Message,如果没有则阻塞等待
Message msg = queue.next(); // might block
if (msg == null) {
// null 表示 Looper 已退出(如调用了 quit()),结束 loop
return;
}
// 正常取到消息后,调用目标 Handler 派发消息
// target 即发送该消息时绑定的 Handler
msg.target.dispatchMessage(msg);
// 消息处理完成后,释放消息对象回池中复用
msg.recycleUnchecked();
}
}
2. MessageQueue.next() → nativePollOnce()
在 MessageQueue.next() 中,调用了 JNI 方法 nativePollOnce() 来监听消息和事件:
3. android_os_MessageQueue_nativePollOnce
scss
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->pollOnce(timeoutMillis);
}
pollOnce() 会调用 Looper::pollOnce():
arduino
void NativeMessageQueue::pollOnce(int timeoutMillis) {
mLooper->pollOnce(timeoutMillis);
}
4. Looper::pollOnce() 最终调用 epoll_wait
Looper::pollOnce 中调用 pollInner
arduino
int Looper::pollOnce(int timeoutMillis, ...) {
int result = pollInner(timeoutMillis);
...
}
核心方法:
arduino
int Looper::pollInner(int timeoutMillis) {
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
...
}
epoll_wait() 是一个高效的内核级阻塞函数(syscall),用于等待一个或多个文件描述符上发生 I/O 事件,从而实现事件驱动的非阻塞编程。
参数说明:
-
mEpollFd.get():获取 epoll 实例的文件描述符(用于监控事件)
-
eventItems:一个epoll_event数组,用来存储发生的事件
-
EPOLL_MAX_EVENTS:一次最多返回多少个事件(常量)
-
timeoutMillis:阻塞的时间,单位是毫秒(例如:-1 表示无限阻塞,0 表示立即返回)
Looper.loop() 阻塞主线程其实是通过 epoll_wait() 来 高效监听多个事件源(管道、Binder、ANR 信号、socket 等),没事件就睡觉,有事件就立刻醒来处理,既节能又响应及时,这就是 Android 主线程调度的精髓!
5. 有消息/事件来了怎么唤醒?
当我们在子线程或者主线程执行如下代码时:
ini
handler.sendMessage(Message.obtain().apply { what = 100 })
它最终会调用 MessageQueue.enqueueMessage(),这个方法里有这么一句关键代码:
scss
nativeWake(mPtr);
对应到 native 层(frameworks/base/core/jni/android_os_MessageQueue.cpp):
scss
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
然后进入 Looper::wake() 中(frameworks/base/core/jni/android_os_MessageQueue.cpp → Looper.cpp):
arduino
void Looper::wake() {
ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, "w", 1));
}
这句 write(mWakeEventFd, "w", 1); 就是关键:👉 往 epoll 注册的 eventfd 写数据,从而唤醒 epoll_wait。