- 注册 Zygote 的 socket
- 请求启动应用
- 处理启动应用请求
- fork() 应用进程
- 子进程初始化
- 预加载系统类和资源
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) {
// .... 其他代码省略
// 会调用 Process.start 开启应用
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 /* startChildZygote */,
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>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
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);
// --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);
}
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 直接通过字符串作为地址进行连接就可以通信。
// 如果socket没有连接,则尝试连接socket,如果已经打开了socket则什么都不做。
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;
}
// The primary zygote didn't match. Try the secondary.
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);
// processOneCommand 方法处理读取的命令 处理完后面会断开链接,并从监听列表中移除
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
// We're in the child. We should always have a command to run at this
// stage if processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This shows up as
// a regular POLLIN event in our regular processing loop.
// 判断是否处理完了事件,处理完则断开链接 移除监听
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
}
// 。
。
。
}
}
}
fork() 应用进程
ZygoteConnnect 类中的 processOneCommand 负责创建子进程,首先调用args = readArgumentList(); 从 socket 中读入多个参数,参数样式为 “--setuid=1” 行与行之间用 /r /n 分割,读取完成后传入新建的 Arguments 对象 并调用parseArgs(args);解析成参数列表。
解析参数之后还会对参数进行校验和设置。
// 检查用户是否有权利指定进程用户id,组id和所属的组,以及一些安全检查等。
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) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
子进程初始化
上面讲了如果是在子进程中,则执行 handleChildProc() 函数。
来完成子进程的初始化,代码如下
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
* objects still need to be closed properly.
*/
// 首先关闭了 socket 连接
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);
}
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
// Should not get here.
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
}
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();
// 设置 UncaughtException 的处理方法
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);
// 重制 Log 系统
LogManager.getLogManager().reset();
new AndroidConfig();
// 设置 http.agent 属性
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) {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
// 这个两个是设置虚拟机的参数
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
// findStaticMain 内部的 Run 方法通过 invoke 执行Java层的 main 方法
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
findStaticMain 经过一系列的处理最后会调用到 MethodAndArgsCaller 返回 Runnable,执行run方法后执行的是下面方法,mMethod 实际上是 main 方法。
// Method m;
// try {
// m = cl.getMethod("main", new Class[] { String[].class });
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;
}
-
预加载 Java 类
系统的 Java 类会频繁的执行,因此,需要把类的信息预先加载到系统内存中,并在所有应用进程中共享,Android将所有需要预加载的类放到了本地文件 preloaded-classes中,android9的目录位于 frameworks/base/config/preloaded-classes
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();
// 首先获取一个 FileInputStream 通过流读取文件内容
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) {
// Skip comments and blank lines.
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 装载类的信息(它不会创建一个对象)
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);
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)