Android Zygote分析
作者:互联网
Android Zygote
Android的zygote本质上是Android的虚拟机,是Android的SystemServer和几乎所有Java应用的卵化器,它们的父进程都是zygote。没有zygote就没有Android,Android的启动也离不开zygote。
zygote是很重要的一个服务进程,我们在本文档中分析以下zygote在Android中所扮演的角色、作用以及一些设计的特点。
Android版本:AndroidQ。
zygote的启动
zygote是服务进程的别名,zygote实际上是app_process这个可执行程序所运行的:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
zygote由rc文件定义init启动的服务,其来源就是app_process,这也是Android的虚拟机的可执行文件。从rc文件中也有一些细节:
1.zygote的进程优先级是最高的,priority被设成-20,主要是因为Android的启动非常依赖于SystemServer的启动,而SystemServer也是zygote fork出来的,因此需要将其的优先级设成最高的。
2.zygote的user是root权限,其group是root、readproc(读取/proc的节点)、reserved_disk(未知).
3.zygote在启动时创建了两个socket(zygote和usap_pool_primary),用于进程间的通信,后面会有说到。
4.zygote是Android非常重要的核心服务之一,当其因异常退出后init会将其重新启动,并将一些相关的节点和服务重新设置。
5.向内核通告其为前台进程任务。
zygote的启动实际上是分成了两部分:①SystemServer的启动;②ZygoteServer的启动。这两者前面是在同一个进程中执行的,当虚拟机创建完成后才正式分离。
zygote启动的前奏
我们先来看以下前面的部分:
// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
argc--;
argv++;
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
// We're in zygote mode.
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
app_process的main方法比较长,以上是精简后的代码,再根据rc中定义zygote服务的参数,可以获知,局部变量zygote为true,startSystemServer为true,className为空串。因此这里会先创建Java虚拟机cache,然后执行Java代码ZygoteInit的main方法。
@UnsupportedAppUsage
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;
Runnable caller;
try {
Zygote.initNativeState(isPrimaryZygote);
zygoteServer = new ZygoteServer(isPrimaryZygote);
……
if (!enableLazyPreload) {
preload(bootTimingsTraceLog);
} else {
Zygote.resetNicePriority();
}
……
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}
if (caller != null) {
caller.run();
}
}
ZygoteInit的main()方法是Android启动中的第一个Java进程的主方法。在ZygoteInit中,一般无特殊原因,都会调用preload()方法将Android Java层应用常用的资源预加装,其原因是:
1.Android是基于Linux系统开发的,底层就是Linux操作系统,而Linux进程的fork机制有一个特点,就是写时拷贝机制;fork出来的进程是最初是共用一块内存,只有当发生写操作时,才会将对应的内存块进行拷贝修改,而一些只读的内存块则会所有fork出来的进程共享。
2.preload()方法所加装的东西主要有以下几类:常用类文件、Resources资源、HALs资源、opengl、webview等。这些资源一般都是只读的,不会进行修改,而且是很多应用都可能会用到的。因此预先加载后所有由zygote fork出来的应用进程都能共用一块内存。
preload
static void preload(TimingsTraceLog bootTimingsTraceLog) {
beginPreload();
preloadClasses();
cacheNonBootClasspathClassLoaders();
preloadResources();
nativePreloadAppProcessHALs();
maybePreloadGraphicsDriver();
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
endPreload();
warmUpJcaProviders();
sPreloadComplete = true;
}
preload()方法中有很多是安全、trace和虚拟机相关的内容,我们主要关心一些我们常用的东西。
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;
}
runtime.setTargetHeapUtilization(0.8f);
try {
BufferedReader br =
new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
int count = 0;
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
try {
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
} catch (UnsatisfiedLinkError e) {
} catch (Throwable t) {
}
}
} catch (IOException e) {
} finally {
IoUtils.closeQuietly(is);
runtime.setTargetHeapUtilization(defaultUtilization);
runtime.preloadDexCaches();
}
}
preloadClasses()方法主要是从/system/etc/preloaded-classes
文件中读取需要预加载的类名,然后通过Class.forname将该类加载到内存中,并会执行其中的一些静态方法(Java的类加载机制)。这里的重点是preloaded-classes文件,这个文件一般使用Android原生的文件,其路径在frameworks/base/config/preloaded-classes
,一般不需要我们去修改,格式如下:
android.R$styleable
android.accessibilityservice.AccessibilityServiceInfo$1
android.accessibilityservice.AccessibilityServiceInfo
android.accounts.Account$1
android.accounts.Account
android.accounts.AccountManager$10
android.accounts.AccountManager$11
android.accounts.AccountManager$18
android.accounts.AccountManager$1
android.accounts.AccountManager$20
android.accounts.AccountManager$2
android.accounts.AccountManager$AmsTask$1
android.accounts.AccountManager$AmsTask$Response
android.accounts.AccountManager$AmsTask
android.accounts.AccountManager$BaseFutureTask$1
android.accounts.AccountManager$BaseFutureTask$Response
android.accounts.AccountManager$BaseFutureTask
android.accounts.AccountManager$Future2Task$1
android.accounts.AccountManager$Future2Task
android.accounts.AccountManager
每一行都是一个类的全名。
preloadResources
private static void preloadResources() {
final VMRuntime runtime = VMRuntime.getRuntime();
try {
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
long startTime = SystemClock.uptimeMillis();
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(ar);
ar.recycle();
startTime = SystemClock.uptimeMillis();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(ar);
ar.recycle();
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();
}
}
mResources.finishPreloading();
} catch (RuntimeException e) {
}
}
preloadResources()方法主要是做了以下几件事:
1.在Resources.startPreloading()方法中,调用updateConfiguration()方法为系统创建Configuration,这是后面应用和系统的一些配置来源。
2.从preloaded_drawables中获取预加载的drawables资源,并将其加载到内存中。preloaded_drawables字段在frameworks/base/core/res/res/values/arrays.xml
中定义。
3.从preloaded_color_state_lists中获取预加载的color资源,并将其加载到内存中,preloaded_color_state_lists字段也是定义在frameworks/base/core/res/res/values/arrays.xml
中。
4.如果支持自由窗口模式,则将preloaded_freeform_multi_window_drawables字段中定义的预加载的freeform drawables也加载进来。
nativePreloadAppProcessHALs
nativePreloadAppProcessHALs()方法是将Gralloc的HALs加载进来:
void android_internal_os_ZygoteInit_nativePreloadAppProcessHALs(JNIEnv* env, jclass) {
ScopedSCSExit x;
android::GraphicBufferMapper::preloadHal();
}
void GraphicBufferMapper::preloadHal() {
Gralloc2Mapper::preload();
Gralloc3Mapper::preload();
}
nativePreloadGraphicsDriver
nativePreloadGraphicsDriver()方法是用于加载图形驱动(egl):
private static void maybePreloadGraphicsDriver() {
if (!SystemProperties.getBoolean(PROPERTY_DISABLE_GRAPHICS_DRIVER_PRELOADING, false)) {
nativePreloadGraphicsDriver();
}
}
void android_internal_os_ZygoteInit_nativePreloadGraphicsDriver(JNIEnv* env, jclass) {
ScopedSCSExit x;
if (Properties::peekRenderPipelineType() == RenderPipelineType::SkiaGL) {
eglGetDisplay(EGL_DEFAULT_DISPLAY);
}
}
forkSystemServer
SystemServer是通过forkSystemServer()方法fork出来并开始执行,forkSystemServer()的代码树中有很多晦涩的代码, 我们将会跳过一些我们不相关的代码来分析。
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
ZygoteArguments parsedArgs = null;
int pid;
try {
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false);
if (profileSystemServer) {
parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
forkSystemServer()中主要做了两件事:①调用Zygote.forkSystemServer()方法去fork一个新的进程出来。②fork()后的子进程是SystemServer进程,则等待zygote的启动完成,并执行真正的SystemServer代码。
// Zygote.java
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
// Enable tracing as soon as we enter the system_server.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
}
ZygoteHooks.postForkCommon();
return pid;
}
ZygoteHooks.preFork():将Daemons线程关掉,虚拟机进行一些copy前的处理。
resetNicePriority():将进程的优先级设回普通的级别。
nativeForkSystemServer():调用native层方法去fork一个新的进程。
ZygoteHooks.postForkCommon():重新启动Daemons线程,虚拟机进行copy后的处理。
fork操作是不会将进程中所有线程拷贝的,只会拷贝当前线程。
Daemons线程是指:①HeapTaskDaemon;②ReferenceQueueDaemon;③FinalizerDaemon;④FinalizerWatchdogDaemon。平时在trace文件(ANR或者其他方式获取的trace文件)中看到Java应用进程都会有这4个线程,这4个线程就是在这里创建的。
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
jlong effective_capabilities) {
pid_t pid = ForkCommon(env, true,
fds_to_close,
fds_to_ignore);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
permitted_capabilities, effective_capabilities,
MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, nullptr, nullptr);
} else if (pid > 0) {
gSystemServerPid = pid;
int status;
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
}
if (UsePerAppMemcg()) {
if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
ALOGE("couldn't add process %d into system memcg group", pid);
}
}
}
return pid;
}
ForkCommon():主要调用Linux的fork系统调用,fork一个新的进程,子进程的pid为0,父进程返回子进程的pid值。
SpecializeCommon():子进程(SystemServer)需要做的处理,这里做了非常多的操作,很多都是虚拟机相关的东西,其中有secure storage的挂载(MountEmulatedStorage),SeAndroid的配置,创建SystemServer的classLoader(ZygoteInit.createSystemServerClassLoader())以及hidden api的检查等。
再回到ZygoteInit.forkSystemServer()方法,此时两个进程都会返回到此处,此时两个进程就到这里分道扬镳了。SystemServer进程将ZygoteServer的socket关闭,然后调用handleSystemServerProcess()方法去执行SystemServer的源码。
createSystemServerClassLoader();
ClassLoader cl = sCachedSystemServerClassLoader;
if (cl != null) {
Thread.currentThread().setContextClassLoader(cl);
}
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, cl);
handleSystemServerProcess()方法的核心代码就是上面那几行,先获取classloader,并将其设置为root classloader。然后调用ZygoteInit.zygoteInit()方法去执行。
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
ZygoteInit.nativeZygoteInit()方法为进程创建Binder的环境(ProcessStatae),这个将会在新的文章中对binder进行分析。
RuntimeInit.applicationInit()方法则会去执行传参进来的类的main()方法,这里就是:com.android.server.SystemServer
.
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
ZygoteInit.forkSystemServer()返回一个runnable,返回到ZygoteInit.main()方法后,SystemServer进程就会继续执行这个runnable。
ZygoteServer.runSelectLoop
当zygote进程返回到main()方法后,就会继续执行ZygoteServer.runSelectLoop()方法,从名字上和注释来看,这个方法应该是一个死循环,是不断进行循环执行命令的方法:
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
while (true) {
fetchUsapPoolPolicyPropsWithMinInterval();
int[] usapPipeFDs = null;
StructPollfd[] pollFDs = null;
if (mUsapPoolEnabled) {
usapPipeFDs = Zygote.getUsapPipeFDs();
pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
} else {
pollFDs = new StructPollfd[socketFDs.size()];
}
int pollIndex = 0;
for (FileDescriptor socketFD : socketFDs) {
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = socketFD;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
}
final int usapPoolEventFDIndex = pollIndex;
if (mUsapPoolEnabled) {
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = mUsapPoolEventFD;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
for (int usapPipeFD : usapPipeFDs) {
FileDescriptor managedFd = new FileDescriptor();
managedFd.setInt$(usapPipeFD);
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = managedFd;
pollFDs[pollIndex].events = (short) POLLIN;
++pollIndex;
}
}
try {
Os.poll(pollFDs, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
if (pollIndex == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
try {
ZygoteConnection connection = peers.get(pollIndex);
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(pollIndex);
socketFDs.remove(pollIndex);
}
}
} catch (Exception e) {
if (!mIsForkChild) {
ZygoteConnection conn = peers.remove(pollIndex);
conn.closeSocket();
socketFDs.remove(pollIndex);
} else {
throw e;
}
} finally {
mIsForkChild = false;
}
} else {
long messagePayload = -1;
try {
byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
DataInputStream inputStream =
new DataInputStream(new ByteArrayInputStream(buffer));
messagePayload = inputStream.readLong();
} else {
continue;
}
} catch (Exception ex) {
if (pollIndex == usapPoolEventFDIndex) {
} else {
}
continue;
}
if (pollIndex > usapPoolEventFDIndex) {
Zygote.removeUsapTableEntry((int) messagePayload);
}
usapPoolFDRead = true;
}
}
if (usapPoolFDRead) {
int[] sessionSocketRawFDs =
socketFDs.subList(1, socketFDs.size())
.stream()
.mapToInt(fd -> fd.getInt$())
.toArray();
final Runnable command = fillUsapPool(sessionSocketRawFDs);
if (command != null) {
return command;
}
}
}
}
runSelectLoop()方法主要做两件事:
1.每次循环都重新构建监听文件列表,主要是ZygoteServer的socket文件(ZygoteServer的socket和其他应用进程连接过来的socket)和usap文件节点(目前看来,zygote默认是没有使用,作用未明,不做分析)。
2.监听文件列表,并从中获取命令执行。
Os.poll(pollFDs, -1)调用表示从监听队列中监听事件。usapPoolEventFDIndex的值是socket fds最后的位置,处理监听文件事件时,分了三类:
1.ZygoteServer的socket,index为0,在runSelectLoop()方法的开始时就先将ZygoteServer的socket add到socketFDs中,因此该fd在监听列表中的index为0。
2.0< index < usapPoolEventFDIndex,在这个区间的文件节点时其他应用进程连接过来的socket节点,其他应用会通过对应的socket来进行指令的传输。
3.index >= usapPoolEventFDIndex,usap节点,作用不明,先不管。
对于第一种情况调用acceptCommandPeer()方法来获取申请连接的ZygoteConnection实例和socket fd。
对于第二种情况,先拿到对应的ZygoteConnection实例,调用其processOneCommand()方法来获取客户端传递过来的命令。
processOneCommand
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
ZygoteArguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = Zygote.readArgumentList(mSocketReader);
// TODO (chriswailes): Remove this and add an assert.
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
throw new IllegalStateException("IOException on command socket", ex);
}
// readArgumentList returns null only when it has reached EOF with no available
// data to read. This will only happen when the remote socket has disconnected.
if (args == null) {
isEof = true;
return null;
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
parsedArgs = new ZygoteArguments(args);
if (parsedArgs.mAbiListQuery) {
handleAbiListQuery();
return null;
}
if (parsedArgs.mPidQuery) {
handlePidQuery();
return null;
}
if (parsedArgs.mUsapPoolStatusSpecified) {
return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
}
if (parsedArgs.mPreloadDefault) {
handlePreload();
return null;
}
if (parsedArgs.mPreloadPackage != null) {
handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
return null;
}
if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
Parcel appInfoParcel = Parcel.obtain();
appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
appInfoParcel.setDataPosition(0);
ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
appInfoParcel.recycle();
if (appInfo != null) {
handlePreloadApp(appInfo);
} else {
throw new IllegalArgumentException("Failed to deserialize --preload-app");
}
return null;
}
if (parsedArgs.mApiBlacklistExemptions != null) {
return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
}
if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
|| parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
return handleHiddenApiAccessLogSampleRate(zygoteServer,
parsedArgs.mHiddenApiAccessLogSampleRate,
parsedArgs.mHiddenApiAccessStatslogSampleRate);
}
if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: "
+ "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
+ ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
}
Zygote.applyUidSecurityPolicy(parsedArgs, peer);
Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null;
if (parsedArgs.mRLimits != null) {
rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
}
int[] fdsToIgnore = null;
if (parsedArgs.mInvokeWith != null) {
try {
FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
Os.fcntlInt(childPipeFd, F_SETFD, 0);
fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
} catch (ErrnoException errnoEx) {
throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
}
}
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
* in the child process before it switches from Zygote-root to
* the UID and privileges of the application being launched.
*
* In order to avoid "bad file descriptor" errors when the
* two LocalSocket objects are closed, the Posix file
* descriptors are released via a dup2() call which closes
* the socket and substitutes an open descriptor to /dev/null.
*/
int [] fdsToClose = { -1, -1 };
FileDescriptor fd = mSocket.getFileDescriptor();
if (fd != null) {
fdsToClose[0] = fd.getInt$();
}
fd = zygoteServer.getZygoteSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
}
fd = null;
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.mStartChildZygote);
} 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;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
processOneCommand通过mSocketReader读取客户端传过来的参数,然后调用ZygoteArguments来进行解析。不同的参数对应不同的操作:
参数 | 操作 |
---|---|
“–query-abi-list” / mAbiListQuery = true | handleAbiListQuery |
“–get-pid” / mPidQuery = true | handlePidQuery |
“–usap-pool-enabled” / mUsapPoolStatusSpecified = true | handleUsapPoolStatusChange |
“–preload-default” / mPreloadDefault = true | handlePreload |
“–preload-package” / mPreloadPackage = true | handlePreloadPackage |
“–preload-app” / mPreloadApp | handlePreloadApp |
“–set-api-blacklist-exemptions” / mApiBlacklistExemptions != null | handleApiBlacklistExemptions |
“–hidden-api-log-sampling-rate” / mHiddenApiAccessLogSampleRate != -1 | handleHiddenApiAccessLogSampleRate |
“–hidden-api-statslog-sampling-rate” / mHiddenApiAccessStatslogSampleRate != -1 | handleHiddenApiAccessLogSampleRate |
other | forkAndSpecialize + handleChildProc |
前面的指令我们所对应的操作不展开分析,以后用到再进行分析。
Process的启动
经过上面的分析,我们已经了解到zygote的基本运行,但是ZygoteConnection.processOneCommand()方法的具体使用没有展开说明。我们在这里以启动一个新的应用为例展开分析。
当启动一个新的应用时,AMS会调用Process.start()方法去让zygote fork一个新的进程来:
// frameworks/base/core/java/android/os/Process.java
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags,
int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
/*useUsapPool=*/ true, zygoteArgs);
}
ZYGOTE_PROCESS是ZygoteProcess的实例对象。ZygoteProcess.start()方法会调用到ZygoteProcess.startViaZygote()方法来设置启动参数,processClass是"android.app.ActivityThread",在ProcessList.startProcessLocked()中设置的。
经过ZygoteProcess.startViaZygote()方法的参数设置后,调用ZygoteProcess.attemptZygoteSendArgsAndGetResult()方法将这些命令和参数通过socket发送到ZygoteSocket中:
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
try {
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
zygoteWriter.write(msgStr);
zygoteWriter.flush();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
+ ex.toString());
throw new ZygoteStartFailedEx(ex);
}
}
attemptZygoteSendArgsAndGetResult()方法通过向Zygote Socket发送命令(zygoteWriter.write())来启动新的应用进程,并等待返回结果。
当客户端的socket将命令发送后,我们继续回到Zygote进程的服务端socket的处理。我们回顾上一章中ZygoteServer.processOneCommand()方法,此时zygote进程做了以下3件事:
1.Zygote.forkAndSpecialize(),fork新的进程。
2.zygoteServer.closeServerSocket(),关闭fork后子进程的socket节点。
3.handleChildProc()返回entrypoint的main()方法,有fork后子进程进行。
总结
问答
1.zygote启动时进行preload的作用是什么?
zygote作为Android的虚拟机,很多应用(java/kotlin)的资源都是共用的,zygote利用了Linux操作系统的copy-on-write机制,预先加载了常用的资源,然后其他的应用通过fork后,所有的进程都能共享一份只能的资源,而不需要为每个应用进程都单独加载一份。
2.zygote在fork进程后,使用runnable的方式返回到main()方法后才执行的原因?
减少线程堆栈的长度,因为fork后进行执行的内容与之前zygote的堆栈内容并无关系,因此不需要为每个进程都保留前面的堆栈信息,而且还能减少进程的堆栈容量限制。
3.zygote的作用。
zygote作为Android的虚拟机,最主要的作用就是启动SystemServer进程,和fork新的应用进程。我们也可以单独使用app_process命令来运行我们的Java代码。
标签:分析,int,Zygote,zygote,Android,null,parsedArgs,android 来源: https://blog.csdn.net/zcyxiaxi/article/details/113957613