1 Introducción al cigoto
Zygote es el proceso más importante en Android Zygote进程和Init进程、SystemServer进程是Android最重要的三大进程
. Zygote es el proceso central para crear un nuevo proceso en el sistema Android. Es responsable de iniciar la máquina virtual Dalvik, cargar algunos recursos y clases del sistema necesarios, iniciar el proceso system_server y luego esperar para procesar las solicitudes de la aplicación.
En el sistema Android, el proceso Zygote trama el proceso de solicitud y el proceso Init inicia el proceso Zygote. El proceso Zygote creará una instancia de máquina virtual Dalvik cuando se inicie, y cada vez que genere un nuevo proceso de aplicación, copiará la instancia de la máquina virtual Dalvik al nuevo proceso de aplicación, de modo que cada proceso de aplicación tenga una máquina virtual Dalvik independiente. instancia.
Clases involucradas en Zygote:
frameworks/base/cmds/app_process/app_main.cpp
frameworks/base/core/jni/AndroidRuntime.cpp
frameworks/base/core/java/com/android/internal/os/
- Zygote.java
- ZygoteInit.java
- ZygoteServer.java
- ZygoteConnection.java
2 inicio del cigoto
Este artículo se basa en Android10(Q)
el análisis del código fuente.
2.1 El proceso de inicio analiza el script init.rc
Zygote se inicia mediante init进程
el script de análisis . init.rc
El script se pasa app_process的main方法
para la segmentación y la lógica correspondiente se realiza de acuerdo con el comando de cadena.
Ahora que la máquina está dividida en 32 y 64 bits, el script de inicio de Zygote init.rc también es diferente:
- init.zygote32.rc: el programa de ejecución correspondiente al proceso cigoto es app_process (modo puro de 32 bits)
- init.zygote64.rc: el programa de ejecución correspondiente al proceso cigoto es app_process64 (modo puro de 64 bits)
- init.zygote32_64.rc: inicia dos procesos de cigoto, los programas de ejecución correspondientes son app_process32 (modo principal), app_process64
- init.zygote64_32.rc: inicia dos procesos de cigoto, los programas de ejecución correspondientes son app_process64 (modo principal), app_process32
El programa que ejecutará zygote es system/bin/app_process
y su código fuente está aquí app_main.cpp
. Echemos un vistazo a cómo app_main maneja los comandos de script:
frameworks/base/cmds/app_process/app_main.cpp
165 #if defined(__LP64__)
166 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
167 static const char ZYGOTE_NICE_NAME[] = "zygote64";
168 #else
169 static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
170 static const char ZYGOTE_NICE_NAME[] = "zygote";
171 #endif
172
173 int main(int argc, char* const argv[])
174 {
......
256 // Parse runtime arguments. Stop at first unrecognized option.
257 bool zygote = false;
258 bool startSystemServer = false;
259 bool application = false;
260 String8 niceName;
261 String8 className;
262
263 ++i; // Skip unused "parent dir" argument.
264 while (i < argc) {
265 const char* arg = argv[i++];
266 if (strcmp(arg, "--zygote") == 0) {
267 zygote = true;
268 niceName = ZYGOTE_NICE_NAME;
269 } else if (strcmp(arg, "--start-system-server") == 0) {
270 startSystemServer = true;
271 } else if (strcmp(arg, "--application") == 0) {
272 application = true;
273 } else if (strncmp(arg, "--nice-name=", 12) == 0) {
274 niceName.setTo(arg + 12);
275 } else if (strncmp(arg, "--", 2) != 0) {
276 className.setTo(arg);
277 break;
278 } else {
279 --i;
280 break;
281 }
282 }
......
309 if (startSystemServer) {
310 args.add(String8("start-system-server"));
311 }
......
331 if (!niceName.isEmpty()) {
332 runtime.setArgv0(niceName.string(), true /* setProcName */);
333 }
334
335 if (zygote) {
336 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
337 } else if (className) {
338 runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
339 } else {
340 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
341 app_usage();
342 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
343 }
344 }
Tomemos init.zygote64.rc
esto como ejemplo:
1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
2 class main
3 priority -20
4 user root
5 group root readproc reserved_disk
6 socket zygote stream 660 root system
7 socket usap_pool_primary stream 660 root system
8 onrestart write /sys/android_power/request_state wake
9 onrestart write /sys/power/state on
10 onrestart restart audioserver
11 onrestart restart cameraserver
12 onrestart restart media
13 onrestart restart netd
14 onrestart restart wificond
15 writepid /dev/cpuset/foreground/tasks
Principalmente este comando de script:service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
De hecho, se dividirá en:
servicio: identificador de servicio
zygote: indica el nombre del servicio a abrir
/system/bin/app_process64: la ruta correspondiente al servicio
-Xzygote: como parámetro requerido para el inicio de la máquina virtual, startVm en AndroidRuntime.cpp () llama a JNI_CreateJavaVM para usar
/system/bin: representa el directorio donde se encuentra el programa de la máquina virtual, porque app_process puede no estar en el mismo directorio que la máquina virtual, por lo que app_process necesita conocer el directorio donde se encuentra la máquina virtual. donde se encuentra la máquina – zygote: especifique la clase ZygoteInit como entrada;
de lo contrario, debe especificar el nombre de la clase que debe ejecutarse
--start-system-server: solo está disponible cuando hay un parámetro --zygote, que le indica a ZygoteInit que el primero El proceso que se genera después del inicio es SystemServer
"--zygote"
Presiona el primer if ,zygote变量
configúralo paratrue
indicar iniciozygote进程
y进程名
cámbialo azygote
ozygote64
- Golpea en el segundo si
"--start-system-server"
,startSystemServer变量
configurado paratrue
indicar que comienzaSystemServer进程
app_main.cpp
Una vez iniciada la main方法
ejecución delZygoteInit
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
2.2 AndroidRuntime inicia ZygoteInit
Entre ellos runtime
está AndroidRuntime
la clase, echemos un AndroidRuntime
vistazo start方法
:
/frameworks/base/core/jni/AndroidRuntime.cpp
1112 /*
1113 * Start the Android runtime. This involves starting the virtual machine
1114 * and calling the "static void main(String[] args)" method in the class
1115 * named by "className".
1116 *
1117 * Passes the main function two arguments, the class name and the specified
1118 * options string.
1119 */
1120 void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
1121 {
......
1164 /* start the virtual machine */
1165 JniInvocation jni_invocation;
1166 jni_invocation.Init(NULL);
1167 JNIEnv* env;
1168 if (startVm(&mJavaVM, &env, zygote) != 0) {
1169 return;
1170 }
1171 onVmCreated(env);
1172
1173 /*
1174 * Register android functions.
1175 */
1176 if (startReg(env) < 0) {
1177 ALOGE("Unable to register all android natives\n");
1178 return;
1179 }
......
1203
1204 /*
1205 * Start VM. This thread becomes the main thread of the VM, and will
1206 * not return until the VM exits.
1207 */
1208 char* slashClassName = toSlashClassName(className != NULL ? className : "");
1209 jclass startClass = env->FindClass(slashClassName);
1210 if (startClass == NULL) {
1211 ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
1212 /* keep going */
1213 } else {
1214 jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
1215 "([Ljava/lang/String;)V");
1216 if (startMeth == NULL) {
1217 ALOGE("JavaVM unable to find main() in '%s'\n", className);
1218 /* keep going */
1219 } else {
1220 env->CallStaticVoidMethod(startClass, startMeth, strArray);
1226 }
1227 }
......
1235 }
Después de un cierto registro de la máquina virtual y el método JNI, CallStaticVoidMethod
se llama al nombre de clase pasado main函数
. El nombre de clase que pasamos son com.android.internal.os.ZygoteInit
las tres cosas principales en AndroidRuntime:
- startVm() crea una máquina virtual
- startReg() registra dinámicamente Java para llamar a jni nativo
- La reflexión llama al main() de ZygoteInit
2.3 Inicialización de ZygoteInit
AndroidRuntime
Creado y yendo Native层
a la entrada del inicio de Android /frameworks/base/core/java/com/android/internal/os/ZygoteInit.javaZygote
AndroidRuntime.start()
Native层
Java层ZygoteInit的main()
ZygoteInit的main()方法
第一个Java进程主方法
818 @UnsupportedAppUsage
819 public static void main(String argv[]) {
820 ZygoteServer zygoteServer = null;
......
833 Runnable caller;
834 try {
......
847 boolean startSystemServer = false;
848 String zygoteSocketName = "zygote";
849 String abiList = null;
850 boolean enableLazyPreload = false;
851 for (int i = 1; i < argv.length; i++) {
852 if ("start-system-server".equals(argv[i])) {
853 startSystemServer = true;
854 } else if ("--enable-lazy-preload".equals(argv[i])) {
855 enableLazyPreload = true;
856 } else if (argv[i].startsWith(ABI_LIST_ARG)) {
857 abiList = argv[i].substring(ABI_LIST_ARG.length());
858 } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
859 zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
860 } else {
861 throw new RuntimeException("Unknown command line argument: " + argv[i]);
862 }
863 }
864
865 final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
866
867 if (abiList == null) {
868 throw new RuntimeException("No ABI list supplied.");
869 }
870
871 // In some configurations, we avoid preloading resources and classes eagerly.
872 // In such cases, we will preload things prior to our first fork.
873 if (!enableLazyPreload) {
......
877 preload(bootTimingsTraceLog);
......
881 } else {
882 Zygote.resetNicePriority();
883 }
......
896 Zygote.initNativeState(isPrimaryZygote);
897
898 ZygoteHooks.stopZygoteNoThreadCreation();
899
900 zygoteServer = new ZygoteServer(isPrimaryZygote);
901
902 if (startSystemServer) {
903 Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
904
905 // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
906 // child (system_server) process.
907 if (r != null) {
908 r.run();
909 return;
910 }
911 }
912
913 Log.i(TAG, "Accepting command socket connections");
914
915 // The select loop returns early in the child process after a fork and
916 // loops forever in the zygote.
917 caller = zygoteServer.runSelectLoop(abiList);
918 } catch (Throwable ex) {
919 Log.e(TAG, "System zygote died with exception", ex);
920 throw ex;
921 } finally {
922 if (zygoteServer != null) {
923 zygoteServer.closeServerSocket();
924 }
925 }
926
927 // We're in the child process and have exited the select loop. Proceed to execute the
928 // command.
929 if (caller != null) {
930 caller.run();
931 }
932 }
Principalmente hizo 3 cosas:
preload()预先加载系统资源,如系统类、资源、系统共享库等
创建 ZygoteServer,其实就是 ServerSocket 循环等待通知 fork 子进程
创建 SystemServer进程
2.3.1 precarga()
preload()
: Preparación de recursos, incluida la carga de clases, la carga de recursos, etc.
135 static void preload(TimingsTraceLog bootTimingsTraceLog) {
138 beginPreload();
141 preloadClasses();
144 cacheNonBootClasspathClassLoaders();
147 preloadResources();
150 nativePreloadAppProcessHALs();
153 maybePreloadGraphicsDriver();
155 preloadSharedLibraries();
156 preloadTextResources();
157 // Ask the WebViewFactory to do any initialization that must run in the zygote process,
158 // for memory sharing purposes.
159 WebViewFactory.prepareWebViewInZygote();
160 endPreload();
161 warmUpJcaProviders();
164 sPreloadComplete = true;
165 }
......
244 /**
245 * Performs Zygote process initialization. Loads and initializes commonly used classes.
246 *
247 * Most classes only cause a few hundred bytes to be allocated, but a few will allocate a dozen
248 * Kbytes (in one case, 500+K).
249 */
250 private static void preloadClasses() {
251 final VMRuntime runtime = VMRuntime.getRuntime();
252
253 InputStream is;
254 try {
255 is = new FileInputStream(PRELOADED_CLASSES);
256 } catch (FileNotFoundException e) {
257 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
258 return;
259 }
260
261 Log.i(TAG, "Preloading classes...");
262 long startTime = SystemClock.uptimeMillis();
263
264 // Drop root perms while running static initializers.
265 final int reuid = Os.getuid();
266 final int regid = Os.getgid();
267
268 // We need to drop root perms only if we're already root. In the case of "wrapped"
269 // processes (see WrapperInit), this function is called from an unprivileged uid
270 // and gid.
271 boolean droppedPriviliges = false;
272 if (reuid == ROOT_UID && regid == ROOT_GID) {
273 try {
274 Os.setregid(ROOT_GID, UNPRIVILEGED_GID);
275 Os.setreuid(ROOT_UID, UNPRIVILEGED_UID);
276 } catch (ErrnoException ex) {
277 throw new RuntimeException("Failed to drop root", ex);
278 }
279
280 droppedPriviliges = true;
281 }
282
283 // Alter the target heap utilization. With explicit GCs this
284 // is not likely to have any effect.
285 float defaultUtilization = runtime.getTargetHeapUtilization();
286 runtime.setTargetHeapUtilization(0.8f);
287
288 try {
289 BufferedReader br =
290 new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
291
292 int count = 0;
293 String line;
294 while ((line = br.readLine()) != null) {
295 // Skip comments and blank lines.
296 line = line.trim();
297 if (line.startsWith("#") || line.equals("")) {
298 continue;
299 }
300
301 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
302 try {
303 if (false) {
304 Log.v(TAG, "Preloading " + line + "...");
305 }
306 // Load and explicitly initialize the given class. Use
307 // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
308 // (to derive the caller's class-loader). Use true to force initialization, and
309 // null for the boot classpath class-loader (could as well cache the
310 // class-loader of this class in a variable).
311 Class.forName(line, true, null);
312 count++;
313 } catch (ClassNotFoundException e) {
314 Log.w(TAG, "Class not found for preloading: " + line);
315 } catch (UnsatisfiedLinkError e) {
316 Log.w(TAG, "Problem preloading " + line + ": " + e);
317 } catch (Throwable t) {
318 Log.e(TAG, "Error preloading " + line + ".", t);
319 if (t instanceof Error) {
320 throw (Error) t;
321 }
322 if (t instanceof RuntimeException) {
323 throw (RuntimeException) t;
324 }
325 throw new RuntimeException(t);
326 }
327 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
328 }
329
330 Log.i(TAG, "...preloaded " + count + " classes in "
331 + (SystemClock.uptimeMillis() - startTime) + "ms.");
332 } catch (IOException e) {
333 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
334 } finally {
335 IoUtils.closeQuietly(is);
336 // Restore default.
337 runtime.setTargetHeapUtilization(defaultUtilization);
338
339 // Fill in dex caches with classes, fields, and methods brought in by preloading.
340 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
341 runtime.preloadDexCaches();
342 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
343
344 // Bring back root. We'll need it later if we're in the zygote.
345 if (droppedPriviliges) {
346 try {
347 Os.setreuid(ROOT_UID, ROOT_UID);
348 Os.setregid(ROOT_GID, ROOT_GID);
349 } catch (ErrnoException ex) {
350 throw new RuntimeException("Failed to restore root", ex);
351 }
352 }
353 }
354 }
......
382 /**
383 * Load in commonly used resources, so they can be shared across processes.
384 *
385 * These tend to be a few Kbytes, but are frequently in the 20-40K range, and occasionally even
386 * larger.
387 */
388 private static void preloadResources() {
389 final VMRuntime runtime = VMRuntime.getRuntime();
390
391 try {
392 mResources = Resources.getSystem();
393 mResources.startPreloading();
394 if (PRELOAD_RESOURCES) {
395 Log.i(TAG, "Preloading resources...");
396
397 long startTime = SystemClock.uptimeMillis();
398 TypedArray ar = mResources.obtainTypedArray(
399 com.android.internal.R.array.preloaded_drawables);
400 int N = preloadDrawables(ar);
401 ar.recycle();
402 Log.i(TAG, "...preloaded " + N + " resources in "
403 + (SystemClock.uptimeMillis() - startTime) + "ms.");
404
405 startTime = SystemClock.uptimeMillis();
406 ar = mResources.obtainTypedArray(
407 com.android.internal.R.array.preloaded_color_state_lists);
408 N = preloadColorStateLists(ar);
409 ar.recycle();
410 Log.i(TAG, "...preloaded " + N + " resources in "
411 + (SystemClock.uptimeMillis() - startTime) + "ms.");
412
413 if (mResources.getBoolean(
414 com.android.internal.R.bool.config_freeformWindowManagement)) {
415 startTime = SystemClock.uptimeMillis();
416 ar = mResources.obtainTypedArray(
417 com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
418 N = preloadDrawables(ar);
419 ar.recycle();
420 Log.i(TAG, "...preloaded " + N + " resource in "
421 + (SystemClock.uptimeMillis() - startTime) + "ms.");
422 }
423 }
424 mResources.finishPreloading();
425 } catch (RuntimeException e) {
426 Log.w(TAG, "Failure preloading resources", e);
427 }
428 }
preloadClasses()
El método consiste principalmente en leer el nombre de la clase que debe cargarse previamente desde el archivo /system/etc/preloaded-classes y luego cargar la clase en la memoria a través de Class.forname y ejecutar algunos de los métodos estáticos (mecanismo de carga de clases de Java). ). El enfoque aquí es el archivo de clases precargadas, que generalmente usa archivos nativos de Android y su ruta está en frameworks/base/config/preloaded-classes.
preloadResources()
El método hace principalmente las siguientes cosas:
1. En el método Resources.startPreloading(), llame al método updateConfiguration() para crear una configuración para el sistema, que son algunas fuentes de configuración para aplicaciones y sistemas posteriores.
2. Obtenga los recursos dibujables precargados de preloaded_drawables y cárguelos en la memoria. El campo preloaded_drawables se define en frameworks/base/core/res/res/values/arrays.xml.
3. Obtenga el recurso de color precargado de preloaded_color_state_lists y cárguelo en la memoria. El campo preloaded_color_state_lists también se define en frameworks/base/core/res/res/values/arrays.xml.
4. Si se admite el modo de ventana libre, también se cargan los elementos dibujables de forma libre precargados definidos en el campo preloaded_freeform_multi_window_drawables.
2.3.2 Servidor Zygote
Se crea una instancia del objeto ZygoteServer en el método principal de ZygoteInit y sus runSelectLoop()
métodos se llaman closeServerSocket()
.
/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
48 class ZygoteServer {
.......
88 /**
89 * Listening socket that accepts new server connections.
90 */
91 private LocalServerSocket mZygoteSocket;
......
142 /**
143 * Initialize the Zygote server with the Zygote server socket, USAP pool server socket, and USAP
144 * pool event FD.
145 *
146 * @param isPrimaryZygote If this is the primary Zygote or not.
147 */
148 ZygoteServer(boolean isPrimaryZygote) {
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 }
166 }
......
176 /**
177 * Registers a server socket for zygote command connections. This opens the server socket
178 * at the specified name in the abstract socket namespace.
179 */
180 void registerServerSocketAtAbstractName(String socketName) {
181 if (mZygoteSocket == null) {
182 try {
183 mZygoteSocket = new LocalServerSocket(socketName);
184 mCloseSocketFd = false;
185 } catch (IOException ex) {
186 throw new RuntimeException(
187 "Error binding to abstract socket '" + socketName + "'", ex);
188 }
189 }
190 }
......
210 /**
211 * Close and clean up zygote sockets. Called on shutdown and on the
212 * child's exit path.
213 */
214 void closeServerSocket() {
215 try {
216 if (mZygoteSocket != null) {
217 FileDescriptor fd = mZygoteSocket.getFileDescriptor();
218 mZygoteSocket.close();
219 if (fd != null && mCloseSocketFd) {
220 Os.close(fd);
221 }
222 }
223 } catch (IOException ex) {
224 Log.e(TAG, "Zygote: error closing sockets", ex);
225 } catch (ErrnoException ex) {
226 Log.e(TAG, "Zygote: error closing descriptor", ex);
227 }
228
229 mZygoteSocket = null;
230 }
......
368 /**
369 * Runs the zygote process's select loop. Accepts new connections as
370 * they happen, and reads commands from connections one spawn-request's
371 * worth at a time.
372 */
373 Runnable runSelectLoop(String abiList) {
374 ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
375 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
376
377 socketFDs.add(mZygoteSocket.getFileDescriptor());
378 peers.add(null);
379
380 while (true) {
381 fetchUsapPoolPolicyPropsWithMinInterval();
382
383 int[] usapPipeFDs = null;
384 StructPollfd[] pollFDs = null;
385
386 // Allocate enough space for the poll structs, taking into account
387 // the state of the USAP pool for this Zygote (could be a
388 // regular Zygote, a WebView Zygote, or an AppZygote).
389 if (mUsapPoolEnabled) {
390 usapPipeFDs = Zygote.getUsapPipeFDs();
391 pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
392 } else {
393 pollFDs = new StructPollfd[socketFDs.size()];
394 }
395
396 /*
397 * For reasons of correctness the USAP pool pipe and event FDs
398 * must be processed before the session and server sockets. This
399 * is to ensure that the USAP pool accounting information is
400 * accurate when handling other requests like API blacklist
401 * exemptions.
402 */
403
404 int pollIndex = 0;
405 for (FileDescriptor socketFD : socketFDs) {
406 pollFDs[pollIndex] = new StructPollfd();
407 pollFDs[pollIndex].fd = socketFD;
408 pollFDs[pollIndex].events = (short) POLLIN;
409 ++pollIndex;
410 }
411
412 final int usapPoolEventFDIndex = pollIndex;
413
414 if (mUsapPoolEnabled) {
415 pollFDs[pollIndex] = new StructPollfd();
416 pollFDs[pollIndex].fd = mUsapPoolEventFD;
417 pollFDs[pollIndex].events = (short) POLLIN;
418 ++pollIndex;
419
420 for (int usapPipeFD : usapPipeFDs) {
421 FileDescriptor managedFd = new FileDescriptor();
422 managedFd.setInt$(usapPipeFD);
423
424 pollFDs[pollIndex] = new StructPollfd();
425 pollFDs[pollIndex].fd = managedFd;
426 pollFDs[pollIndex].events = (short) POLLIN;
427 ++pollIndex;
428 }
429 }
430
431 try {
432 Os.poll(pollFDs, -1);
433 } catch (ErrnoException ex) {
434 throw new RuntimeException("poll failed", ex);
435 }
436
437 boolean usapPoolFDRead = false;
438
439 while (--pollIndex >= 0) {
440 if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
441 continue;
442 }
443
444 if (pollIndex == 0) {
445 // Zygote server socket
446
447 ZygoteConnection newPeer = acceptCommandPeer(abiList);
448 peers.add(newPeer);
449 socketFDs.add(newPeer.getFileDescriptor());
450
451 } else if (pollIndex < usapPoolEventFDIndex) {
452 // Session socket accepted from the Zygote server socket
453
454 try {
455 ZygoteConnection connection = peers.get(pollIndex);
456 final Runnable command = connection.processOneCommand(this);
457
458 // TODO (chriswailes): Is this extra check necessary?
459 if (mIsForkChild) {
460 // We're in the child. We should always have a command to run at this
461 // stage if processOneCommand hasn't called "exec".
462 if (command == null) {
463 throw new IllegalStateException("command == null");
464 }
465
466 return command;
467 } else {
468 // We're in the server - we should never have any commands to run.
469 if (command != null) {
470 throw new IllegalStateException("command != null");
471 }
472
473 // We don't know whether the remote side of the socket was closed or
474 // not until we attempt to read from it from processOneCommand. This
475 // shows up as a regular POLLIN event in our regular processing loop.
476 if (connection.isClosedByPeer()) {
477 connection.closeSocket();
478 peers.remove(pollIndex);
479 socketFDs.remove(pollIndex);
480 }
481 }
482 } catch (Exception e) {
483 if (!mIsForkChild) {
484 // We're in the server so any exception here is one that has taken place
485 // pre-fork while processing commands or reading / writing from the
486 // control socket. Make a loud noise about any such exceptions so that
487 // we know exactly what failed and why.
488
489 Slog.e(TAG, "Exception executing zygote command: ", e);
490
491 // Make sure the socket is closed so that the other end knows
492 // immediately that something has gone wrong and doesn't time out
493 // waiting for a response.
494 ZygoteConnection conn = peers.remove(pollIndex);
495 conn.closeSocket();
496
497 socketFDs.remove(pollIndex);
498 } else {
499 // We're in the child so any exception caught here has happened post
500 // fork and before we execute ActivityThread.main (or any other main()
501 // method). Log the details of the exception and bring down the process.
502 Log.e(TAG, "Caught post-fork exception in child process.", e);
503 throw e;
504 }
505 } finally {
506 // Reset the child flag, in the event that the child process is a child-
507 // zygote. The flag will not be consulted this loop pass after the Runnable
508 // is returned.
509 mIsForkChild = false;
510 }
511 } else {
512 // Either the USAP pool event FD or a USAP reporting pipe.
513
514 // If this is the event FD the payload will be the number of USAPs removed.
515 // If this is a reporting pipe FD the payload will be the PID of the USAP
516 // that was just specialized.
517 long messagePayload = -1;
518
519 try {
520 byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
521 int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
522
523 if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
524 DataInputStream inputStream =
525 new DataInputStream(new ByteArrayInputStream(buffer));
526
527 messagePayload = inputStream.readLong();
528 } else {
529 Log.e(TAG, "Incomplete read from USAP management FD of size "
530 + readBytes);
531 continue;
532 }
533 } catch (Exception ex) {
534 if (pollIndex == usapPoolEventFDIndex) {
535 Log.e(TAG, "Failed to read from USAP pool event FD: "
536 + ex.getMessage());
537 } else {
538 Log.e(TAG, "Failed to read from USAP reporting pipe: "
539 + ex.getMessage());
540 }
541
542 continue;
543 }
544
545 if (pollIndex > usapPoolEventFDIndex) {
546 Zygote.removeUsapTableEntry((int) messagePayload);
547 }
548
549 usapPoolFDRead = true;
550 }
551 }
552
553 // Check to see if the USAP pool needs to be refilled.
554 if (usapPoolFDRead) {
555 int[] sessionSocketRawFDs =
556 socketFDs.subList(1, socketFDs.size())
557 .stream()
558 .mapToInt(fd -> fd.getInt$())
559 .toArray();
560
561 final Runnable command = fillUsapPool(sessionSocketRawFDs);
562
563 if (command != null) {
564 return command;
565 }
566 }
567 }
568 }
569 }
Principalmente haz 3 cosas:
创建ZygoteServer
: ZygoteServer se inicializa y ServerSocket se inicializa internamente, lo que proporciona a Zygote capacidades de comunicación.zygoteServer.runSelectLoop()
: Cuando el proceso cigoto regresa al método main() y se ejecuta, según el nombre y los comentarios, este método debe ser un bucle infinito, que es un método para ejecutar comandos continuamente en un bucle. Principalmente hace dos cosas:
1. El bucle reconstruye la lista de archivos de escucha, principalmente el archivo de socket de ZygoteServer (el socket de ZygoteServer y el socket conectado por otros procesos de aplicación) y el nodo del archivo usap (en la actualidad, parece que zygote no se usa de forma predeterminada, se desconoce su función y no se realiza ningún análisis).
2. Escuche la lista de archivos y obtenga la ejecución del comando.zygoteServer.closeServerSocket()
: Después del ciclo, cierre ServerSocket
2.3.3 Crear proceso SystemServer
718 /**
719 * Prepare the arguments and forks for the system server process.
720 *
721 * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
722 * process; {@code null} in the parent.
723 */
724 private static Runnable forkSystemServer(String abiList, String socketName,
725 ZygoteServer zygoteServer) {
726 long capabilities = posixCapabilitiesAsBits(
727 OsConstants.CAP_IPC_LOCK,
728 OsConstants.CAP_KILL,
729 OsConstants.CAP_NET_ADMIN,
730 OsConstants.CAP_NET_BIND_SERVICE,
731 OsConstants.CAP_NET_BROADCAST,
732 OsConstants.CAP_NET_RAW,
733 OsConstants.CAP_SYS_MODULE,
734 OsConstants.CAP_SYS_NICE,
735 OsConstants.CAP_SYS_PTRACE,
736 OsConstants.CAP_SYS_TIME,
737 OsConstants.CAP_SYS_TTY_CONFIG,
738 OsConstants.CAP_WAKE_ALARM,
739 OsConstants.CAP_BLOCK_SUSPEND
740 );
741 /* Containers run without some capabilities, so drop any caps that are not available. */
742 StructCapUserHeader header = new StructCapUserHeader(
743 OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
744 StructCapUserData[] data;
745 try {
746 data = Os.capget(header);
747 } catch (ErrnoException ex) {
748 throw new RuntimeException("Failed to capget()", ex);
749 }
750 capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
751
752 /* Hardcoded command line to start the system server */
753 String args[] = {
754 "--setuid=1000",
755 "--setgid=1000",
756 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
757 + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
758 "--capabilities=" + capabilities + "," + capabilities,
759 "--nice-name=system_server",
760 "--runtime-args",
761 "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
762 "com.android.server.SystemServer",
763 };
764 ZygoteArguments parsedArgs = null;
765
766 int pid;
767
768 try {
769 parsedArgs = new ZygoteArguments(args);
770 Zygote.applyDebuggerSystemProperty(parsedArgs);
771 Zygote.applyInvokeWithSystemProperty(parsedArgs);
772
773 boolean profileSystemServer = SystemProperties.getBoolean(
774 "dalvik.vm.profilesystemserver", false);
775 if (profileSystemServer) {
776 parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
777 }
778
779 /* Request to fork the system server process */
780 pid = Zygote.forkSystemServer(
781 parsedArgs.mUid, parsedArgs.mGid,
782 parsedArgs.mGids,
783 parsedArgs.mRuntimeFlags,
784 null,
785 parsedArgs.mPermittedCapabilities,
786 parsedArgs.mEffectiveCapabilities);
787 } catch (IllegalArgumentException ex) {
788 throw new RuntimeException(ex);
789 }
790
791 /* For child process */
792 if (pid == 0) {
793 if (hasSecondZygote(abiList)) {
794 waitForSecondaryZygote(socketName);
795 }
796
797 zygoteServer.closeServerSocket();
798 return handleSystemServerProcess(parsedArgs);
799 }
800
801 return null;
802 }
forkSystemServer()
:
①Llame al método Zygote.forkSystemServer() para bifurcar un nuevo proceso.
②El proceso hijo después de fork () es el proceso SystemServer, luego espere a que se complete el inicio de zygote y ejecute el código real de SystemServer.
2.4 Diagrama de flujo de inicio de Zygote
3 Resumen
Todos los procesos son creados por Zygote, y el cigoto se utiliza principalmente para la incubación system_server进程
y el procesamiento 应用程序进程
. Después de incubar el primer proceso system_server, al runSelectLoop
esperar y procesar el mensaje, el proceso de aplicación dividida todavía está controlado por system_server, 等待 AMS 给他发消息(告诉 zygote 创建进程)
como la creación de un proceso secundario cuando se inicia la aplicación.
Desde AndroidRuntime hasta ZygoteInit, se divide principalmente en tres procesos principales:
1.:
创建虚拟机——startVm()
Llame a la función de creación de la máquina virtual JNI
2注册JNI函数——startReg()
.: La máquina virtual se creó antes y aquí hay algunas funciones JNI registradas para esta máquina virtual (las funciones utilizadas en el mundo Java posterior son implementaciones nativas y estas funciones deben registrarse con anticipación) 3.
Aquí, cuando sea necesario执行CallStaticViodMethod
, a través de esta función, ingresará al mundo Java cuidadosamente diseñado por Android. Esta función llamará a la función principal de com.android.internal.os.ZygoteInit
Para ingresar al mundo de Java en la función ZygoteInit.main, hay 4 pasos clave:
1.
预加载类和资源——preload()
Principalmente preloadClasses y preloadResources, donde preloadClasses es generalmente una clase cuyo tiempo de carga excede los 1250 ms, por lo que debe precargarse en zygote
2.建立IPC通信服务——初始化ZygoteServer,内部初始化了ZygoteSocket
La comunicación entre zygote y otros programas en el sistema no usa Binder, pero usa Socket basado en AF_UNIX tipo.Es para establecer este Socket
3.Esta启动system_server——forkSystemServer()
función creará el proceso system_server donde reside el Servicio del sistema en el mundo Java.Este proceso es el núcleo del marco y el primer proceso generado por el cigoto. Si muere, provoca que el cigoto se suicide.
4.等待请求——runSelectLoop()
Después de que zygote regrese de startSystemServer, ingresará a la cuarta función clave runSelectLoop. En la primera función ZygoteServer, se registra un socket para IPC y se usará aquí. Aquí Zygote adopta un mecanismo de multiplexación de E/S eficiente para garantizar que duerme cuando no hay solicitud del cliente o procesamiento de datos, de lo contrario responde a la solicitud del cliente.等待 AMS 给他发消息(告诉 zygote 创建进程)
. En este momento, zygote ha completado el trabajo inicial en el mundo de Java, llama a runSelectLoop y comienza a dormir, y se despertará en cualquier momento cuando reciba una solicitud o procesamiento de datos y continuará trabajando.
4 preguntas de la entrevista
1 ¿Cuál es el papel del proceso de inicio?
El proceso init juega un vínculo entre lo anterior y lo siguiente. El propio Android está basado en Linux. El proceso init es el primer proceso del espacio de usuario en el sistema Linux. El proceso init pertenece a un proceso demonio, para ser precisos, es el primer proceso controlado por el usuario en el sistema Linux, su número de proceso es 1 (el número de proceso es 0 es el proceso del kernel) y su ciclo de vida se ejecuta a través de todo el kernel de Linux, siempre. El origen común de todos los demás procesos en Android es el proceso de inicio.
La función de entrada de inicio de Android Q (10.0) se ajusta del init.cpp original a main.cpp, lo que separa las operaciones de cada etapa y hace que el código sea más conciso.
Como proceso número uno del Hijo del Cielo, se le han asignado muchas responsabilidades importantes, que se dividen principalmente en tres etapas:
- El trabajo principal de la primera etapa del proceso de inicio es
挂载分区
crear nodos de dispositivos y algunos directorios clave, inicializar el sistema de salida de registros y habilitar las políticas de seguridad de SELinux.- El trabajo principal de la segunda etapa del proceso de inicio es
初始化属性系统
analizar las reglas de coincidencia de SELinux, procesar la señal de terminación del proceso hijo e iniciar el servicio de atributos del sistema. Se puede decir que cada elemento es muy crítico. Si el primero La etapa es prepararse para el sistema de atributos y SELinux, luego la segunda etapa es implementar realmente estas funciones.- La tercera etapa de init es principalmente
解析init.rc来启动其他进程
ingresar a un bucle infinito y continuar子进程实时监控(守护)
.
La tercera etapa inicia otros procesos a través de initrc, como los nuestros comunes 启动Zygote进程
, 启动SeviceManager进程
etc.
2 ¿Cuál es el proceso original del proceso Cigoto (o el origen del proceso Cigoto)?
Al principio app_process
, Zygote se inició cuando comenzó el proceso de inicio y luego se app_main.cpp
modificó a Zygote.
3 ¿Zygote está en el espacio del kernel o en el espacio del usuario?
Debido a que el proceso de inicio se crea en el espacio del usuario, y Zygote es creado e iniciado por el proceso de inicio, entoncesZygote是在用户空间。
4 ¿Por qué Zygote necesita utilizar la comunicación Socket en lugar de Binder?
Zygote es un proceso importante en Android, es el proceso principal que inicia el proceso de solicitud. Zygote usa Socket para comunicarse con el proceso de la aplicación en lugar de usar el mecanismo IPC Binder en Android, porque Socket y Binder tienen diferentes ventajas y desventajas, y el uso de Socket en el proceso Zygote puede satisfacer mejor las necesidades del proceso Zygote.
Zygote 用 binder 通信会导致死锁
Supongamos que Zygote usa Binder para comunicarse, debido a que Binder admite subprocesos múltiples, hay problemas de concurrencia y la solución al problema de concurrencia es agregar bloqueos. Si la bifurcación del proceso se ejecuta en subprocesos múltiples, Binder puede esperar el bloqueo bajo el mecanismo de bloqueo punto muerto.Zygote 用 binder 通信会导致读写错误
La razón fundamental es que cuando se utiliza un nuevo ProcessState para la comunicación de Binder, mmap necesita solicitar una porción de memoria para proporcionarla al kernel para el intercambio de datos. Y si se bifurca directamente, cuando el proceso hijo se comunica con la carpeta, el kernel continuará usando la dirección solicitada por el proceso padre para escribir datos, y en este momento activará el proceso hijo COW (Copiar en escritura). , lo que hará que se reasigne el espacio de direcciones. El proceso hijo también intenta acceder a la dirección del mmap del proceso padre anterior, lo que provocará fallas en los segmentos SIGSEGV y SEGV_MAPERR.Zygote初始化时,Binder还没开始初始化。
Socket具有良好的跨平台性
, para poder comunicarse entre diferentes sistemas operativos y lenguajes. Esto es muy importante para el proceso Zygote, ya que necesita ejecutarse en diferentes dispositivos y arquitecturas y comunicarse con diferentes procesos de aplicación. El uso de Socket puede hacer que el proceso Zygote sea más flexible y escalable, porque no necesita considerar las restricciones y requisitos específicos que trae Binder.Socket具有简单的API和易于使用的特点
. El proceso Zygote debe iniciarse rápidamente y establecer comunicación con el proceso de la aplicación. Socket proporciona un método de comunicación rápido y confiable, y es fácil de implementar utilizando la API de Socket. Por el contrario, Binder requiere más trabajo de configuración y mantenimiento, lo que puede agregar complejidad y gastos generales innecesarios al proceso Zygote.Socket在数据传输时具有更低的延迟和更高的吞吐量
, que es muy importante para el proceso de cigoto. El proceso Zygote necesita iniciar el proceso de solicitud en un corto período de tiempo y necesita transmitir una gran cantidad de datos y códigos. El alto rendimiento y la baja latencia de Socket lo convierten en una mejor opción.
En resumen, el uso de Socket en lugar de Binder en el proceso Zygote es una elección basada en sus ventajas y necesidades. Aunque Binder juega un papel importante en Android, en algunos casos, el uso de Socket puede proporcionar un mejor rendimiento y una mayor flexibilidad. Además, Binder no estaba maduro al principio y los miembros del equipo preferían usar Socket para la comunicación entre procesos. Posteriormente, se realizaron muchas optimizaciones para que la comunicación de Binder fuera madura y estable.
5 ¿Cada aplicación cargará recursos y clases del sistema?
La función del proceso cigoto:
1. Cree un Socket en el lado del Servicio y abra un ServerSocket para comunicarse con otros procesos.
2. Cargar clases del sistema y recursos del sistema.
3. Inicie el proceso del servidor del sistema.
Después de que el proceso Zygote precarga los recursos del sistema, incuba otros procesos de la máquina virtual y luego comparte la memoria de la máquina virtual y los recursos de la capa de marco (共享内存)
, lo que mejora en gran medida la velocidad de inicio y ejecución de las aplicaciones.
6 ¿Qué hace el síndrome premenstrual? ¿Cómo se entiende el síndrome premenstrual?
Se proporcionan gestión de paquetes, análisis de paquetes, almacenamiento en caché de resultados e interfaces de consulta.
/data/app
carpetas atravesadas- descomprimir
apk
el archivo - dom analiza
AndroidManifest.xml
el archivo.
7 Por qué existe AMS El papel de AMS
- Consulta PMS
- objeto generado por reflexión
- Gestionar el ciclo de vida de la actividad
Centro de caché AMS:ActivityThread
8 Cómo AMS gestiona la actividad, explorando el principio de ejecución de AMS
La actividad es responsable de describir el proceso y el estado de su ciclo de vida en el lado de la aplicación ActivityClientRecord
, pero al final estos procesos y estados son ActivityManagerService(以下简称AMS)
gestionados y controlados.
BroadcastRecord
: Describe el BroadcastReceiver del proceso de solicitud, queBroadcastQueue
es administrado por.ServiceRecord
: Describe el componente del servicio Servicio, que esActiveServices
responsable de la gestión.ContentProviderRecord
: describe el proveedor de contenido ContentProvider,ProviderMap
administrado por.ActivityRecord
: Se utiliza para describir la actividad,ActivityStackSupervisor
gestionada por.