blob: c4c98baf0e4ca5fd798da0edb7c5d1351acf863e [file] [log] [blame]
Tobias Sargeantb9679dc2016-01-19 16:34:54 +00001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.os;
18
19import static android.system.OsConstants.POLLIN;
20
21import android.net.LocalServerSocket;
Robert Sesekded20982016-08-15 13:59:13 -040022import android.net.LocalSocket;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080023import android.os.SystemClock;
24import android.os.Trace;
25import android.provider.DeviceConfig;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000026import android.system.ErrnoException;
Chris Wailes2be26262019-01-11 16:14:43 -080027import android.system.Os;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000028import android.system.StructPollfd;
29import android.util.Log;
Narayan Kamathac0b4be2017-07-05 14:45:38 +010030import android.util.Slog;
Chris Wailes2be26262019-01-11 16:14:43 -080031
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080032import dalvik.system.ZygoteHooks;
33
Chris Wailesba4c2eb2019-01-11 17:13:00 -080034import java.io.ByteArrayInputStream;
35import java.io.DataInputStream;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000036import java.io.FileDescriptor;
Chris Wailes2be26262019-01-11 16:14:43 -080037import java.io.IOException;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000038import java.util.ArrayList;
39
40/**
41 * Server socket class for zygote processes.
42 *
43 * Provides functions to wait for commands on a UNIX domain socket, and fork
44 * off child processes that inherit the initial state of the VM.%
45 *
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080046 * Please see {@link ZygoteArguments} for documentation on the
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000047 * client protocol.
48 */
49class ZygoteServer {
Chris Wailesba4c2eb2019-01-11 17:13:00 -080050 // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000051 public static final String TAG = "ZygoteServer";
52
Robert Sesekd0a190df2018-02-12 18:46:01 -050053 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080054 * The maximim value that will be accepted from the BLASTULA_POOL_SIZE_MAX device property.
55 * is a mirror of BLASTULA_POOL_MAX_LIMIT found in com_android_internal_os_Zygote.cpp.
56 */
57 private static final int BLASTULA_POOL_SIZE_MAX_LIMIT = 100;
58
59 /**
60 * The minimum value that will be accepted from the BLASTULA_POOL_SIZE_MIN device property.
61 */
62 private static final int BLASTULA_POOL_SIZE_MIN_LIMIT = 1;
63
64 /** The default value used for the BLASTULA_POOL_SIZE_MAX device property */
65 private static final String BLASTULA_POOL_SIZE_MAX_DEFAULT = "10";
66
67 /** The default value used for the BLASTULA_POOL_SIZE_MIN device property */
68 private static final String BLASTULA_POOL_SIZE_MIN_DEFAULT = "1";
69
70 /**
Chris Wailesae937142019-01-24 12:57:33 -080071 * Indicates if this Zygote server can support a blastula pool. Currently this should only be
72 * true for the primary and secondary Zygotes, and not the App Zygotes or the WebView Zygote.
73 *
74 * TODO (chriswailes): Make this an explicit argument to the constructor
75 */
76
77 private final boolean mBlastulaPoolSupported;
78
79 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080080 * If the blastula pool should be created and used to start applications.
81 *
82 * Setting this value to false will disable the creation, maintenance, and use of the blastula
83 * pool. When the blastula pool is disabled the application lifecycle will be identical to
84 * previous versions of Android.
85 */
86 private boolean mBlastulaPoolEnabled = false;
87
88 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -050089 * Listening socket that accepts new server connections.
90 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -080091 private LocalServerSocket mZygoteSocket;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000092
Narayan Kamathac0b4be2017-07-05 14:45:38 +010093 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080094 * The name of the blastula socket to use if the blastula pool is enabled.
95 */
96 private LocalServerSocket mBlastulaPoolSocket;
97
98 /**
99 * File descriptor used for communication between the signal handler and the ZygoteServer poll
100 * loop.
101 * */
102 private FileDescriptor mBlastulaPoolEventFD;
103
104 /**
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800105 * Whether or not mZygoteSocket's underlying FD should be closed directly.
106 * If mZygoteSocket is created with an existing FD, closing the socket does
Robert Sesekd0a190df2018-02-12 18:46:01 -0500107 * not close the FD and it must be closed explicitly. If the socket is created
108 * with a name instead, then closing the socket will close the underlying FD
109 * and it should not be double-closed.
110 */
111 private boolean mCloseSocketFd;
112
113 /**
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100114 * Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}.
115 */
116 private boolean mIsForkChild;
117
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800118 /**
119 * The runtime-adjustable maximum Blastula pool size.
120 */
121 private int mBlastulaPoolSizeMax = 0;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000122
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800123 /**
124 * The runtime-adjustable minimum Blastula pool size.
125 */
126 private int mBlastulaPoolSizeMin = 0;
127
128 /**
129 * The runtime-adjustable value used to determine when to re-fill the
130 * blastula pool. The pool will be re-filled when
131 * (sBlastulaPoolMax - gBlastulaPoolCount) >= sBlastulaPoolRefillThreshold.
132 */
133 private int mBlastulaPoolRefillThreshold = 0;
134
135 ZygoteServer() {
136 mBlastulaPoolEventFD = null;
137 mZygoteSocket = null;
138 mBlastulaPoolSocket = null;
Chris Wailesae937142019-01-24 12:57:33 -0800139
140 mBlastulaPoolSupported = false;
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100141 }
142
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000143 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800144 * Initialize the Zygote server with the Zygote server socket, blastula pool server socket,
145 * and blastula pool event FD.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800146 *
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800147 * @param isPrimaryZygote If this is the primary Zygote or not.
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000148 */
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800149 ZygoteServer(boolean isPrimaryZygote) {
150 mBlastulaPoolEventFD = Zygote.getBlastulaPoolEventFD();
151
152 if (isPrimaryZygote) {
153 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
154 mBlastulaPoolSocket =
155 Zygote.createManagedSocketFromInitSocket(
156 Zygote.BLASTULA_POOL_PRIMARY_SOCKET_NAME);
157 } else {
158 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
159 mBlastulaPoolSocket =
160 Zygote.createManagedSocketFromInitSocket(
161 Zygote.BLASTULA_POOL_SECONDARY_SOCKET_NAME);
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000162 }
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800163
164 fetchBlastulaPoolPolicyProps();
Chris Wailesae937142019-01-24 12:57:33 -0800165
166 mBlastulaPoolSupported = true;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800167 }
168
169 void setForkChild() {
170 mIsForkChild = true;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000171 }
172
Chris Wailesae937142019-01-24 12:57:33 -0800173 public boolean isBlastulaPoolEnabled() {
174 return mBlastulaPoolEnabled;
175 }
176
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000177 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500178 * Registers a server socket for zygote command connections. This opens the server socket
179 * at the specified name in the abstract socket namespace.
180 */
181 void registerServerSocketAtAbstractName(String socketName) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800182 if (mZygoteSocket == null) {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500183 try {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800184 mZygoteSocket = new LocalServerSocket(socketName);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500185 mCloseSocketFd = false;
186 } catch (IOException ex) {
187 throw new RuntimeException(
188 "Error binding to abstract socket '" + socketName + "'", ex);
189 }
190 }
191 }
192
193 /**
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000194 * Waits for and accepts a single command connection. Throws
195 * RuntimeException on failure.
196 */
197 private ZygoteConnection acceptCommandPeer(String abiList) {
198 try {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800199 return createNewConnection(mZygoteSocket.accept(), abiList);
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000200 } catch (IOException ex) {
201 throw new RuntimeException(
202 "IOException during accept()", ex);
203 }
204 }
205
Robert Sesekded20982016-08-15 13:59:13 -0400206 protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
207 throws IOException {
208 return new ZygoteConnection(socket, abiList);
209 }
210
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000211 /**
212 * Close and clean up zygote sockets. Called on shutdown and on the
213 * child's exit path.
214 */
215 void closeServerSocket() {
216 try {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800217 if (mZygoteSocket != null) {
218 FileDescriptor fd = mZygoteSocket.getFileDescriptor();
219 mZygoteSocket.close();
Robert Sesekd0a190df2018-02-12 18:46:01 -0500220 if (fd != null && mCloseSocketFd) {
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000221 Os.close(fd);
222 }
223 }
224 } catch (IOException ex) {
225 Log.e(TAG, "Zygote: error closing sockets", ex);
226 } catch (ErrnoException ex) {
227 Log.e(TAG, "Zygote: error closing descriptor", ex);
228 }
229
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800230 mZygoteSocket = null;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000231 }
232
233 /**
234 * Return the server socket's underlying file descriptor, so that
235 * ZygoteConnection can pass it to the native code for proper
236 * closure after a child process is forked off.
237 */
238
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800239 FileDescriptor getZygoteSocketFileDescriptor() {
240 return mZygoteSocket.getFileDescriptor();
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000241 }
242
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800243 private void fetchBlastulaPoolPolicyProps() {
Chris Wailesdb132a32019-02-20 10:49:27 -0800244 if (mBlastulaPoolSupported) {
245 final String blastulaPoolSizeMaxPropString =
246 Zygote.getSystemProperty(
247 DeviceConfig.RuntimeNative.BLASTULA_POOL_SIZE_MAX,
248 BLASTULA_POOL_SIZE_MAX_DEFAULT);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800249
Chris Wailesdb132a32019-02-20 10:49:27 -0800250 if (!blastulaPoolSizeMaxPropString.isEmpty()) {
251 mBlastulaPoolSizeMax =
252 Integer.min(
253 Integer.parseInt(blastulaPoolSizeMaxPropString),
254 BLASTULA_POOL_SIZE_MAX_LIMIT);
255 }
256
257 final String blastulaPoolSizeMinPropString =
258 Zygote.getSystemProperty(
259 DeviceConfig.RuntimeNative.BLASTULA_POOL_SIZE_MIN,
260 BLASTULA_POOL_SIZE_MIN_DEFAULT);
261
262 if (!blastulaPoolSizeMinPropString.isEmpty()) {
263 mBlastulaPoolSizeMin =
264 Integer.max(
265 Integer.parseInt(blastulaPoolSizeMinPropString),
266 BLASTULA_POOL_SIZE_MIN_LIMIT);
267 }
268
269 final String blastulaPoolRefillThresholdPropString =
270 Zygote.getSystemProperty(
271 DeviceConfig.RuntimeNative.BLASTULA_POOL_REFILL_THRESHOLD,
272 Integer.toString(mBlastulaPoolSizeMax / 2));
273
274 if (!blastulaPoolRefillThresholdPropString.isEmpty()) {
275 mBlastulaPoolRefillThreshold =
276 Integer.min(
277 Integer.parseInt(blastulaPoolRefillThresholdPropString),
278 mBlastulaPoolSizeMax);
279 }
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800280 }
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800281 }
282
283 private long mLastPropCheckTimestamp = 0;
284
285 private void fetchBlastulaPoolPolicyPropsWithMinInterval() {
286 final long currentTimestamp = SystemClock.elapsedRealtime();
287
288 if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
289 fetchBlastulaPoolPolicyProps();
290 mLastPropCheckTimestamp = currentTimestamp;
291 }
292 }
293
294 /**
295 * Checks to see if the current policy says that pool should be refilled, and spawns new
296 * blastulas if necessary.
297 *
298 * @param sessionSocketRawFDs Anonymous session sockets that are currently open
299 * @return In the Zygote process this function will always return null; in blastula processes
300 * this function will return a Runnable object representing the new application that is
301 * passed up from blastulaMain.
302 */
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800303
Chris Wailesae937142019-01-24 12:57:33 -0800304 Runnable fillBlastulaPool(int[] sessionSocketRawFDs) {
305 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillBlastulaPool");
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800306
Chris Wailesae937142019-01-24 12:57:33 -0800307 int blastulaPoolCount = Zygote.getBlastulaPoolCount();
308 int numBlastulasToSpawn = mBlastulaPoolSizeMax - blastulaPoolCount;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800309
Chris Wailesae937142019-01-24 12:57:33 -0800310 if (blastulaPoolCount < mBlastulaPoolSizeMin
311 || numBlastulasToSpawn >= mBlastulaPoolRefillThreshold) {
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800312
Chris Wailesae937142019-01-24 12:57:33 -0800313 // Disable some VM functionality and reset some system values
314 // before forking.
315 ZygoteHooks.preFork();
316 Zygote.resetNicePriority();
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800317
Chris Wailesae937142019-01-24 12:57:33 -0800318 while (blastulaPoolCount++ < mBlastulaPoolSizeMax) {
319 Runnable caller = Zygote.forkBlastula(mBlastulaPoolSocket, sessionSocketRawFDs);
320
321 if (caller != null) {
322 return caller;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800323 }
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800324 }
325
Chris Wailesae937142019-01-24 12:57:33 -0800326 // Re-enable runtime services for the Zygote. Blastula services
327 // are re-enabled in specializeBlastula.
328 ZygoteHooks.postForkCommon();
329
330 Log.i("zygote",
331 "Filled the blastula pool. New blastulas: " + numBlastulasToSpawn);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800332 }
333
Chris Wailesae937142019-01-24 12:57:33 -0800334 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
335
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800336 return null;
337 }
338
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000339 /**
Chris Wailesdb132a32019-02-20 10:49:27 -0800340 * Empty or fill the blastula pool as dictated by the current and new blastula pool statuses.
341 */
342 Runnable setBlastulaPoolStatus(boolean newStatus, LocalSocket sessionSocket) {
343 if (!mBlastulaPoolSupported) {
344 Log.w(TAG,
345 "Attempting to enable a blastula pool for a Zygote that doesn't support it.");
346 return null;
347 } else if (mBlastulaPoolEnabled == newStatus) {
348 return null;
349 }
350
351 mBlastulaPoolEnabled = newStatus;
352
353 if (newStatus) {
354 return fillBlastulaPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() });
355 } else {
356 Zygote.emptyBlastulaPool();
357 return null;
358 }
359 }
360
361 /**
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000362 * Runs the zygote process's select loop. Accepts new connections as
363 * they happen, and reads commands from connections one spawn-request's
364 * worth at a time.
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000365 */
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100366 Runnable runSelectLoop(String abiList) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800367 ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000368 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
369
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800370 socketFDs.add(mZygoteSocket.getFileDescriptor());
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000371 peers.add(null);
372
373 while (true) {
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800374 fetchBlastulaPoolPolicyPropsWithMinInterval();
375
Chris Wailesae937142019-01-24 12:57:33 -0800376 int[] blastulaPipeFDs = null;
377 StructPollfd[] pollFDs = null;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800378
Chris Wailesae937142019-01-24 12:57:33 -0800379 // Allocate enough space for the poll structs, taking into account
380 // the state of the blastula pool for this Zygote (could be a
381 // regular Zygote, a WebView Zygote, or an AppZygote).
382 if (mBlastulaPoolEnabled) {
383 blastulaPipeFDs = Zygote.getBlastulaPipeFDs();
384 pollFDs = new StructPollfd[socketFDs.size() + 1 + blastulaPipeFDs.length];
385 } else {
386 pollFDs = new StructPollfd[socketFDs.size()];
387 }
388
389 /*
390 * For reasons of correctness the blastula pool pipe and event FDs
391 * must be processed before the session and server sockets. This
392 * is to ensure that the blastula pool accounting information is
393 * accurate when handling other requests like API blacklist
394 * exemptions.
395 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800396
397 int pollIndex = 0;
398 for (FileDescriptor socketFD : socketFDs) {
399 pollFDs[pollIndex] = new StructPollfd();
400 pollFDs[pollIndex].fd = socketFD;
401 pollFDs[pollIndex].events = (short) POLLIN;
402 ++pollIndex;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000403 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800404
405 final int blastulaPoolEventFDIndex = pollIndex;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800406
Chris Wailesae937142019-01-24 12:57:33 -0800407 if (mBlastulaPoolEnabled) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800408 pollFDs[pollIndex] = new StructPollfd();
Chris Wailesae937142019-01-24 12:57:33 -0800409 pollFDs[pollIndex].fd = mBlastulaPoolEventFD;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800410 pollFDs[pollIndex].events = (short) POLLIN;
411 ++pollIndex;
Chris Wailesae937142019-01-24 12:57:33 -0800412
413 for (int blastulaPipeFD : blastulaPipeFDs) {
414 FileDescriptor managedFd = new FileDescriptor();
415 managedFd.setInt$(blastulaPipeFD);
416
417 pollFDs[pollIndex] = new StructPollfd();
418 pollFDs[pollIndex].fd = managedFd;
419 pollFDs[pollIndex].events = (short) POLLIN;
420 ++pollIndex;
421 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800422 }
423
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000424 try {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800425 Os.poll(pollFDs, -1);
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000426 } catch (ErrnoException ex) {
427 throw new RuntimeException("poll failed", ex);
428 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800429
Chris Wailesae937142019-01-24 12:57:33 -0800430 boolean blastulaPoolFDRead = false;
431
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800432 while (--pollIndex >= 0) {
433 if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000434 continue;
435 }
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100436
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800437 if (pollIndex == 0) {
438 // Zygote server socket
439
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000440 ZygoteConnection newPeer = acceptCommandPeer(abiList);
441 peers.add(newPeer);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800442 socketFDs.add(newPeer.getFileDescriptor());
443
444 } else if (pollIndex < blastulaPoolEventFDIndex) {
445 // Session socket accepted from the Zygote server socket
446
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100447 try {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800448 ZygoteConnection connection = peers.get(pollIndex);
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100449 final Runnable command = connection.processOneCommand(this);
450
Chris Wailesdb132a32019-02-20 10:49:27 -0800451 // TODO (chriswailes): Is this extra check necessary?
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100452 if (mIsForkChild) {
453 // We're in the child. We should always have a command to run at this
454 // stage if processOneCommand hasn't called "exec".
455 if (command == null) {
456 throw new IllegalStateException("command == null");
457 }
458
459 return command;
460 } else {
461 // We're in the server - we should never have any commands to run.
462 if (command != null) {
463 throw new IllegalStateException("command != null");
464 }
465
466 // We don't know whether the remote side of the socket was closed or
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800467 // not until we attempt to read from it from processOneCommand. This
468 // shows up as a regular POLLIN event in our regular processing loop.
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100469 if (connection.isClosedByPeer()) {
470 connection.closeSocket();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800471 peers.remove(pollIndex);
472 socketFDs.remove(pollIndex);
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100473 }
474 }
475 } catch (Exception e) {
476 if (!mIsForkChild) {
477 // We're in the server so any exception here is one that has taken place
478 // pre-fork while processing commands or reading / writing from the
479 // control socket. Make a loud noise about any such exceptions so that
480 // we know exactly what failed and why.
481
482 Slog.e(TAG, "Exception executing zygote command: ", e);
483
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800484 // Make sure the socket is closed so that the other end knows
485 // immediately that something has gone wrong and doesn't time out
486 // waiting for a response.
487 ZygoteConnection conn = peers.remove(pollIndex);
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100488 conn.closeSocket();
489
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800490 socketFDs.remove(pollIndex);
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100491 } else {
492 // We're in the child so any exception caught here has happened post
493 // fork and before we execute ActivityThread.main (or any other main()
494 // method). Log the details of the exception and bring down the process.
495 Log.e(TAG, "Caught post-fork exception in child process.", e);
496 throw e;
497 }
Robert Sesekd0a190df2018-02-12 18:46:01 -0500498 } finally {
499 // Reset the child flag, in the event that the child process is a child-
500 // zygote. The flag will not be consulted this loop pass after the Runnable
501 // is returned.
502 mIsForkChild = false;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000503 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800504 } else {
505 // Either the blastula pool event FD or a blastula reporting pipe.
506
507 // If this is the event FD the payload will be the number of blastulas removed.
508 // If this is a reporting pipe FD the payload will be the PID of the blastula
509 // that was just specialized.
510 long messagePayload = -1;
511
512 try {
513 byte[] buffer = new byte[Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES];
514 int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
515
516 if (readBytes == Zygote.BLASTULA_MANAGEMENT_MESSAGE_BYTES) {
517 DataInputStream inputStream =
518 new DataInputStream(new ByteArrayInputStream(buffer));
519
520 messagePayload = inputStream.readLong();
521 } else {
522 Log.e(TAG, "Incomplete read from blastula management FD of size "
523 + readBytes);
524 continue;
525 }
526 } catch (Exception ex) {
527 if (pollIndex == blastulaPoolEventFDIndex) {
528 Log.e(TAG, "Failed to read from blastula pool event FD: "
529 + ex.getMessage());
530 } else {
531 Log.e(TAG, "Failed to read from blastula reporting pipe: "
532 + ex.getMessage());
533 }
534
535 continue;
536 }
537
538 if (pollIndex > blastulaPoolEventFDIndex) {
539 Zygote.removeBlastulaTableEntry((int) messagePayload);
540 }
541
Chris Wailesae937142019-01-24 12:57:33 -0800542 blastulaPoolFDRead = true;
543 }
544 }
545
546 // Check to see if the blastula pool needs to be refilled.
547 if (blastulaPoolFDRead) {
548 int[] sessionSocketRawFDs =
549 socketFDs.subList(1, socketFDs.size())
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800550 .stream()
551 .mapToInt(fd -> fd.getInt$())
552 .toArray();
553
Chris Wailesae937142019-01-24 12:57:33 -0800554 final Runnable command = fillBlastulaPool(sessionSocketRawFDs);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800555
Chris Wailesae937142019-01-24 12:57:33 -0800556 if (command != null) {
557 return command;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000558 }
559 }
560 }
561 }
562}