blob: 65953172818e19851675a3c03b26f1b3348830ef [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 /**
Chris Wailes7e797b62019-02-22 18:29:22 -080054 * The maximim value that will be accepted from the USAP_POOL_SIZE_MAX device property.
55 * is a mirror of USAP_POOL_MAX_LIMIT found in com_android_internal_os_Zygote.cpp.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080056 */
Chris Wailes7e797b62019-02-22 18:29:22 -080057 private static final int USAP_POOL_SIZE_MAX_LIMIT = 100;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080058
59 /**
Chris Wailes7e797b62019-02-22 18:29:22 -080060 * The minimum value that will be accepted from the USAP_POOL_SIZE_MIN device property.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080061 */
Chris Wailes7e797b62019-02-22 18:29:22 -080062 private static final int USAP_POOL_SIZE_MIN_LIMIT = 1;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080063
Chris Wailes7e797b62019-02-22 18:29:22 -080064 /** The default value used for the USAP_POOL_SIZE_MAX device property */
65 private static final String USAP_POOL_SIZE_MAX_DEFAULT = "10";
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080066
Chris Wailes7e797b62019-02-22 18:29:22 -080067 /** The default value used for the USAP_POOL_SIZE_MIN device property */
68 private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1";
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080069
70 /**
Chris Wailes7e797b62019-02-22 18:29:22 -080071 * Indicates if this Zygote server can support a unspecialized app process pool. Currently this
72 * should only be true for the primary and secondary Zygotes, and not the App Zygotes or the
73 * WebView Zygote.
Chris Wailesae937142019-01-24 12:57:33 -080074 *
75 * TODO (chriswailes): Make this an explicit argument to the constructor
76 */
77
Chris Wailes7e797b62019-02-22 18:29:22 -080078 private final boolean mUsapPoolSupported;
Chris Wailesae937142019-01-24 12:57:33 -080079
80 /**
Chris Wailes7e797b62019-02-22 18:29:22 -080081 * If the unspecialized app process pool should be created and used to start applications.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080082 *
Chris Wailes7e797b62019-02-22 18:29:22 -080083 * Setting this value to false will disable the creation, maintenance, and use of the USAP
84 * pool. When the USAP pool is disabled the application lifecycle will be identical to
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080085 * previous versions of Android.
86 */
Chris Wailes7e797b62019-02-22 18:29:22 -080087 private boolean mUsapPoolEnabled = false;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080088
89 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -050090 * Listening socket that accepts new server connections.
91 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -080092 private LocalServerSocket mZygoteSocket;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +000093
Narayan Kamathac0b4be2017-07-05 14:45:38 +010094 /**
Chris Wailes7e797b62019-02-22 18:29:22 -080095 * The name of the unspecialized app process pool socket to use if the USAP pool is enabled.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080096 */
Chris Wailes7e797b62019-02-22 18:29:22 -080097 private LocalServerSocket mUsapPoolSocket;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080098
99 /**
100 * File descriptor used for communication between the signal handler and the ZygoteServer poll
101 * loop.
102 * */
Chris Wailes7e797b62019-02-22 18:29:22 -0800103 private FileDescriptor mUsapPoolEventFD;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800104
105 /**
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800106 * Whether or not mZygoteSocket's underlying FD should be closed directly.
107 * If mZygoteSocket is created with an existing FD, closing the socket does
Robert Sesekd0a190df2018-02-12 18:46:01 -0500108 * not close the FD and it must be closed explicitly. If the socket is created
109 * with a name instead, then closing the socket will close the underlying FD
110 * and it should not be double-closed.
111 */
112 private boolean mCloseSocketFd;
113
114 /**
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100115 * Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}.
116 */
117 private boolean mIsForkChild;
118
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800119 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800120 * The runtime-adjustable maximum USAP pool size.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800121 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800122 private int mUsapPoolSizeMax = 0;
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000123
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800124 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800125 * The runtime-adjustable minimum USAP pool size.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800126 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800127 private int mUsapPoolSizeMin = 0;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800128
129 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800130 * The runtime-adjustable value used to determine when to re-fill the USAP pool. The pool will
131 * be re-filled when (mUsapPoolMax - gUsapPoolCount) >= sUsapPoolRefillThreshold.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800132 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800133 private int mUsapPoolRefillThreshold = 0;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800134
135 ZygoteServer() {
Chris Wailes7e797b62019-02-22 18:29:22 -0800136 mUsapPoolEventFD = null;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800137 mZygoteSocket = null;
Chris Wailes7e797b62019-02-22 18:29:22 -0800138 mUsapPoolSocket = null;
Chris Wailesae937142019-01-24 12:57:33 -0800139
Chris Wailes7e797b62019-02-22 18:29:22 -0800140 mUsapPoolSupported = false;
Narayan Kamathac0b4be2017-07-05 14:45:38 +0100141 }
142
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000143 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800144 * Initialize the Zygote server with the Zygote server socket, USAP pool server socket, and USAP
145 * 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) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800150 mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800151
152 if (isPrimaryZygote) {
153 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
Chris Wailes7e797b62019-02-22 18:29:22 -0800154 mUsapPoolSocket =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800155 Zygote.createManagedSocketFromInitSocket(
Chris Wailes7e797b62019-02-22 18:29:22 -0800156 Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800157 } else {
158 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
Chris Wailes7e797b62019-02-22 18:29:22 -0800159 mUsapPoolSocket =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800160 Zygote.createManagedSocketFromInitSocket(
Chris Wailes7e797b62019-02-22 18:29:22 -0800161 Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
Tobias Sargeantb9679dc2016-01-19 16:34:54 +0000162 }
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800163
Chris Wailes7e797b62019-02-22 18:29:22 -0800164 fetchUsapPoolPolicyProps();
Chris Wailesae937142019-01-24 12:57:33 -0800165
Chris Wailes7e797b62019-02-22 18:29:22 -0800166 mUsapPoolSupported = 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 Wailes7e797b62019-02-22 18:29:22 -0800173 public boolean isUsapPoolEnabled() {
174 return mUsapPoolEnabled;
Chris Wailesae937142019-01-24 12:57:33 -0800175 }
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
Chris Wailes7e797b62019-02-22 18:29:22 -0800243 private void fetchUsapPoolPolicyProps() {
244 if (mUsapPoolSupported) {
245 final String usapPoolSizeMaxPropString =
Chris Wailesdb132a32019-02-20 10:49:27 -0800246 Zygote.getSystemProperty(
Chris Wailes7e797b62019-02-22 18:29:22 -0800247 DeviceConfig.RuntimeNative.USAP_POOL_SIZE_MAX,
248 USAP_POOL_SIZE_MAX_DEFAULT);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800249
Chris Wailes7e797b62019-02-22 18:29:22 -0800250 if (!usapPoolSizeMaxPropString.isEmpty()) {
251 mUsapPoolSizeMax =
Chris Wailesdb132a32019-02-20 10:49:27 -0800252 Integer.min(
Chris Wailes7e797b62019-02-22 18:29:22 -0800253 Integer.parseInt(usapPoolSizeMaxPropString),
254 USAP_POOL_SIZE_MAX_LIMIT);
Chris Wailesdb132a32019-02-20 10:49:27 -0800255 }
256
Chris Wailes7e797b62019-02-22 18:29:22 -0800257 final String usapPoolSizeMinPropString =
Chris Wailesdb132a32019-02-20 10:49:27 -0800258 Zygote.getSystemProperty(
Chris Wailes7e797b62019-02-22 18:29:22 -0800259 DeviceConfig.RuntimeNative.USAP_POOL_SIZE_MIN,
260 USAP_POOL_SIZE_MIN_DEFAULT);
Chris Wailesdb132a32019-02-20 10:49:27 -0800261
Chris Wailes7e797b62019-02-22 18:29:22 -0800262 if (!usapPoolSizeMinPropString.isEmpty()) {
263 mUsapPoolSizeMin =
Chris Wailesdb132a32019-02-20 10:49:27 -0800264 Integer.max(
Chris Wailes7e797b62019-02-22 18:29:22 -0800265 Integer.parseInt(usapPoolSizeMinPropString),
266 USAP_POOL_SIZE_MIN_LIMIT);
Chris Wailesdb132a32019-02-20 10:49:27 -0800267 }
268
Chris Wailes7e797b62019-02-22 18:29:22 -0800269 final String usapPoolRefillThresholdPropString =
Chris Wailesdb132a32019-02-20 10:49:27 -0800270 Zygote.getSystemProperty(
Chris Wailes7e797b62019-02-22 18:29:22 -0800271 DeviceConfig.RuntimeNative.USAP_POOL_REFILL_THRESHOLD,
272 Integer.toString(mUsapPoolSizeMax / 2));
Chris Wailesdb132a32019-02-20 10:49:27 -0800273
Chris Wailes7e797b62019-02-22 18:29:22 -0800274 if (!usapPoolRefillThresholdPropString.isEmpty()) {
275 mUsapPoolRefillThreshold =
Chris Wailesdb132a32019-02-20 10:49:27 -0800276 Integer.min(
Chris Wailes7e797b62019-02-22 18:29:22 -0800277 Integer.parseInt(usapPoolRefillThresholdPropString),
278 mUsapPoolSizeMax);
Chris Wailesdb132a32019-02-20 10:49:27 -0800279 }
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800280 }
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800281 }
282
283 private long mLastPropCheckTimestamp = 0;
284
Chris Wailes7e797b62019-02-22 18:29:22 -0800285 private void fetchUsapPoolPolicyPropsWithMinInterval() {
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800286 final long currentTimestamp = SystemClock.elapsedRealtime();
287
288 if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800289 fetchUsapPoolPolicyProps();
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800290 mLastPropCheckTimestamp = currentTimestamp;
291 }
292 }
293
294 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800295 * Checks to see if the current policy says that pool should be refilled, and spawns new USAPs
296 * if necessary.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800297 *
298 * @param sessionSocketRawFDs Anonymous session sockets that are currently open
Chris Wailes7e797b62019-02-22 18:29:22 -0800299 * @return In the Zygote process this function will always return null; in unspecialized app
300 * processes this function will return a Runnable object representing the new
301 * application that is passed up from usapMain.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800302 */
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800303
Chris Wailes7e797b62019-02-22 18:29:22 -0800304 Runnable fillUsapPool(int[] sessionSocketRawFDs) {
305 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool");
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800306
Chris Wailes7e797b62019-02-22 18:29:22 -0800307 int usapPoolCount = Zygote.getUsapPoolCount();
308 int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800309
Chris Wailes7e797b62019-02-22 18:29:22 -0800310 if (usapPoolCount < mUsapPoolSizeMin
311 || numUsapsToSpawn >= mUsapPoolRefillThreshold) {
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 Wailes7e797b62019-02-22 18:29:22 -0800318 while (usapPoolCount++ < mUsapPoolSizeMax) {
319 Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs);
Chris Wailesae937142019-01-24 12:57:33 -0800320
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 Wailes7e797b62019-02-22 18:29:22 -0800326 // Re-enable runtime services for the Zygote. Services for unspecialized app process
327 // are re-enabled in specializeAppProcess.
Chris Wailesae937142019-01-24 12:57:33 -0800328 ZygoteHooks.postForkCommon();
329
330 Log.i("zygote",
Chris Wailes7e797b62019-02-22 18:29:22 -0800331 "Filled the USAP pool. New USAPs: " + numUsapsToSpawn);
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 Wailes7e797b62019-02-22 18:29:22 -0800340 * Empty or fill the USAP pool as dictated by the current and new USAP pool statuses.
Chris Wailesdb132a32019-02-20 10:49:27 -0800341 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800342 Runnable setUsapPoolStatus(boolean newStatus, LocalSocket sessionSocket) {
343 if (!mUsapPoolSupported) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800344 Log.w(TAG,
Chris Wailes7e797b62019-02-22 18:29:22 -0800345 "Attempting to enable a USAP pool for a Zygote that doesn't support it.");
Chris Wailesdb132a32019-02-20 10:49:27 -0800346 return null;
Chris Wailes7e797b62019-02-22 18:29:22 -0800347 } else if (mUsapPoolEnabled == newStatus) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800348 return null;
349 }
350
Chris Wailes7e797b62019-02-22 18:29:22 -0800351 mUsapPoolEnabled = newStatus;
Chris Wailesdb132a32019-02-20 10:49:27 -0800352
353 if (newStatus) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800354 return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() });
Chris Wailesdb132a32019-02-20 10:49:27 -0800355 } else {
Chris Wailes7e797b62019-02-22 18:29:22 -0800356 Zygote.emptyUsapPool();
Chris Wailesdb132a32019-02-20 10:49:27 -0800357 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) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800374 fetchUsapPoolPolicyPropsWithMinInterval();
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800375
Chris Wailes7e797b62019-02-22 18:29:22 -0800376 int[] usapPipeFDs = null;
Chris Wailesae937142019-01-24 12:57:33 -0800377 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
Chris Wailes7e797b62019-02-22 18:29:22 -0800380 // the state of the USAP pool for this Zygote (could be a
Chris Wailesae937142019-01-24 12:57:33 -0800381 // regular Zygote, a WebView Zygote, or an AppZygote).
Chris Wailes7e797b62019-02-22 18:29:22 -0800382 if (mUsapPoolEnabled) {
383 usapPipeFDs = Zygote.getUsapPipeFDs();
384 pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
Chris Wailesae937142019-01-24 12:57:33 -0800385 } else {
386 pollFDs = new StructPollfd[socketFDs.size()];
387 }
388
389 /*
Chris Wailes7e797b62019-02-22 18:29:22 -0800390 * For reasons of correctness the USAP pool pipe and event FDs
Chris Wailesae937142019-01-24 12:57:33 -0800391 * must be processed before the session and server sockets. This
Chris Wailes7e797b62019-02-22 18:29:22 -0800392 * is to ensure that the USAP pool accounting information is
Chris Wailesae937142019-01-24 12:57:33 -0800393 * 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
Chris Wailes7e797b62019-02-22 18:29:22 -0800405 final int usapPoolEventFDIndex = pollIndex;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800406
Chris Wailes7e797b62019-02-22 18:29:22 -0800407 if (mUsapPoolEnabled) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800408 pollFDs[pollIndex] = new StructPollfd();
Chris Wailes7e797b62019-02-22 18:29:22 -0800409 pollFDs[pollIndex].fd = mUsapPoolEventFD;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800410 pollFDs[pollIndex].events = (short) POLLIN;
411 ++pollIndex;
Chris Wailesae937142019-01-24 12:57:33 -0800412
Chris Wailes7e797b62019-02-22 18:29:22 -0800413 for (int usapPipeFD : usapPipeFDs) {
Chris Wailesae937142019-01-24 12:57:33 -0800414 FileDescriptor managedFd = new FileDescriptor();
Chris Wailes7e797b62019-02-22 18:29:22 -0800415 managedFd.setInt$(usapPipeFD);
Chris Wailesae937142019-01-24 12:57:33 -0800416
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 Wailes7e797b62019-02-22 18:29:22 -0800430 boolean usapPoolFDRead = false;
Chris Wailesae937142019-01-24 12:57:33 -0800431
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
Chris Wailes7e797b62019-02-22 18:29:22 -0800444 } else if (pollIndex < usapPoolEventFDIndex) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800445 // 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 {
Chris Wailes7e797b62019-02-22 18:29:22 -0800505 // Either the USAP pool event FD or a USAP reporting pipe.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800506
Chris Wailes7e797b62019-02-22 18:29:22 -0800507 // If this is the event FD the payload will be the number of USAPs removed.
508 // If this is a reporting pipe FD the payload will be the PID of the USAP
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800509 // that was just specialized.
510 long messagePayload = -1;
511
512 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800513 byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800514 int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
515
Chris Wailes7e797b62019-02-22 18:29:22 -0800516 if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800517 DataInputStream inputStream =
518 new DataInputStream(new ByteArrayInputStream(buffer));
519
520 messagePayload = inputStream.readLong();
521 } else {
Chris Wailes7e797b62019-02-22 18:29:22 -0800522 Log.e(TAG, "Incomplete read from USAP management FD of size "
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800523 + readBytes);
524 continue;
525 }
526 } catch (Exception ex) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800527 if (pollIndex == usapPoolEventFDIndex) {
528 Log.e(TAG, "Failed to read from USAP pool event FD: "
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800529 + ex.getMessage());
530 } else {
Chris Wailes7e797b62019-02-22 18:29:22 -0800531 Log.e(TAG, "Failed to read from USAP reporting pipe: "
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800532 + ex.getMessage());
533 }
534
535 continue;
536 }
537
Chris Wailes7e797b62019-02-22 18:29:22 -0800538 if (pollIndex > usapPoolEventFDIndex) {
539 Zygote.removeUsapTableEntry((int) messagePayload);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800540 }
541
Chris Wailes7e797b62019-02-22 18:29:22 -0800542 usapPoolFDRead = true;
Chris Wailesae937142019-01-24 12:57:33 -0800543 }
544 }
545
Chris Wailes7e797b62019-02-22 18:29:22 -0800546 // Check to see if the USAP pool needs to be refilled.
547 if (usapPoolFDRead) {
Chris Wailesae937142019-01-24 12:57:33 -0800548 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 Wailes7e797b62019-02-22 18:29:22 -0800554 final Runnable command = fillUsapPool(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}