前文回顾:
Android8 从系统启动到用户见到第一个Activity的流程源码分析(二)-CSDN博客文章浏览阅读484次,点赞13次,收藏6次。本文分析了Android系统启动第一个Activity的关键流程。首先通过ActivityStarter的startActivityUnchecked方法初始化状态并确定目标任务栈,接着调用ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法恢复焦点栈顶Activity。当检测到目标进程不存在时,AMS会通过startProcessLocked方法创建新进程,该方法经过多次重载最终调用Process.start,通过Zygote forkhttps://blog.csdn.net/g_i_a_o_giao/article/details/151027854?spm=1011.2124.3001.6209Android8 从系统启动到用户见到第一个Activity的流程源码分析(一)-CSDN博客文章浏览阅读412次,点赞3次,收藏4次。本文分析了Android系统启动过程中AMS(ActivityManagerService)的systemReady方法及其关键流程。当SystemService调用AMS的systemReady方法后,AMS会初始化各类服务,清理不允许运行的进程,最终通过startHomeActivityLocked启动主屏幕Activity。该流程涉及多个关键步骤: 创建Home Intent并解析对应Activity信息 通过ActivityStarter启动主屏幕Activity 在startActivityLoc
https://blog.csdn.net/g_i_a_o_giao/article/details/150958400?spm=1011.2124.3001.6209紧接上篇文章,我们分析到了frameworks/base/core/java/android/os/Process.java中的start方法。
在这个方法中主要还是调用ZygoteProcess.java中的start方法。
java
/**
* 启动一个新的应用进程。这是Android框架中创建新进程的主要入口点。
*
* <p>如果系统启用了Zygote进程机制(默认情况),将通过Zygote fork一个新的进程,
* 并在新进程中执行指定{@code processClass}的静态{@code main()}函数。
* 此函数调用返回后,新进程会继续运行。
*
* <p>如果未启用Zygote进程机制(例如在某些特殊环境下),则会在调用者的当前进程中
* 创建一个新线程,并在该线程中调用{@code processClass}的{@code main()}方法。
* (这是一种退化情况,通常不会发生)。
*
* <p>{@code niceName} 参数如果非空,将作为进程的自定义显示名称,替代{@code processClass}。
* 这允许您即使使用相同的{@code processClass}启动多个进程,也能轻松区分它们。
* (例如,为不同WebView服务进程设置可读的名称)。
*
* <p>当{@code invokeWith}参数不为null时,进程将以"全新应用"(fresh app)的方式启动,
* 而不是通过Zygote fork。请注意,这通常需要root权限(uid 0)或
* {@code debugFlags}包含{@link Zygote#DEBUG_ENABLE_DEBUGGER}(即可调试状态)才被允许。
* (这通常用于使用wrap.sh脚本或类似工具来启动进程进行调试)。
*
* @param processClass 用作进程主入口点的类名(例如:"android.app.ActivityThread")。
* @param niceName 进程的更可读名称(用于`ps`命令等),例如应用包名。
* @param uid 进程运行时的用户ID。
* @param gid 进程运行时的主组ID。
* @param gids 与进程关联的附加组ID数组(用于权限管理)。
* @param debugFlags 控制进程调试行为的附加标志位(例如:启用JDWP、CheckJNI)。
* @param mountExternal 外部存储挂载模式(例如:{@link Zygote#MOUNT_EXTERNAL_NONE})。
* @param targetSdkVersion 应用的目标SDK版本,用于控制兼容性行为。
* @param seInfo 可为null,新进程的SELinux安全上下文信息。
* @param abi 非null,启动此应用应使用的ABI(例如:"arm64-v8a")。
* @param instructionSet 可为null,要使用的指令集(例如:"arm64")。
* @param appDataDir 可为null,应用的数据目录。
* @param invokeWith 可为null,用于启动进程的命令(例如:"/system/bin/logwrapper /data/app/wrap.sh")。
* @param zygoteArgs 提供给Zygote进程的额外参数。
*
* @return ProcessStartResult 一个描述进程启动尝试结果的对象,包含进程PID等信息。
* @throws RuntimeException 如果启动过程中发生致命错误。
*
* @hide 这是一个隐藏API,对普通应用开发者不可见,仅供系统内部使用。
*/
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
// 将启动请求委托给一个ZygoteProcess实例处理。
// zygoteProcess封装了与Zygote进程通信的细节(通过本地Socket)。
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
那我们继续看一下这个zygoteProcess.java中的start方法。在这个方法中又调用了startViaZygote方法。在startViaZygote方法中,创建了一个参数列表,然后解析参数并且添加到列表中,最后又调用了zygoteSendArgsAndGetResult方法。
java
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
/**
* Starts a new process via the zygote mechanism.
*
* @param processClass Class name whose static main() to run
* @param niceName 'nice' process name to appear in ps
* @param uid a POSIX uid that the new process should setuid() to
* @param gid a POSIX gid that the new process shuold setgid() to
* @param gids null-ok; a list of supplementary group IDs that the
* new process should setgroup() to.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi the ABI the process should use.
* @param instructionSet null-ok the instruction set to use.
* @param appDataDir null-ok the data directory of the app.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_JDWP) != 0) {
argsForZygote.add("--enable-jdwp");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
argsForZygote.add("--generate-debug-info");
}
if ((debugFlags & Zygote.DEBUG_ALWAYS_JIT) != 0) {
argsForZygote.add("--always-jit");
}
if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
argsForZygote.add("--native-debuggable");
}
if ((debugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
argsForZygote.add("--java-debuggable");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
在这个zygoteSendArgsAndGetResult方法中,首先检查传递的参数,然后通过socket通信向zygote进程发送符合通信协议的字符串。
java
/**
* 向Zygote进程发送一个参数列表,Zygote进程会根据这些参数启动一个新的子进程并返回其PID。
* 请注意:当前实现不允许参数中包含换行符('\n'),如果发现则会用空格替换。
* (根据注释,但实际代码是直接抛出异常,这是一个值得注意的细节)
*
* @param zygoteState 表示与Zygote进程连接状态的对象,包含Socket的读写流
* @param args 要发送给Zygote的参数列表,这些参数将用于配置新进程
* @return ProcessStartResult 包含新创建子进程PID的对象
* @throws ZygoteStartFailedEx 如果进程启动因任何原因失败,则抛出此异常
*/
@GuardedBy("mLock") // 此方法需要持有mLock锁,保证多线程环境下的同步访问
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
// 1. 参数预检:在发送前检查所有参数,确保没有嵌入的换行符('\n')
// 这样做可以避免向Zygote写入部分响应,保证协议的完整性。
int sz = args.size();
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
// 如果发现换行符,立即抛出异常,而不是替换它。
// (注释说"替换",但代码实际是"抛出异常",这可能意味着注释过时或代码逻辑已更改)
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
/**
* 与Zygote进程的通信协议格式(请参考com.android.internal.os.SystemZygoteInit.readArgumentList()):
* a) 首先发送一个参数数量的字符串(本质上是argc),以换行符结束
* b) 然后发送相应数量的参数字符串,每个参数都以换行符结束
*
* Zygote进程读取这些参数后,会进行fork操作,然后写入子进程的pid(失败则为-1),
* 随后再写入一个布尔值表示是否使用了包装进程(wrapper process)。
*/
final BufferedWriter writer = zygoteState.writer; // 获取Socket的字符输出流
final DataInputStream inputStream = zygoteState.inputStream; // 获取Socket的数据输入流
// 2. 发送参数数量
writer.write(Integer.toString(args.size())); // 将参数个数转换为字符串并写入
writer.newLine(); // 写入换行符,表示本条消息结束
// 3. 逐个发送所有参数
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg); // 写入参数内容
writer.newLine(); // 每个参数后都写入一个换行符,作为分隔符
}
writer.flush(); // 强制刷新缓冲区,确保所有数据都立即发送到Zygote端
// 4. 读取Zygote的响应
// 这里有一个思考点:是否应该设置读取超时?目前没有。
Process.ProcessStartResult result = new Process.ProcessStartResult();
// 必须从输入流中读取完整的响应数据,避免有字节残留在流中,
// 否则可能会被下一次进程启动操作意外读到,导致严重错误。
result.pid = inputStream.readInt(); // 首先读取一个整数,即Zygote返回的PID
result.usingWrapper = inputStream.readBoolean(); // 然后读取一个布尔值,表示是否使用了包装器
// 5. 检查响应结果
if (result.pid < 0) {
// 如果PID小于0(通常是-1),表示Zygote端fork()系统调用失败
throw new ZygoteStartFailedEx("fork() failed");
}
return result; // 返回成功的结果
} catch (IOException ex) {
// 6. 异常处理:如果在通信过程中发生IO异常
zygoteState.close(); // 关闭与Zygote的连接状态(包括Socket)
// 将IOException包装成ZygoteStartFailedEx并重新抛出
throw new ZygoteStartFailedEx(ex);
}
}
之前在分析Zygote进程启动的源码笔记中有分析过,ZygoteInit.java的main方法中会调用ZygoteServer.java中的runSelectLoop方法。在这个方法中,会通过多路复用的方式监听多个socket并且受到消息时创建一个ZygoteConnection对象,然后调用它的processOneCommand方法。那我们来看看这个performOneCommand方法。
java
/**
* 从命令Socket中读取一条启动命令并处理。如果成功,将fork一个子进程。
* 在子进程中,返回一个用于调用子进程main方法(或等效方法)的{@code Runnable}。
* 在父进程(即Zygote自身)中,始终返回{@code null}。
*
* 如果客户端关闭了socket,会设置一个{@code EOF}条件,调用者可以通过调用
* {@code ZygoteConnection.isClosedByPeer}来检测。
*
* @param zygoteServer 管理ZygoteServer状态的对象
* @return Runnable 在子进程中返回一个Runnable任务,在父进程中返回null
*/
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
// 1. 读取参数:从Socket连接中读取客户端发送的参数列表
args = readArgumentList();
// 获取辅助文件描述符(通过Socket传递的FD,如启动Service时使用的FD)
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
// readArgumentList 仅在到达EOF(没有可用数据可读)时返回null。
// 这只会发生在远程socket已断开连接的情况下。
if (args == null) {
isEof = true; // 标记连接已被对等方关闭
return null;
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
// 2. 参数解析:将字符串参数解析为结构化的Arguments对象,便于后续处理
parsedArgs = new Arguments(args);
// 3. 处理特殊查询命令(这些命令不fork进程,直接返回响应)
if (parsedArgs.abiListQuery) {
handleAbiListQuery(); // 处理ABI列表查询
return null;
}
if (parsedArgs.preloadDefault) {
handlePreload(); // 处理默认预加载请求
return null;
}
if (parsedArgs.preloadPackage != null) {
// 处理特定包的预加载请求
handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs,
parsedArgs.preloadPackageCacheKey);
return null;
}
// 4. 安全策略检查:确保客户端没有尝试设置任何能力(capabilities)
// 能力控制应由Zygote根据策略决定,而不是由客户端指定。
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: " +
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
}
// 应用UID安全策略(检查请求的UID是否允许)
applyUidSecurityPolicy(parsedArgs, peer);
// 应用invoke-with安全策略(检查是否允许使用包装脚本启动)
applyInvokeWithSecurityPolicy(parsedArgs, peer);
// 应用调试器相关的系统属性
applyDebuggerSystemProperty(parsedArgs);
// 应用invoke-with相关的系统属性
applyInvokeWithSystemProperty(parsedArgs);
// 5. 准备资源限制(rlimits)
int[][] rlimits = null;
if (parsedArgs.rlimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d);
}
// 6. 处理 invoke-with 模式(使用包装脚本启动)
int[] fdsToIgnore = null;
if (parsedArgs.invokeWith != null) {
try {
// 创建一对管道,用于父进程(Zygote)和子进程之间的通信
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
childPipeFd = pipeFds[1]; // 子进程端
serverPipeFd = pipeFds[0]; // 服务器(Zygote)端
// 清除子进程端管道的FD_CLOEXEC标志,使其在execvp后仍然保持打开
Os.fcntlInt(childPipeFd, F_SETFD, 0);
// 设置要忽略的文件描述符数组(在fork时保持打开)
fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
} catch (ErrnoException errnoEx) {
throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
}
}
/**
* 为了避免将描述符泄漏给Zygote子进程,本地代码必须在从Zygote-root切换到
* 要启动的应用程序的UID和权限之前,关闭子进程中的两个Zygote socket描述符。
*
* 为了避免在关闭两个LocalSocket对象时出现"坏文件描述符"错误,
* Posix文件描述符通过dup2()调用被释放,该调用会关闭socket并用一个
* 指向/dev/null的打开描述符替代。
*/
int [] fdsToClose = { -1, -1 }; // 初始化要关闭的FD数组
// 获取当前命令socket的FD,并标记为需要在子进程中关闭
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
fdsToClose[0] = fd.getInt$();
}
// 获取Zygote服务器主socket的FD,并标记为需要在子进程中关闭
fd = zygoteServer.getServerSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
}
fd = null; // 帮助GC
// 7. 核心操作:fork子进程并进行专门化配置
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
try {
if (pid == 0) {
// 8. 子进程处理路径
zygoteServer.setForkChild(); // 标记ZygoteServer当前处于子进程
// 关闭子进程中不需要的Zygote server socket
zygoteServer.closeServerSocket();
// 安静地关闭服务器端管道(子进程不需要)
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
// 处理子进程逻辑,返回一个Runnable(这里是调用ActivityThread.main())
return handleChildProc(parsedArgs, descriptors, childPipeFd);
} else {
// 9. 父进程(Zygote)处理路径
// pid < 0 表示fork失败,将在handleParentProc中处理
// 安静地关闭子进程端管道(父进程不需要)
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
// 处理父进程逻辑(如跟踪子进程状态、清理等)
handleParentProc(pid, descriptors, serverPipeFd);
return null; // 父进程总是返回null
}
} finally {
// 10. 清理资源:确保在任何路径下都关闭管道FD,避免资源泄漏
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
在这个方法中会对传递过来的参数列表进行解析,然后根据参数进行判断是否要fork一个新的进程。如果需要的话,就需要调用Zygote.forkAndSpecialize方法(之前的文章已经解析过,可以查看Android8 Zygote源码分析学习笔记(二)-CSDN博客进行复习)。调用这个方法会fork一个新的进程,然后会对进程进行一系列配置,最后会调用handleChildProc方法来找到之前传递的参数android.app.ActivityThread。
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
那么根据之前的分析,handleChildProc方法会找到ActivityThread.java的main函数并且封装成Runnable对象返回,在ZygoteInit的main方法中会执行这个runnable对象的run方法。
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
那么我们就要去看看/frameworks/base/core/java/android/app/ActivityThread.java中的main方法。它的主要作用是创建一个属于主线程的MainLooper,然后创建一个ActivityThread对象,最后调用了attch方法附着到系统进程中。
java
/**
* Android应用进程的主入口点。该方法由Zygote在fork出新应用进程后调用。
* 它负责初始化应用的主线程、消息循环(Looper)和与应用进程生命周期相关的核心组件。
*
* @param args 命令行参数(通常由Zygote进程传递过来)
*/
public static void main(String[] args) {
// 1. 开始性能跟踪:标记"ActivityThreadMain"阶段的开始,便于使用Systrace等工具分析启动性能。
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// 2. 禁用CloseGuard:CloseGuard默认是开启的,它会检测资源未关闭的情况,但日志非常冗长。
// 这里先全局禁用它,后续在调试版本中会通过StrictMode有选择地开启(输出到DropBox而非Logcat)。
CloseGuard.setEnabled(false);
// 3. 初始化环境:为当前用户初始化环境变量、配置和存储路径。
// 例如,设置数据目录(/data/user/0/<package_name>)。
Environment.initForCurrentUser();
// 4. 设置事件日志报告器:为libcore库设置一个事件日志报告器,
// 允许系统库将事件记录到Android的EventLog中。
EventLogger.setReporter(new EventLoggingReporter());
// 5. 设置可信证书存储位置:确保TrustedCertificateStore在正确的位置查找CA证书。
// configDir 通常是 /data/misc/user/<user-id>/keystore
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
// 6. 设置进程参数:将进程的参数argv[0]设置为"<pre-initialized>"。
// 这是一个临时状态,后续在attach过程中会被设置为实际的进程名(包名)。
Process.setArgV0("<pre-initialized>");
// 7. 准备主线程的消息循环(Looper):这是Android消息机制的核心。
// 该方法会创建一个Looper对象并将其设置到当前线程(主线程)的ThreadLocal中。
Looper.prepareMainLooper();
// 8. 创建主线程对象:实例化ActivityThread,它是Android应用主线程的管理者,
// 负责调度和执行AMS与应用之间的核心交互(如Activity生命周期回调)。
ActivityThread thread = new ActivityThread();
// 9. 附着到系统进程:调用attach方法,通过Binder通知ActivityManagerService(AMS)
// 本应用进程已准备就绪。参数false表示这不是系统进程。
// 这是一个非常关键的操作,它会:
// a) 获取AMS的代理对象(IActivityManager)
// b) 调用AMS的attachApplication方法,将本进程的ApplicationThread对象(Binder stub)传递给AMS
// c) AMS收到后,会开始调度启动本应用应该运行的Activity、Service等组件。
thread.attach(false);
// 10. 设置全局的主线程Handler:sMainThreadHandler是ActivityThread中的H Handler,
// 它负责处理从AMS发送过来的消息(如LAUNCH_ACTIVITY, PAUSE_ACTIVITY等)。
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 11. (可选)设置消息循环的日志打印:此代码块被if (false)禁用,可用于调试消息循环的处理过程。
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// 结束"ActivityThreadMain"阶段的性能跟踪。
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 12. 启动消息循环:开始无限循环,处理消息队列(MessageQueue)中的消息。
// 主线程会阻塞在这里,不断地从消息队列中取出消息,并由H Handler及其target(如ActivityThread)进行处理。
// 这是一个永不返回的调用(除非调用Looper.quit(),但主线程不允许这样做)。
Looper.loop();
// 13. 如果Looper.loop()意外返回(退出),则抛出运行时异常。
// 因为Android应用的主消息循环设计上是永不停止的,所以执行到这里意味着发生了严重错误。
throw new RuntimeException("Main thread loop unexpectedly exited");
}
那继续分析这个attch方法,在这个方法中,主要是获取了AMS的binder对象,并且调用attachApplication方法将ApplicationThread对象mAppThread传递给AMS,至此,AMS获得了向本应用进程发送消息的能力。
java
final ApplicationThread mAppThread = new ApplicationThread();
// 继承自Stub,说明这是个binder对象
private class ApplicationThread extends IApplicationThread.Stub {
.......省略代码......
}
/**
* 将当前ActivityThread(应用进程)附着到系统进程或作为普通应用进程初始化。
* 这是应用进程启动后与系统服务器建立通信的关键步骤。
*
* @param system 如果为true,表示当前是系统进程(如system_server)的初始化;
* 如果为false,表示是普通应用进程的初始化。
*/
private void attach(boolean system) {
sCurrentActivityThread = this; // 设置当前线程为全局的ActivityThread实例
mSystemThread = system; // 记录当前是否是系统进程
if (!system) {
// --- 普通应用进程的初始化路径 ---
// 1. 添加首次绘制处理器:在View系统首次执行绘制前启用JIT编译器优化
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled(); // 确保JIT编译器已启用
}
});
// 2. 设置DDM(Dalvik Debug Monitor)中的应用名称,用于调试和 profiling
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
// 3. 将ApplicationThread对象设置为Runtime的应用程序对象。
// ApplicationThread是一个Binder对象,是AMS与应用进程通信的接收端。
RuntimeInit.setApplicationObject(mAppThread.asBinder());
// 4. 获取ActivityManagerService(AMS)的Binder代理对象
final IActivityManager mgr = ActivityManager.getService();
try {
// 5. 【关键调用】通过Binder调用AMS的attachApplication方法,
// 将本进程的ApplicationThread对象(mAppThread)传递给AMS。
// 至此,AMS获得了向本应用进程发送消息的能力(如启动Activity、Service等)。
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer(); // 处理来自系统服务的远程异常
}
// 6. 添加GC监视器:监控堆内存使用情况,在接近堆内存限制时通知AMS释放一些Activity
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return; // 如果没有Activity发生改变,则跳过
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory(); // Dalvik堆的最大大小
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); // 已使用的大小
// 如果已使用内存超过最大值的3/4,则认为内存紧张
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
// 通知AMS可以释放一些本进程中的Activity以节省内存
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
// --- 系统进程(system_server)的初始化路径 ---
// 系统进程不需要设置application object,因为如果系统崩溃,
// 我们无法显示警报,只能直接退出。
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
// 创建Instrumentation对象,用于监控系统与应用的交互(主要用于测试)
mInstrumentation = new Instrumentation();
// 为系统进程创建应用上下文(Context)
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
// 创建并初始化系统应用的Application对象
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate(); // 调用Application的onCreate()生命周期方法
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
// 7. 为libcore添加dropbox日志报告器:当发生严重错误时,日志会被记录到DropBox中。
DropBox.setReporter(new DropBoxReporter());
// 8. 添加全局配置变更回调:当系统配置(如屏幕方向、语言等)发生变化时,此回调会被触发。
ViewRootImpl.ConfigChangedCallback configChangedCallback
= (Configuration globalConfig) -> {
synchronized (mResourcesManager) {
// 需要立即将配置变更应用到资源管理器,因为返回后视图层级结构会被告知此变更。
if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
null /* compat */)) {
// 更新本地化列表
updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
mResourcesManager.getConfiguration().getLocales());
// 如果资源配置确实发生了改变,并且新配置比待处理的配置更新,则通知消息循环
if (mPendingConfiguration == null
|| mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
mPendingConfiguration = globalConfig;
// 发送H.CONFIGURATION_CHANGED消息,最终会触发onConfigurationChanged回调
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
}
}
}
};
// 将配置变更回调注册到ViewRootImpl
ViewRootImpl.addConfigCallback(configChangedCallback);
}
至此,分析到这里进行一个小的总结。**FallbackHome应用的进程已经成功fork出来了,并且创建了ActivityThread对象和AMS进行了binder绑定。**那么接下来要分析,这个应用进程的Application的oncreate方法是怎样执行的,Activity的onCreate方法是怎么执行的,Activity又是怎么展示到前台的。