blob: e49b65e63c770b5b3ada3e362a1aea00823fdac3 [file] [log] [blame]
Robert Sesek8f8d1872016-03-18 16:52:57 -04001/*
2 * Copyright (C) 2016 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 android.os;
18
Sudheer Shankad81b1d72018-09-05 16:37:30 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010021import android.content.pm.ApplicationInfo;
Robert Sesek8f8d1872016-03-18 16:52:57 -040022import android.net.LocalSocket;
23import android.net.LocalSocketAddress;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080024import android.provider.DeviceConfig;
Robert Sesek8f8d1872016-03-18 16:52:57 -040025import android.util.Log;
Gustav Senntonf0c52b52017-04-27 17:00:50 +010026import android.util.Slog;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010027
Robert Sesekded20982016-08-15 13:59:13 -040028import com.android.internal.annotations.GuardedBy;
Robert Sesek8f8d1872016-03-18 16:52:57 -040029import com.android.internal.os.Zygote;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010030
Robert Sesek8f8d1872016-03-18 16:52:57 -040031import java.io.BufferedWriter;
32import java.io.DataInputStream;
33import java.io.IOException;
34import java.io.OutputStreamWriter;
35import java.nio.charset.StandardCharsets;
36import java.util.ArrayList;
37import java.util.Arrays;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010038import java.util.Base64;
Mathew Inwood8faeab82018-03-16 14:26:08 +000039import java.util.Collections;
Robert Sesek8f8d1872016-03-18 16:52:57 -040040import java.util.List;
Robert Sesekd0a190df2018-02-12 18:46:01 -050041import java.util.UUID;
Robert Sesek8f8d1872016-03-18 16:52:57 -040042
43/*package*/ class ZygoteStartFailedEx extends Exception {
44 ZygoteStartFailedEx(String s) {
45 super(s);
46 }
47
48 ZygoteStartFailedEx(Throwable cause) {
49 super(cause);
50 }
51
52 ZygoteStartFailedEx(String s, Throwable cause) {
53 super(s, cause);
54 }
55}
56
57/**
58 * Maintains communication state with the zygote processes. This class is responsible
59 * for the sockets opened to the zygotes and for starting processes on behalf of the
60 * {@link android.os.Process} class.
61 *
62 * {@hide}
63 */
64public class ZygoteProcess {
Chris Wailesefce9292019-01-11 13:19:20 -080065
66 /**
67 * @hide for internal use only.
68 */
Martijn Coenen82dc85a2019-01-28 13:12:28 +010069 public static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
70
71 /**
72 * @hide for internal use only.
73 *
74 * Use a relatively short delay, because for app zygote, this is in the critical path of
75 * service launch.
76 */
77 public static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
78
79 /**
Chris Wailesefce9292019-01-11 13:19:20 -080080 * @hide for internal use only
81 */
Robert Sesek8f8d1872016-03-18 16:52:57 -040082 private static final String LOG_TAG = "ZygoteProcess";
83
84 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080085 * The default value for enabling the blastula pool.
86 */
87 private static final String BLASTULA_POOL_ENABLED_DEFAULT = "false";
88
89 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -040090 * The name of the socket used to communicate with the primary zygote.
91 */
Chris Wailesefce9292019-01-11 13:19:20 -080092 private final LocalSocketAddress mZygoteSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -040093
94 /**
95 * The name of the secondary (alternate ABI) zygote socket.
96 */
Chris Wailesefce9292019-01-11 13:19:20 -080097 private final LocalSocketAddress mZygoteSecondarySocketAddress;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080098
Chris Wailesba4c2eb2019-01-11 17:13:00 -080099 /**
100 * The name of the socket used to communicate with the primary blastula pool.
101 */
102 private final LocalSocketAddress mBlastulaPoolSocketAddress;
103
104 /**
105 * The name of the socket used to communicate with the secondary (alternate ABI) blastula pool.
106 */
107 private final LocalSocketAddress mBlastulaPoolSecondarySocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400108
Chris Wailesefce9292019-01-11 13:19:20 -0800109 public ZygoteProcess() {
110 mZygoteSocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800111 new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME,
112 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesefce9292019-01-11 13:19:20 -0800113 mZygoteSecondarySocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800114 new LocalSocketAddress(Zygote.SECONDARY_SOCKET_NAME,
Chris Wailesefce9292019-01-11 13:19:20 -0800115 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800116
117 mBlastulaPoolSocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800118 new LocalSocketAddress(Zygote.BLASTULA_POOL_PRIMARY_SOCKET_NAME,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800119 LocalSocketAddress.Namespace.RESERVED);
120 mBlastulaPoolSecondarySocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800121 new LocalSocketAddress(Zygote.BLASTULA_POOL_SECONDARY_SOCKET_NAME,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800122 LocalSocketAddress.Namespace.RESERVED);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800123
Chris Wailesdb132a32019-02-20 10:49:27 -0800124 if (fetchBlastulaPoolEnabledProp()) {
125 informZygotesOfBlastulaPoolStatus();
126 }
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500127 }
128
Chris Wailesefce9292019-01-11 13:19:20 -0800129 public ZygoteProcess(LocalSocketAddress primarySocketAddress,
130 LocalSocketAddress secondarySocketAddress) {
131 mZygoteSocketAddress = primarySocketAddress;
132 mZygoteSecondarySocketAddress = secondarySocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800133
134 mBlastulaPoolSocketAddress = null;
135 mBlastulaPoolSecondarySocketAddress = null;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400136 }
137
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500138 public LocalSocketAddress getPrimarySocketAddress() {
Chris Wailesefce9292019-01-11 13:19:20 -0800139 return mZygoteSocketAddress;
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500140 }
141
Robert Sesek8f8d1872016-03-18 16:52:57 -0400142 /**
143 * State for communicating with the zygote process.
144 */
145 public static class ZygoteState {
Chris Wailesefce9292019-01-11 13:19:20 -0800146 final LocalSocketAddress mZygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800147 final LocalSocketAddress mBlastulaSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400148
Chris Wailesefce9292019-01-11 13:19:20 -0800149 private final LocalSocket mZygoteSessionSocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400150
Chris Wailesefce9292019-01-11 13:19:20 -0800151 final DataInputStream mZygoteInputStream;
152 final BufferedWriter mZygoteOutputWriter;
153
154 private final List<String> mABIList;
155
156 private boolean mClosed;
157
158 private ZygoteState(LocalSocketAddress zygoteSocketAddress,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800159 LocalSocketAddress blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800160 LocalSocket zygoteSessionSocket,
161 DataInputStream zygoteInputStream,
162 BufferedWriter zygoteOutputWriter,
163 List<String> abiList) {
164 this.mZygoteSocketAddress = zygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800165 this.mBlastulaSocketAddress = blastulaSocketAddress;
Chris Wailesefce9292019-01-11 13:19:20 -0800166 this.mZygoteSessionSocket = zygoteSessionSocket;
167 this.mZygoteInputStream = zygoteInputStream;
168 this.mZygoteOutputWriter = zygoteOutputWriter;
169 this.mABIList = abiList;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400170 }
171
Chris Wailesefce9292019-01-11 13:19:20 -0800172 /**
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800173 * Create a new ZygoteState object by connecting to the given Zygote socket and saving the
174 * given blastula socket address.
Chris Wailesefce9292019-01-11 13:19:20 -0800175 *
176 * @param zygoteSocketAddress Zygote socket to connect to
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800177 * @param blastulaSocketAddress Blastula socket address to save for later
Chris Wailesefce9292019-01-11 13:19:20 -0800178 * @return A new ZygoteState object containing a session socket for the given Zygote socket
179 * address
180 * @throws IOException
181 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800182 public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress,
183 LocalSocketAddress blastulaSocketAddress)
Chris Wailesefce9292019-01-11 13:19:20 -0800184 throws IOException {
185
Robert Sesek8f8d1872016-03-18 16:52:57 -0400186 DataInputStream zygoteInputStream = null;
Chris Wailesefce9292019-01-11 13:19:20 -0800187 BufferedWriter zygoteOutputWriter = null;
188 final LocalSocket zygoteSessionSocket = new LocalSocket();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400189
190 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800191 zygoteSessionSocket.connect(zygoteSocketAddress);
192 zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
193 zygoteOutputWriter =
194 new BufferedWriter(
195 new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800196 Zygote.SOCKET_BUFFER_SIZE);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400197 } catch (IOException ex) {
198 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800199 zygoteSessionSocket.close();
200 } catch (IOException ignore) { }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400201
202 throw ex;
203 }
204
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800205 return new ZygoteState(zygoteSocketAddress, blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800206 zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
207 getAbiList(zygoteOutputWriter, zygoteInputStream));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400208 }
209
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800210 LocalSocket getBlastulaSessionSocket() throws IOException {
211 final LocalSocket blastulaSessionSocket = new LocalSocket();
212 blastulaSessionSocket.connect(this.mBlastulaSocketAddress);
213
214 return blastulaSessionSocket;
215 }
216
Robert Sesek8f8d1872016-03-18 16:52:57 -0400217 boolean matches(String abi) {
Chris Wailesefce9292019-01-11 13:19:20 -0800218 return mABIList.contains(abi);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400219 }
220
221 public void close() {
222 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800223 mZygoteSessionSocket.close();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400224 } catch (IOException ex) {
225 Log.e(LOG_TAG,"I/O exception on routine close", ex);
226 }
227
228 mClosed = true;
229 }
230
231 boolean isClosed() {
232 return mClosed;
233 }
234 }
235
236 /**
Robert Sesekded20982016-08-15 13:59:13 -0400237 * Lock object to protect access to the two ZygoteStates below. This lock must be
238 * acquired while communicating over the ZygoteState's socket, to prevent
239 * interleaved access.
240 */
241 private final Object mLock = new Object();
242
243 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000244 * List of exemptions to the API blacklist. These are prefix matches on the runtime format
245 * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
246 * list.
247 */
248 private List<String> mApiBlacklistExemptions = Collections.emptyList();
249
250 /**
Mathew Inwood04194fe2018-04-04 14:48:03 +0100251 * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
252 */
253 private int mHiddenApiAccessLogSampleRate;
254
255 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400256 * The state of the connection to the primary zygote.
257 */
258 private ZygoteState primaryZygoteState;
259
260 /**
261 * The state of the connection to the secondary zygote.
262 */
263 private ZygoteState secondaryZygoteState;
264
265 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800266 * If the blastula pool should be created and used to start applications.
267 *
268 * Setting this value to false will disable the creation, maintenance, and use of the blastula
269 * pool. When the blastula pool is disabled the application lifecycle will be identical to
270 * previous versions of Android.
271 */
272 private boolean mBlastulaPoolEnabled = false;
273
274 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400275 * Start a new process.
276 *
277 * <p>If processes are enabled, a new process is created and the
278 * static main() function of a <var>processClass</var> is executed there.
279 * The process will continue running after this function returns.
280 *
281 * <p>If processes are not enabled, a new thread in the caller's
Mathew Inwood8faeab82018-03-16 14:26:08 +0000282 * process is created and main() of <var>processclass</var> called there.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400283 *
284 * <p>The niceName parameter, if not an empty string, is a custom name to
285 * give to the process instead of using processClass. This allows you to
286 * make easily identifyable processes even if you are using the same base
287 * <var>processClass</var> to start them.
288 *
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000289 * When invokeWith is not null, the process will be started as a fresh app
Tamas Berghammer0ca16fa2016-11-11 16:08:26 +0000290 * and not a zygote fork. Note that this is only allowed for uid 0 or when
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100291 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000292 *
Robert Sesek8f8d1872016-03-18 16:52:57 -0400293 * @param processClass The class to use as the process's main entry
294 * point.
295 * @param niceName A more readable name to use for the process.
296 * @param uid The user-id under which the process will run.
297 * @param gid The group-id under which the process will run.
298 * @param gids Additional group-ids associated with the process.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100299 * @param runtimeFlags Additional flags.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400300 * @param targetSdkVersion The target SDK version for the app.
301 * @param seInfo null-ok SELinux information for the new process.
302 * @param abi non-null the ABI this app should be started with.
303 * @param instructionSet null-ok the instruction set to use.
304 * @param appDataDir null-ok the data directory of the app.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000305 * @param invokeWith null-ok the command to invoke with.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700306 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700307 * @param packagesForUid null-ok all the packages with the same uid as this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400308 * @param zygoteArgs Additional arguments to supply to the zygote process.
309 *
310 * @return An object that describes the result of the attempt to start the process.
311 * @throws RuntimeException on fatal start failure
312 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700313 public final Process.ProcessStartResult start(@NonNull final String processClass,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400314 final String niceName,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700315 int uid, int gid, @Nullable int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100316 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400317 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700318 @Nullable String seInfo,
319 @NonNull String abi,
320 @Nullable String instructionSet,
321 @Nullable String appDataDir,
322 @Nullable String invokeWith,
323 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700324 @Nullable String[] packagesForUid,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800325 @Nullable String sandboxId,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800326 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700327 @Nullable String[] zygoteArgs) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800328 // TODO (chriswailes): Is there a better place to check this value?
329 if (fetchBlastulaPoolEnabledPropWithMinInterval()) {
330 informZygotesOfBlastulaPoolStatus();
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800331 }
332
Robert Sesek8f8d1872016-03-18 16:52:57 -0400333 try {
334 return startViaZygote(processClass, niceName, uid, gid, gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100335 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
Chris Wailesefce9292019-01-11 13:19:20 -0800336 abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
Sudheer Shankae51005d2019-02-24 10:24:09 -0800337 packageName, packagesForUid, sandboxId,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800338 useBlastulaPool, zygoteArgs);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400339 } catch (ZygoteStartFailedEx ex) {
340 Log.e(LOG_TAG,
341 "Starting VM process through Zygote failed");
342 throw new RuntimeException(
343 "Starting VM process through Zygote failed", ex);
344 }
345 }
346
347 /** retry interval for opening a zygote socket */
348 static final int ZYGOTE_RETRY_MILLIS = 500;
349
350 /**
351 * Queries the zygote for the list of ABIS it supports.
352 *
353 * @throws ZygoteStartFailedEx if the query failed.
354 */
Robert Sesekded20982016-08-15 13:59:13 -0400355 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800356 private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400357 throws IOException {
358 // Each query starts with the argument count (1 in this case)
359 writer.write("1");
360 // ... followed by a new-line.
361 writer.newLine();
362 // ... followed by our only argument.
363 writer.write("--query-abi-list");
364 writer.newLine();
365 writer.flush();
366
367 // The response is a length prefixed stream of ASCII bytes.
368 int numBytes = inputStream.readInt();
369 byte[] bytes = new byte[numBytes];
370 inputStream.readFully(bytes);
371
Chris Wailesefce9292019-01-11 13:19:20 -0800372 String rawList = new String(bytes, StandardCharsets.US_ASCII);
373
374 return Arrays.asList(rawList.split(","));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400375 }
376
377 /**
378 * Sends an argument list to the zygote process, which starts a new child
379 * and returns the child's pid. Please note: the present implementation
380 * replaces newlines in the argument list with spaces.
381 *
382 * @throws ZygoteStartFailedEx if process start failed for any reason
383 */
Robert Sesekded20982016-08-15 13:59:13 -0400384 @GuardedBy("mLock")
Chris Wailesdb132a32019-02-20 10:49:27 -0800385 private Process.ProcessStartResult zygoteSendArgsAndGetResult(
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800386 ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400387 throws ZygoteStartFailedEx {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800388 // Throw early if any of the arguments are malformed. This means we can
389 // avoid writing a partial response to the zygote.
390 for (String arg : args) {
391 if (arg.indexOf('\n') >= 0) {
392 throw new ZygoteStartFailedEx("embedded newlines not allowed");
393 }
394 }
395
Chris Wailesb13bfc52019-02-20 11:19:48 -0800396 /*
397 * See com.android.internal.os.ZygoteArguments.parseArgs()
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800398 * Presently the wire format to the zygote process is:
399 * a) a count of arguments (argc, in essence)
400 * b) a number of newline-separated argument strings equal to count
401 *
402 * After the zygote process reads these it will write the pid of
403 * the child or -1 on failure, followed by boolean to
404 * indicate whether a wrapper process was used.
405 */
406 String msgStr = Integer.toString(args.size()) + "\n"
407 + String.join("\n", args) + "\n";
408
409 // Should there be a timeout on this?
410 Process.ProcessStartResult result = new Process.ProcessStartResult();
411
412 // TODO (chriswailes): Move branch body into separate function.
Chris Wailesdb132a32019-02-20 10:49:27 -0800413 if (useBlastulaPool && mBlastulaPoolEnabled && isValidBlastulaCommand(args)) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800414 LocalSocket blastulaSessionSocket = null;
415
416 try {
417 blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();
418
419 final BufferedWriter blastulaWriter =
420 new BufferedWriter(
421 new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
422 Zygote.SOCKET_BUFFER_SIZE);
423 final DataInputStream blastulaReader =
424 new DataInputStream(blastulaSessionSocket.getInputStream());
425
426 blastulaWriter.write(msgStr);
427 blastulaWriter.flush();
428
429 result.pid = blastulaReader.readInt();
430 // Blastulas can't be used to spawn processes that need wrappers.
431 result.usingWrapper = false;
432
433 if (result.pid < 0) {
434 throw new ZygoteStartFailedEx("Blastula specialization failed");
435 }
436
437 return result;
438 } catch (IOException ex) {
439 // If there was an IOException using the blastula pool we will log the error and
440 // attempt to start the process through the Zygote.
441 Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
Chris Wailesae937142019-01-24 12:57:33 -0800442 + ex.getMessage());
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800443 } finally {
444 try {
445 blastulaSessionSocket.close();
446 } catch (IOException ex) {
447 Log.e(LOG_TAG, "Failed to close blastula session socket: " + ex.getMessage());
Robert Sesek0b58f192016-10-10 18:34:42 -0400448 }
449 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800450 }
Robert Sesek0b58f192016-10-10 18:34:42 -0400451
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800452 try {
453 final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
454 final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400455
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800456 zygoteWriter.write(msgStr);
457 zygoteWriter.flush();
Robert Sesek0b58f192016-10-10 18:34:42 -0400458
459 // Always read the entire result from the input stream to avoid leaving
460 // bytes in the stream for future process starts to accidentally stumble
461 // upon.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800462 result.pid = zygoteInputStream.readInt();
463 result.usingWrapper = zygoteInputStream.readBoolean();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400464 } catch (IOException ex) {
465 zygoteState.close();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800466 Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
467 + ex.toString());
Robert Sesek8f8d1872016-03-18 16:52:57 -0400468 throw new ZygoteStartFailedEx(ex);
469 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800470
471 if (result.pid < 0) {
472 throw new ZygoteStartFailedEx("fork() failed");
473 }
474
475 return result;
476 }
477
478 /**
479 * Flags that may not be passed to a blastula.
480 */
481 private static final String[] INVALID_BLASTULA_FLAGS = {
482 "--query-abi-list",
483 "--get-pid",
484 "--preload-default",
485 "--preload-package",
486 "--preload-app",
487 "--start-child-zygote",
488 "--set-api-blacklist-exemptions",
489 "--hidden-api-log-sampling-rate",
490 "--invoke-with"
491 };
492
493 /**
494 * Tests a command list to see if it is valid to send to a blastula.
495 * @param args Zygote/Blastula command arguments
496 * @return True if the command can be passed to a blastula; false otherwise
497 */
498 private static boolean isValidBlastulaCommand(ArrayList<String> args) {
499 for (String flag : args) {
500 for (String badFlag : INVALID_BLASTULA_FLAGS) {
501 if (flag.startsWith(badFlag)) {
502 return false;
503 }
504 }
505 }
506
507 return true;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400508 }
509
510 /**
511 * Starts a new process via the zygote mechanism.
512 *
513 * @param processClass Class name whose static main() to run
514 * @param niceName 'nice' process name to appear in ps
515 * @param uid a POSIX uid that the new process should setuid() to
516 * @param gid a POSIX gid that the new process shuold setgid() to
517 * @param gids null-ok; a list of supplementary group IDs that the
518 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100519 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400520 * @param targetSdkVersion The target SDK version for the app.
521 * @param seInfo null-ok SELinux information for the new process.
522 * @param abi the ABI the process should use.
523 * @param instructionSet null-ok the instruction set to use.
524 * @param appDataDir null-ok the data directory of the app.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500525 * @param startChildZygote Start a sub-zygote. This creates a new zygote process
526 * that has its state cloned from this zygote process.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700527 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700528 * @param packagesForUid null-ok all the packages with the same uid as this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400529 * @param extraArgs Additional arguments to supply to the zygote process.
530 * @return An object that describes the result of the attempt to start the process.
531 * @throws ZygoteStartFailedEx if process start failed for any reason
532 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700533 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
534 @Nullable final String niceName,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400535 final int uid, final int gid,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700536 @Nullable final int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100537 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400538 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700539 @Nullable String seInfo,
540 @NonNull String abi,
541 @Nullable String instructionSet,
542 @Nullable String appDataDir,
543 @Nullable String invokeWith,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500544 boolean startChildZygote,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700545 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700546 @Nullable String[] packagesForUid,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800547 @Nullable String sandboxId,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800548 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700549 @Nullable String[] extraArgs)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400550 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400551 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400552
Robert Sesekded20982016-08-15 13:59:13 -0400553 // --runtime-args, --setuid=, --setgid=,
554 // and --setgroups= must go first
555 argsForZygote.add("--runtime-args");
556 argsForZygote.add("--setuid=" + uid);
557 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100558 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400559 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
560 argsForZygote.add("--mount-external-default");
561 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
562 argsForZygote.add("--mount-external-read");
563 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
564 argsForZygote.add("--mount-external-write");
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700565 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
566 argsForZygote.add("--mount-external-full");
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800567 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
568 argsForZygote.add("--mount-external-installer");
Sudheer Shanka0b6da532019-01-09 12:06:51 -0800569 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
570 argsForZygote.add("--mount-external-legacy");
Robert Sesekded20982016-08-15 13:59:13 -0400571 }
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700572
Robert Sesekded20982016-08-15 13:59:13 -0400573 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400574
Robert Sesekded20982016-08-15 13:59:13 -0400575 // --setgroups is a comma-separated list
576 if (gids != null && gids.length > 0) {
577 StringBuilder sb = new StringBuilder();
578 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400579
Robert Sesekded20982016-08-15 13:59:13 -0400580 int sz = gids.length;
581 for (int i = 0; i < sz; i++) {
582 if (i != 0) {
583 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400584 }
Robert Sesekded20982016-08-15 13:59:13 -0400585 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400586 }
587
Robert Sesekded20982016-08-15 13:59:13 -0400588 argsForZygote.add(sb.toString());
589 }
590
591 if (niceName != null) {
592 argsForZygote.add("--nice-name=" + niceName);
593 }
594
595 if (seInfo != null) {
596 argsForZygote.add("--seinfo=" + seInfo);
597 }
598
599 if (instructionSet != null) {
600 argsForZygote.add("--instruction-set=" + instructionSet);
601 }
602
603 if (appDataDir != null) {
604 argsForZygote.add("--app-data-dir=" + appDataDir);
605 }
606
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000607 if (invokeWith != null) {
608 argsForZygote.add("--invoke-with");
609 argsForZygote.add(invokeWith);
610 }
611
Robert Sesekd0a190df2018-02-12 18:46:01 -0500612 if (startChildZygote) {
613 argsForZygote.add("--start-child-zygote");
614 }
615
Sudheer Shanka154fe3f2018-07-30 14:44:26 -0700616 if (packageName != null) {
617 argsForZygote.add("--package-name=" + packageName);
618 }
619
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700620 if (packagesForUid != null && packagesForUid.length > 0) {
621 final StringBuilder sb = new StringBuilder();
622 sb.append("--packages-for-uid=");
623
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800624 // TODO (chriswailes): Replace with String.join
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700625 for (int i = 0; i < packagesForUid.length; ++i) {
626 if (i != 0) {
627 sb.append(',');
628 }
629 sb.append(packagesForUid[i]);
630 }
631 argsForZygote.add(sb.toString());
632 }
633
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800634 if (sandboxId != null) {
635 argsForZygote.add("--sandbox-id=" + sandboxId);
636 }
637
Robert Sesekded20982016-08-15 13:59:13 -0400638 argsForZygote.add(processClass);
639
640 if (extraArgs != null) {
641 for (String arg : extraArgs) {
642 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400643 }
Robert Sesekded20982016-08-15 13:59:13 -0400644 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400645
Robert Sesekded20982016-08-15 13:59:13 -0400646 synchronized(mLock) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800647 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
Chris Wailesdb132a32019-02-20 10:49:27 -0800648 useBlastulaPool,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800649 argsForZygote);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400650 }
651 }
652
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800653 private boolean fetchBlastulaPoolEnabledProp() {
654 boolean origVal = mBlastulaPoolEnabled;
655
656 final String propertyString =
657 Zygote.getSystemProperty(
658 DeviceConfig.RuntimeNative.BLASTULA_POOL_ENABLED,
659 BLASTULA_POOL_ENABLED_DEFAULT);
660
661 if (!propertyString.isEmpty()) {
662 mBlastulaPoolEnabled =
663 Zygote.getSystemPropertyBoolean(
664 DeviceConfig.RuntimeNative.BLASTULA_POOL_ENABLED,
665 Boolean.parseBoolean(BLASTULA_POOL_ENABLED_DEFAULT));
666 }
667
Chris Wailesdb132a32019-02-20 10:49:27 -0800668 if (origVal != mBlastulaPoolEnabled) {
669 Log.i(LOG_TAG, "blastulaPoolEnabled = " + mBlastulaPoolEnabled);
670 }
671
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800672 return origVal != mBlastulaPoolEnabled;
673 }
674
675 private long mLastPropCheckTimestamp = 0;
676
677 private boolean fetchBlastulaPoolEnabledPropWithMinInterval() {
678 final long currentTimestamp = SystemClock.elapsedRealtime();
679
680 if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
681 mLastPropCheckTimestamp = currentTimestamp;
682 return fetchBlastulaPoolEnabledProp();
683 }
684
685 return false;
686 }
687
Robert Sesek8f8d1872016-03-18 16:52:57 -0400688 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500689 * Closes the connections to the zygote, if they exist.
690 */
691 public void close() {
692 if (primaryZygoteState != null) {
693 primaryZygoteState.close();
694 }
695 if (secondaryZygoteState != null) {
696 secondaryZygoteState.close();
697 }
698 }
699
700 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400701 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
702 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
703 * already open.
704 */
705 public void establishZygoteConnectionForAbi(String abi) {
706 try {
Robert Sesekded20982016-08-15 13:59:13 -0400707 synchronized(mLock) {
708 openZygoteSocketIfNeeded(abi);
709 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400710 } catch (ZygoteStartFailedEx ex) {
711 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
712 }
713 }
714
715 /**
Andreas Gampe8444dca2018-05-01 13:31:28 -0700716 * Attempt to retrieve the PID of the zygote serving the given abi.
717 */
718 public int getZygotePid(String abi) {
719 try {
720 synchronized (mLock) {
721 ZygoteState state = openZygoteSocketIfNeeded(abi);
722
723 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800724 state.mZygoteOutputWriter.write("1");
Andreas Gampe8444dca2018-05-01 13:31:28 -0700725 // ... followed by a new-line.
Chris Wailesefce9292019-01-11 13:19:20 -0800726 state.mZygoteOutputWriter.newLine();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700727 // ... followed by our only argument.
Chris Wailesefce9292019-01-11 13:19:20 -0800728 state.mZygoteOutputWriter.write("--get-pid");
729 state.mZygoteOutputWriter.newLine();
730 state.mZygoteOutputWriter.flush();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700731
732 // The response is a length prefixed stream of ASCII bytes.
Chris Wailesefce9292019-01-11 13:19:20 -0800733 int numBytes = state.mZygoteInputStream.readInt();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700734 byte[] bytes = new byte[numBytes];
Chris Wailesefce9292019-01-11 13:19:20 -0800735 state.mZygoteInputStream.readFully(bytes);
Andreas Gampe8444dca2018-05-01 13:31:28 -0700736
737 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
738 }
739 } catch (Exception ex) {
740 throw new RuntimeException("Failure retrieving pid", ex);
741 }
742 }
743
744 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000745 * Push hidden API blacklisting exemptions into the zygote process(es).
746 *
747 * <p>The list of exemptions will take affect for all new processes forked from the zygote after
748 * this call.
749 *
Mathew Inwood33d51382018-04-05 13:56:39 +0100750 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
751 * whitelisted/public APIs (i.e. allowed, no logging of usage).
Mathew Inwood8faeab82018-03-16 14:26:08 +0000752 */
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100753 public boolean setApiBlacklistExemptions(List<String> exemptions) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000754 synchronized (mLock) {
755 mApiBlacklistExemptions = exemptions;
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100756 boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
757 if (ok) {
758 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
759 }
760 return ok;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000761 }
762 }
763
Mathew Inwood04194fe2018-04-04 14:48:03 +0100764 /**
765 * Set the precentage of detected hidden API accesses that are logged to the event log.
766 *
767 * <p>This rate will take affect for all new processes forked from the zygote after this call.
768 *
769 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
770 */
771 public void setHiddenApiAccessLogSampleRate(int rate) {
772 synchronized (mLock) {
773 mHiddenApiAccessLogSampleRate = rate;
774 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
775 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
776 }
777 }
778
Mathew Inwood8faeab82018-03-16 14:26:08 +0000779 @GuardedBy("mLock")
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100780 private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000781 if (state == null || state.isClosed()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100782 Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
783 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000784 }
785 if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100786 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000787 }
788 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800789 state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
790 state.mZygoteOutputWriter.newLine();
791 state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
792 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000793 for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
Chris Wailesefce9292019-01-11 13:19:20 -0800794 state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
795 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000796 }
Chris Wailesefce9292019-01-11 13:19:20 -0800797 state.mZygoteOutputWriter.flush();
798 int status = state.mZygoteInputStream.readInt();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000799 if (status != 0) {
800 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
801 }
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100802 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000803 } catch (IOException ioe) {
804 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100805 mApiBlacklistExemptions = Collections.emptyList();
806 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000807 }
808 }
809
Mathew Inwood04194fe2018-04-04 14:48:03 +0100810 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
811 if (state == null || state.isClosed()) {
812 return;
813 }
814 if (mHiddenApiAccessLogSampleRate == -1) {
815 return;
816 }
817 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800818 state.mZygoteOutputWriter.write(Integer.toString(1));
819 state.mZygoteOutputWriter.newLine();
820 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
Mathew Inwood04194fe2018-04-04 14:48:03 +0100821 + Integer.toString(mHiddenApiAccessLogSampleRate));
Chris Wailesefce9292019-01-11 13:19:20 -0800822 state.mZygoteOutputWriter.newLine();
823 state.mZygoteOutputWriter.flush();
824 int status = state.mZygoteInputStream.readInt();
Mathew Inwood04194fe2018-04-04 14:48:03 +0100825 if (status != 0) {
826 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
827 }
828 } catch (IOException ioe) {
829 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
830 }
831 }
832
Mathew Inwood8faeab82018-03-16 14:26:08 +0000833 /**
Chris Wailesdb132a32019-02-20 10:49:27 -0800834 * Creates a ZygoteState for the primary zygote if it doesn't exist or has been disconnected.
835 */
836 @GuardedBy("mLock")
837 private void attemptConnectionToPrimaryZygote() throws IOException {
838 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
839 primaryZygoteState =
840 ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
841
842 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
843 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
844 }
845 }
846
847 /**
848 * Creates a ZygoteState for the secondary zygote if it doesn't exist or has been disconnected.
849 */
850 @GuardedBy("mLock")
851 private void attemptConnectionToSecondaryZygote() throws IOException {
852 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
853 secondaryZygoteState =
854 ZygoteState.connect(mZygoteSecondarySocketAddress,
855 mBlastulaPoolSecondarySocketAddress);
856
857 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
858 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
859 }
860 }
861
862 /**
Chris Wailesefce9292019-01-11 13:19:20 -0800863 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
864 * already open. If a compatible session socket is already open that session socket is returned.
865 * This function may block and may have to try connecting to multiple Zygotes to find the
866 * appropriate one. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400867 */
Robert Sesekded20982016-08-15 13:59:13 -0400868 @GuardedBy("mLock")
Chris Wailesdb132a32019-02-20 10:49:27 -0800869 private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
870 try {
871 attemptConnectionToPrimaryZygote();
Chris Wailesefce9292019-01-11 13:19:20 -0800872
Chris Wailesdb132a32019-02-20 10:49:27 -0800873 if (primaryZygoteState.matches(abi)) {
874 return primaryZygoteState;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400875 }
Chris Wailesefce9292019-01-11 13:19:20 -0800876
Chris Wailesdb132a32019-02-20 10:49:27 -0800877 // The primary zygote didn't match. Try the secondary.
878 attemptConnectionToSecondaryZygote();
Chris Wailesefce9292019-01-11 13:19:20 -0800879
Chris Wailesdb132a32019-02-20 10:49:27 -0800880 if (secondaryZygoteState.matches(abi)) {
881 return secondaryZygoteState;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400882 }
Chris Wailesdb132a32019-02-20 10:49:27 -0800883 } catch (IOException ioe) {
884 throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400885 }
886
887 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
888 }
Robert Sesekded20982016-08-15 13:59:13 -0400889
890 /**
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100891 * Instructs the zygote to pre-load the application code for the given Application.
892 * Only the app zygote supports this function.
893 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
894 */
895 public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
896 IOException {
897 synchronized (mLock) {
898 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800899 state.mZygoteOutputWriter.write("2");
900 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100901
Chris Wailesefce9292019-01-11 13:19:20 -0800902 state.mZygoteOutputWriter.write("--preload-app");
903 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100904
905 // Zygote args needs to be strings, so in order to pass ApplicationInfo,
906 // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
907 Parcel parcel = Parcel.obtain();
908 appInfo.writeToParcel(parcel, 0 /* flags */);
909 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
910 parcel.recycle();
Chris Wailesefce9292019-01-11 13:19:20 -0800911 state.mZygoteOutputWriter.write(encodedParcelData);
912 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100913
Chris Wailesefce9292019-01-11 13:19:20 -0800914 state.mZygoteOutputWriter.flush();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100915
Chris Wailesefce9292019-01-11 13:19:20 -0800916 return (state.mZygoteInputStream.readInt() == 0);
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100917 }
918 }
919
920 /**
Robert Sesekded20982016-08-15 13:59:13 -0400921 * Instructs the zygote to pre-load the classes and native libraries at the given paths
922 * for the specified abi. Not all zygotes support this function.
923 */
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500924 public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
925 String cacheKey, String abi) throws ZygoteStartFailedEx,
926 IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400927 synchronized(mLock) {
928 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800929 state.mZygoteOutputWriter.write("5");
930 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400931
Chris Wailesefce9292019-01-11 13:19:20 -0800932 state.mZygoteOutputWriter.write("--preload-package");
933 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400934
Chris Wailesefce9292019-01-11 13:19:20 -0800935 state.mZygoteOutputWriter.write(packagePath);
936 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400937
Chris Wailesefce9292019-01-11 13:19:20 -0800938 state.mZygoteOutputWriter.write(libsPath);
939 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400940
Chris Wailesefce9292019-01-11 13:19:20 -0800941 state.mZygoteOutputWriter.write(libFileName);
942 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500943
Chris Wailesefce9292019-01-11 13:19:20 -0800944 state.mZygoteOutputWriter.write(cacheKey);
945 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000946
Chris Wailesefce9292019-01-11 13:19:20 -0800947 state.mZygoteOutputWriter.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100948
Chris Wailesefce9292019-01-11 13:19:20 -0800949 return (state.mZygoteInputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400950 }
951 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000952
953 /**
954 * Instructs the zygote to preload the default set of classes and resources. Returns
955 * {@code true} if a preload was performed as a result of this call, and {@code false}
956 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
957 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
958 */
959 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
960 synchronized (mLock) {
961 ZygoteState state = openZygoteSocketIfNeeded(abi);
962 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800963 state.mZygoteOutputWriter.write("1");
964 state.mZygoteOutputWriter.newLine();
965 state.mZygoteOutputWriter.write("--preload-default");
966 state.mZygoteOutputWriter.newLine();
967 state.mZygoteOutputWriter.flush();
Narayan Kamath669afcc2017-02-06 20:24:08 +0000968
Chris Wailesefce9292019-01-11 13:19:20 -0800969 return (state.mZygoteInputStream.readInt() == 0);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000970 }
971 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100972
973 /**
974 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800975 * @param zygoteSocketName The name of the socket to connect to.
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100976 */
Chris Wailesefce9292019-01-11 13:19:20 -0800977 public static void waitForConnectionToZygote(String zygoteSocketName) {
978 final LocalSocketAddress zygoteSocketAddress =
979 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
980 waitForConnectionToZygote(zygoteSocketAddress);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500981 }
982
983 /**
984 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800985 * @param zygoteSocketAddress The name of the socket to connect to.
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500986 */
Chris Wailesefce9292019-01-11 13:19:20 -0800987 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
Martijn Coenen82dc85a2019-01-28 13:12:28 +0100988 int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS;
989 for (int n = numRetries; n >= 0; n--) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100990 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800991 final ZygoteState zs =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800992 ZygoteState.connect(zygoteSocketAddress, null);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100993 zs.close();
994 return;
995 } catch (IOException ioe) {
996 Log.w(LOG_TAG,
997 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
998 }
999
1000 try {
Martijn Coenen82dc85a2019-01-28 13:12:28 +01001001 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001002 } catch (InterruptedException ie) {
1003 }
1004 }
Chris Wailesefce9292019-01-11 13:19:20 -08001005 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
1006 + zygoteSocketAddress.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001007 }
Robert Sesekd0a190df2018-02-12 18:46:01 -05001008
1009 /**
Chris Wailesdb132a32019-02-20 10:49:27 -08001010 * Sends messages to the zygotes telling them to change the status of their blastula pools. If
1011 * this notification fails the ZygoteProcess will fall back to the previous behavior.
1012 */
1013 private void informZygotesOfBlastulaPoolStatus() {
1014 final String command = "1\n--blastula-pool-enabled=" + mBlastulaPoolEnabled + "\n";
1015
1016 synchronized (mLock) {
1017 try {
1018 attemptConnectionToPrimaryZygote();
1019
1020 primaryZygoteState.mZygoteOutputWriter.write(command);
1021 primaryZygoteState.mZygoteOutputWriter.flush();
1022 } catch (IOException ioe) {
1023 mBlastulaPoolEnabled = !mBlastulaPoolEnabled;
1024 Log.w(LOG_TAG, "Failed to inform zygotes of blastula pool status: "
1025 + ioe.getMessage());
1026 return;
1027 }
1028
1029 try {
1030 attemptConnectionToSecondaryZygote();
1031
1032 try {
1033 secondaryZygoteState.mZygoteOutputWriter.write(command);
1034 secondaryZygoteState.mZygoteOutputWriter.flush();
1035
1036 // Wait for the secondary Zygote to finish its work.
1037 secondaryZygoteState.mZygoteInputStream.readInt();
1038 } catch (IOException ioe) {
1039 throw new IllegalStateException(
1040 "Blastula pool state change cause an irrecoverable error",
1041 ioe);
1042 }
1043 } catch (IOException ioe) {
1044 // No secondary zygote present. This is expected on some devices.
1045 }
1046
1047 // Wait for the response from the primary zygote here so the primary/secondary zygotes
1048 // can work concurrently.
1049 try {
1050 // Wait for the primary zygote to finish its work.
1051 primaryZygoteState.mZygoteInputStream.readInt();
1052 } catch (IOException ioe) {
1053 throw new IllegalStateException(
1054 "Blastula pool state change cause an irrecoverable error",
1055 ioe);
1056 }
1057 }
1058 }
1059
1060 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -05001061 * Starts a new zygote process as a child of this zygote. This is used to create
1062 * secondary zygotes that inherit data from the zygote that this object
1063 * communicates with. This returns a new ZygoteProcess representing a connection
1064 * to the newly created zygote. Throws an exception if the zygote cannot be started.
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001065 *
1066 * @param processClass The class to use as the child zygote's main entry
1067 * point.
1068 * @param niceName A more readable name to use for the process.
1069 * @param uid The user-id under which the child zygote will run.
1070 * @param gid The group-id under which the child zygote will run.
1071 * @param gids Additional group-ids associated with the child zygote process.
1072 * @param runtimeFlags Additional flags.
1073 * @param seInfo null-ok SELinux information for the child zygote process.
1074 * @param abi non-null the ABI of the child zygote
1075 * @param acceptedAbiList ABIs this child zygote will accept connections for; this
1076 * may be different from <code>abi</code> in case the children
1077 * spawned from this Zygote only communicate using ABI-safe methods.
1078 * @param instructionSet null-ok the instruction set to use.
Martijn Coenen86f08a52019-01-03 16:23:01 +01001079 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
1080 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
Robert Sesekd0a190df2018-02-12 18:46:01 -05001081 */
1082 public ChildZygoteProcess startChildZygote(final String processClass,
1083 final String niceName,
1084 int uid, int gid, int[] gids,
1085 int runtimeFlags,
1086 String seInfo,
1087 String abi,
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001088 String acceptedAbiList,
Martijn Coenen86f08a52019-01-03 16:23:01 +01001089 String instructionSet,
1090 int uidRangeStart,
1091 int uidRangeEnd) {
Robert Sesekd0a190df2018-02-12 18:46:01 -05001092 // Create an unguessable address in the global abstract namespace.
1093 final LocalSocketAddress serverAddress = new LocalSocketAddress(
1094 processClass + "/" + UUID.randomUUID().toString());
1095
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001096 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
Martijn Coenen86f08a52019-01-03 16:23:01 +01001097 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
1098 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
1099 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
Robert Sesekd0a190df2018-02-12 18:46:01 -05001100
1101 Process.ProcessStartResult result;
1102 try {
1103 result = startViaZygote(processClass, niceName, uid, gid,
1104 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
1105 abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001106 true /* startChildZygote */, null /* packageName */,
Sudheer Shankae51005d2019-02-24 10:24:09 -08001107 null /* packagesForUid */, null /* sandboxId */,
Chris Wailesba4c2eb2019-01-11 17:13:00 -08001108 false /* useBlastulaPool */, extraArgs);
Robert Sesekd0a190df2018-02-12 18:46:01 -05001109 } catch (ZygoteStartFailedEx ex) {
1110 throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
1111 }
1112
1113 return new ChildZygoteProcess(serverAddress, result.pid);
1114 }
Robert Sesek8f8d1872016-03-18 16:52:57 -04001115}