Zygote 进程初始化完成后,会化身为守护进程来执行启动应用程序的任务。下面是启动时序图
注册 Zygote 的 socket
- ZygoteInit 的 main() 方法首先调用 registerServerSocketFromEnv() 来创建一个本地 socket,接着调用 runSelectLoop() 来进入等待 socket 连接的循环中。
- registerServerSocketFromEnv() 方法如下
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 通过设置环境变量 ANDROID_SOCKET_ 来获取 socket句柄。Zygote 在 init.rc 中定义 init.zygote32(或其他init.zygote32_64等) 有一句话
socket zygote stream 660 root system
Init 进程会通过这条选项来创建一个 AF_UNIX 的 socket,并把它的句柄放到环境变量 ANDROID_SOCKET_zygote 中,这个环境变量后面的 zygote 就是选项中的名字。
得到句柄后将通过 FileDescriptor fd = new FileDescriptor(); 生成一个 FileDescriptor 对象,然后在通过mServerSocket = new LocalServerSocket(fd); 生成一个本地服务 socket,它的值将保存在全局 mServerSocket 中。
请求启动应用
android 启动一个新的进程是在 ActivityManagerService 中完成的,可能会有多种原因导致系统启动一个新的进程,最终在 ActivityManagerService 中都是通过调用方法 startProcessLocked() 来完成这一过程。startProcessLocked() 准备好参数后,会调用 Process 的 start() 方法来启动应用。部分代码如下
private ProcessStartResult startProcess(String hostingType, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
Process.start() 的第一个参数是String entryPoint,如果往上查找会发现 entryPoint 的定义为 final String entryPoint = "android.app.ActivityThread"; 就是应用启动后执行的入口类。
Process.start() 实际上走的是 ZygoteProcess.start() 方法。方法如下:processClass 就是 android.app.ActivityThread
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, false ,
zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
接下来通过调用 startViaZygote() 方法,将进程的启动参数保存到argsForZygote,最后调用zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
将应用程序启动的参数发送到 Zygote 进程,startViaZygote 代码如下
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
boolean startChildZygote,
String[] extraArgs)
throws ZygoteStartFailedEx {
ArrayList<String> argsForZygote = new ArrayList<String>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
argsForZygote.add("--runtime-flags=" + runtimeFlags);
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);
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);
}
if (startChildZygote) {
argsForZygote.add("--start-child-zygote");
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
上面代码最后调用了 zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote) 第一个参数如下调用了openZygoteSocketIfNeeded方法,建立 socket连接并且返回 ZygoteState,对于 LocalSocket 直接通过字符串作为地址进行连接就可以通信。
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
处理启动应用请求
之前提过,ZygoteInit 类的 main方法最后调用了 zygoteServer.runSelectLoop(abiList); 开始了监听和接收消息的环节。
当 (pollFds[i].revents & POLLIN) == 0 结果 为 false 代表有事件的请求到来,则调用 acceptCommandPeer() 来和客户端建立连接,然后把这个连接添加到监听数组中,等待socket的命令到来。接到命令后会处理参数,处理结束后会断开连接并且移除监听。
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
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 {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
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);
}
}
}
}
}
}
fork() 应用进程
ZygoteConnnect 类中的 processOneCommand 负责创建子进程,首先调用args = readArgumentList(); 从 socket 中读入多个参数,参数样式为 “--setuid=1” 行与行之间用 /r /n 分割,读取完成后传入新建的 Arguments 对象 并调用parseArgs(args);解析成参数列表。
解析参数之后还会对参数进行校验和设置。
applyUidSecurityPolicy(parsedArgs, peer);
applyInvokeWithSecurityPolicy(parsedArgs, peer);
applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs);
上面检测通过后,processOneCommand 会调用下面代码来 fork 子进程
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);
最终会调用 native 层的 nativeForkAndSpecialize() 的函数来完成 fork 操作
native private static int nativeForkAndSpecialize(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);
nativeForkAndSpecialize() 函数的主要工作:
- fork() 出子进程
- 在子进程中挂载 external storage
- 在子进程中设置用户 Id、组Id、所属进程id
- 在子进程中执行系统调用 setrlimit 来设置系统资源限制
- 在子进程中执行系统调用 capset 来设置进程的权限
- 在子进程中设置应用上下文
native 返回 Java 层后,processOneCommand 方法继续执行,如果 pid==0 则在父进程中,否则在子进程中。
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;
}
子进程初始化
上面讲了如果是在子进程中,则执行 handleChildProc() 函数。来完成子进程的初始化,代码如下
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
closeSocket();
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null );
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null );
}
}
}
parsedArgs.invokeWith 普遍为Null,如果不为 Null 则通过 exec 方式启动 app_process 进程来执行Java类(通过执行 exec 的区别前面文章有讲过,fork + exec 和 单独 fork 不执行 exec 的区别)。
正常情况会调用 ZygoteInit.zygoteInit ,主要执行的方法 是 RuntimeInit.commonInit,ZygoteInit.nativeZygoteInit() 和 RuntimeInit.applicationInit
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
- RuntimeInit.commonInit(); 方法
protected static final void commonInit() {
LoggingHandler loggingHandler = new LoggingHandler();
Thread.setUncaughtExceptionPreHandler(loggingHandler);
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
TimezoneGetter.setInstance(new TimezoneGetter() {
@Override
public String getId() {
return SystemProperties.get("persist.sys.timezone");
}
});
TimeZone.setDefault(null);
LogManager.getLogManager().reset();
new AndroidConfig();
String userAgent = getDefaultUserAgent();
System.setProperty("http.agent", userAgent);
NetworkManagementSocketTagger.install();
String trace = SystemProperties.get("ro.kernel.android.tracing");
if (trace.equals("1")) {
Slog.i(TAG, "NOTE: emulator trace profiling enabled");
Debug.enableEmulatorTraceOutput();
}
initialized = true;
}
- ZygoteInit.nativeZygoteInit(); 方法
这个是 native 方法 private static final native void nativeZygoteInit(); 调用的是 AndroidRuntime.cpp中的方法
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
gCurRuntime 是 AppRuntime 的全局指针,它的 onZygoteInit() 函数如下:主要是初始化了 Binder 环境,这样应用就可以使用 Binder了。
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
- RuntimeInit.applicationInit() 方法
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
nativeSetExitWithoutCleanup(true);
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
findStaticMain 经过一系列的处理最后会调用到 MethodAndArgsCaller 返回 Runnable,执行run方法后执行的是下面方法,mMethod 实际上是 main 方法。
mMethod.invoke(null, new Object[] { mArgs });
接下来就进入了应用本身的启动流程了。
预加载系统类和资源
为了加快应用程序的启动,Android把系统常用的 Java 类和一部分 Framework 的资源在 zygote 进程中加载,这些预加载的类和资源在所有经 Zygote fork出的进程中都是共享的。
ZygoteInit 在 main() 方法中调用的 preload(bootTimingsTraceLog); 加载系统类,系统资源和OpenGL等方法初始化如下
static void preload(TimingsTraceLog bootTimingsTraceLog) {
beginIcuCachePinning();
preloadClasses();
preloadResources();
nativePreloadAppProcessHALs();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
endIcuCachePinning();
warmUpJcaProviders();
sPreloadComplete = true;
}
android.R$styleable
android.accessibilityservice.AccessibilityServiceInfo
android.accessibilityservice.AccessibilityServiceInfo$1
android.accounts.Account
android.accounts.Account$1
android.accounts.AccountManager
android.accounts.AccountManager$1
android.accounts.AccountManager$10
android.accounts.AccountManager$11
android.accounts.AccountManager$18
android.accounts.AccountManager$2
android.accounts.AccountManager$20
android.accounts.IAccountManagerResponse
android.accounts.IAccountManagerResponse$Stub
android.accounts.OnAccountsUpdateListener
android.accounts.OperationCanceledException
android.animation.AnimationHandler
android.animation.AnimationHandler$1
android.animation.AnimationHandler$AnimationFrameCallback
android.animation.AnimationHandler$AnimationFrameCallbackProvider
.....
加载这些类的方法是 preloadClasses() ,流程如下
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
try {
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
Class.forName(line, true, null);
count++;
}
}
private static void preloadResources() {
final VMRuntime runtime = VMRuntime.getRuntime();
try {
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
Log.i(TAG, "Preloading resources...");
long startTime = SystemClock.uptimeMillis();
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resources in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
startTime = SystemClock.uptimeMillis();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resources in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
if (mResources.getBoolean(
com.android.internal.R.bool.config_freeformWindowManagement)) {
startTime = SystemClock.uptimeMillis();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
N = preloadDrawables(ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resource in "
+ (SystemClock.uptimeMillis() - startTime) + "ms.");
}
}
mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, "Failure preloading resources", e);
}
}
|