blob: e94ad2b8989e0e89a375c93968e29d6dcb3114f7 [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;
24import android.util.Log;
Gustav Senntonf0c52b52017-04-27 17:00:50 +010025import android.util.Slog;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010026
Robert Sesekded20982016-08-15 13:59:13 -040027import com.android.internal.annotations.GuardedBy;
Robert Sesek8f8d1872016-03-18 16:52:57 -040028import com.android.internal.os.Zygote;
Robert Sesekded20982016-08-15 13:59:13 -040029import com.android.internal.util.Preconditions;
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 */
69 public static final String ZYGOTE_SOCKET_NAME = "zygote";
70
71 /**
72 * @hide for internal use only.
73 */
74 public static final String ZYGOTE_SECONDARY_SOCKET_NAME = "zygote_secondary";
75
76 /**
Martijn Coenen82dc85a2019-01-28 13:12:28 +010077 * @hide for internal use only.
78 */
79 public static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
80
81 /**
82 * @hide for internal use only.
83 *
84 * Use a relatively short delay, because for app zygote, this is in the critical path of
85 * service launch.
86 */
87 public static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
88
89 /**
Chris Wailesefce9292019-01-11 13:19:20 -080090 * @hide for internal use only
91 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -080092 public static final String BLASTULA_POOL_SOCKET_NAME = "blastula_pool";
93
94 /**
95 * @hide for internal use only
96 */
97 public static final String BLASTULA_POOL_SECONDARY_SOCKET_NAME = "blastula_pool_secondary";
98
99 /**
100 * @hide for internal use only
101 */
Robert Sesek8f8d1872016-03-18 16:52:57 -0400102 private static final String LOG_TAG = "ZygoteProcess";
103
104 /**
105 * The name of the socket used to communicate with the primary zygote.
106 */
Chris Wailesefce9292019-01-11 13:19:20 -0800107 private final LocalSocketAddress mZygoteSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400108
109 /**
110 * The name of the secondary (alternate ABI) zygote socket.
111 */
Chris Wailesefce9292019-01-11 13:19:20 -0800112 private final LocalSocketAddress mZygoteSecondarySocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800113 /**
114 * The name of the socket used to communicate with the primary blastula pool.
115 */
116 private final LocalSocketAddress mBlastulaPoolSocketAddress;
117
118 /**
119 * The name of the socket used to communicate with the secondary (alternate ABI) blastula pool.
120 */
121 private final LocalSocketAddress mBlastulaPoolSecondarySocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400122
Chris Wailesefce9292019-01-11 13:19:20 -0800123 public ZygoteProcess() {
124 mZygoteSocketAddress =
125 new LocalSocketAddress(ZYGOTE_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
126 mZygoteSecondarySocketAddress =
127 new LocalSocketAddress(ZYGOTE_SECONDARY_SOCKET_NAME,
128 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800129
130 mBlastulaPoolSocketAddress =
131 new LocalSocketAddress(BLASTULA_POOL_SOCKET_NAME,
132 LocalSocketAddress.Namespace.RESERVED);
133 mBlastulaPoolSecondarySocketAddress =
134 new LocalSocketAddress(BLASTULA_POOL_SECONDARY_SOCKET_NAME,
135 LocalSocketAddress.Namespace.RESERVED);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500136 }
137
Chris Wailesefce9292019-01-11 13:19:20 -0800138 public ZygoteProcess(LocalSocketAddress primarySocketAddress,
139 LocalSocketAddress secondarySocketAddress) {
140 mZygoteSocketAddress = primarySocketAddress;
141 mZygoteSecondarySocketAddress = secondarySocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800142
143 mBlastulaPoolSocketAddress = null;
144 mBlastulaPoolSecondarySocketAddress = null;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400145 }
146
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500147 public LocalSocketAddress getPrimarySocketAddress() {
Chris Wailesefce9292019-01-11 13:19:20 -0800148 return mZygoteSocketAddress;
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500149 }
150
Robert Sesek8f8d1872016-03-18 16:52:57 -0400151 /**
152 * State for communicating with the zygote process.
153 */
154 public static class ZygoteState {
Chris Wailesefce9292019-01-11 13:19:20 -0800155 final LocalSocketAddress mZygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800156 final LocalSocketAddress mBlastulaSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400157
Chris Wailesefce9292019-01-11 13:19:20 -0800158 private final LocalSocket mZygoteSessionSocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400159
Chris Wailesefce9292019-01-11 13:19:20 -0800160 final DataInputStream mZygoteInputStream;
161 final BufferedWriter mZygoteOutputWriter;
162
163 private final List<String> mABIList;
164
165 private boolean mClosed;
166
167 private ZygoteState(LocalSocketAddress zygoteSocketAddress,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800168 LocalSocketAddress blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800169 LocalSocket zygoteSessionSocket,
170 DataInputStream zygoteInputStream,
171 BufferedWriter zygoteOutputWriter,
172 List<String> abiList) {
173 this.mZygoteSocketAddress = zygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800174 this.mBlastulaSocketAddress = blastulaSocketAddress;
Chris Wailesefce9292019-01-11 13:19:20 -0800175 this.mZygoteSessionSocket = zygoteSessionSocket;
176 this.mZygoteInputStream = zygoteInputStream;
177 this.mZygoteOutputWriter = zygoteOutputWriter;
178 this.mABIList = abiList;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400179 }
180
Chris Wailesefce9292019-01-11 13:19:20 -0800181 /**
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800182 * Create a new ZygoteState object by connecting to the given Zygote socket and saving the
183 * given blastula socket address.
Chris Wailesefce9292019-01-11 13:19:20 -0800184 *
185 * @param zygoteSocketAddress Zygote socket to connect to
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800186 * @param blastulaSocketAddress Blastula socket address to save for later
Chris Wailesefce9292019-01-11 13:19:20 -0800187 * @return A new ZygoteState object containing a session socket for the given Zygote socket
188 * address
189 * @throws IOException
190 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800191 public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress,
192 LocalSocketAddress blastulaSocketAddress)
Chris Wailesefce9292019-01-11 13:19:20 -0800193 throws IOException {
194
Robert Sesek8f8d1872016-03-18 16:52:57 -0400195 DataInputStream zygoteInputStream = null;
Chris Wailesefce9292019-01-11 13:19:20 -0800196 BufferedWriter zygoteOutputWriter = null;
197 final LocalSocket zygoteSessionSocket = new LocalSocket();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400198
199 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800200 zygoteSessionSocket.connect(zygoteSocketAddress);
201 zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
202 zygoteOutputWriter =
203 new BufferedWriter(
204 new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800205 Zygote.SOCKET_BUFFER_SIZE);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400206 } catch (IOException ex) {
207 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800208 zygoteSessionSocket.close();
209 } catch (IOException ignore) { }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400210
211 throw ex;
212 }
213
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800214 return new ZygoteState(zygoteSocketAddress, blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800215 zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
216 getAbiList(zygoteOutputWriter, zygoteInputStream));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400217 }
218
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800219 LocalSocket getBlastulaSessionSocket() throws IOException {
220 final LocalSocket blastulaSessionSocket = new LocalSocket();
221 blastulaSessionSocket.connect(this.mBlastulaSocketAddress);
222
223 return blastulaSessionSocket;
224 }
225
Robert Sesek8f8d1872016-03-18 16:52:57 -0400226 boolean matches(String abi) {
Chris Wailesefce9292019-01-11 13:19:20 -0800227 return mABIList.contains(abi);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400228 }
229
230 public void close() {
231 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800232 mZygoteSessionSocket.close();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400233 } catch (IOException ex) {
234 Log.e(LOG_TAG,"I/O exception on routine close", ex);
235 }
236
237 mClosed = true;
238 }
239
240 boolean isClosed() {
241 return mClosed;
242 }
243 }
244
245 /**
Robert Sesekded20982016-08-15 13:59:13 -0400246 * Lock object to protect access to the two ZygoteStates below. This lock must be
247 * acquired while communicating over the ZygoteState's socket, to prevent
248 * interleaved access.
249 */
250 private final Object mLock = new Object();
251
252 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000253 * List of exemptions to the API blacklist. These are prefix matches on the runtime format
254 * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
255 * list.
256 */
257 private List<String> mApiBlacklistExemptions = Collections.emptyList();
258
259 /**
Mathew Inwood04194fe2018-04-04 14:48:03 +0100260 * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
261 */
262 private int mHiddenApiAccessLogSampleRate;
263
264 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400265 * The state of the connection to the primary zygote.
266 */
267 private ZygoteState primaryZygoteState;
268
269 /**
270 * The state of the connection to the secondary zygote.
271 */
272 private ZygoteState secondaryZygoteState;
273
274 /**
275 * 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.
308 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400309 * @param zygoteArgs Additional arguments to supply to the zygote process.
310 *
311 * @return An object that describes the result of the attempt to start the process.
312 * @throws RuntimeException on fatal start failure
313 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700314 public final Process.ProcessStartResult start(@NonNull final String processClass,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400315 final String niceName,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700316 int uid, int gid, @Nullable int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100317 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400318 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700319 @Nullable String seInfo,
320 @NonNull String abi,
321 @Nullable String instructionSet,
322 @Nullable String appDataDir,
323 @Nullable String invokeWith,
324 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700325 @Nullable String[] packagesForUid,
326 @Nullable String[] visibleVols,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800327 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700328 @Nullable String[] zygoteArgs) {
Robert Sesek8f8d1872016-03-18 16:52:57 -0400329 try {
330 return startViaZygote(processClass, niceName, uid, gid, gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100331 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
Chris Wailesefce9292019-01-11 13:19:20 -0800332 abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800333 packageName, packagesForUid, visibleVols, useBlastulaPool, zygoteArgs);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400334 } catch (ZygoteStartFailedEx ex) {
335 Log.e(LOG_TAG,
336 "Starting VM process through Zygote failed");
337 throw new RuntimeException(
338 "Starting VM process through Zygote failed", ex);
339 }
340 }
341
342 /** retry interval for opening a zygote socket */
343 static final int ZYGOTE_RETRY_MILLIS = 500;
344
345 /**
346 * Queries the zygote for the list of ABIS it supports.
347 *
348 * @throws ZygoteStartFailedEx if the query failed.
349 */
Robert Sesekded20982016-08-15 13:59:13 -0400350 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800351 private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400352 throws IOException {
353 // Each query starts with the argument count (1 in this case)
354 writer.write("1");
355 // ... followed by a new-line.
356 writer.newLine();
357 // ... followed by our only argument.
358 writer.write("--query-abi-list");
359 writer.newLine();
360 writer.flush();
361
362 // The response is a length prefixed stream of ASCII bytes.
363 int numBytes = inputStream.readInt();
364 byte[] bytes = new byte[numBytes];
365 inputStream.readFully(bytes);
366
Chris Wailesefce9292019-01-11 13:19:20 -0800367 String rawList = new String(bytes, StandardCharsets.US_ASCII);
368
369 return Arrays.asList(rawList.split(","));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400370 }
371
372 /**
373 * Sends an argument list to the zygote process, which starts a new child
374 * and returns the child's pid. Please note: the present implementation
375 * replaces newlines in the argument list with spaces.
376 *
377 * @throws ZygoteStartFailedEx if process start failed for any reason
378 */
Robert Sesekded20982016-08-15 13:59:13 -0400379 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400380 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800381 ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400382 throws ZygoteStartFailedEx {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800383 // Throw early if any of the arguments are malformed. This means we can
384 // avoid writing a partial response to the zygote.
385 for (String arg : args) {
386 if (arg.indexOf('\n') >= 0) {
387 throw new ZygoteStartFailedEx("embedded newlines not allowed");
388 }
389 }
390
391 /**
392 * See com.android.internal.os.SystemZygoteInit.readArgumentList()
393 * Presently the wire format to the zygote process is:
394 * a) a count of arguments (argc, in essence)
395 * b) a number of newline-separated argument strings equal to count
396 *
397 * After the zygote process reads these it will write the pid of
398 * the child or -1 on failure, followed by boolean to
399 * indicate whether a wrapper process was used.
400 */
401 String msgStr = Integer.toString(args.size()) + "\n"
402 + String.join("\n", args) + "\n";
403
404 // Should there be a timeout on this?
405 Process.ProcessStartResult result = new Process.ProcessStartResult();
406
407 // TODO (chriswailes): Move branch body into separate function.
408 if (useBlastulaPool && Zygote.BLASTULA_POOL_ENABLED && isValidBlastulaCommand(args)) {
409 LocalSocket blastulaSessionSocket = null;
410
411 try {
412 blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();
413
414 final BufferedWriter blastulaWriter =
415 new BufferedWriter(
416 new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
417 Zygote.SOCKET_BUFFER_SIZE);
418 final DataInputStream blastulaReader =
419 new DataInputStream(blastulaSessionSocket.getInputStream());
420
421 blastulaWriter.write(msgStr);
422 blastulaWriter.flush();
423
424 result.pid = blastulaReader.readInt();
425 // Blastulas can't be used to spawn processes that need wrappers.
426 result.usingWrapper = false;
427
428 if (result.pid < 0) {
429 throw new ZygoteStartFailedEx("Blastula specialization failed");
430 }
431
432 return result;
433 } catch (IOException ex) {
434 // If there was an IOException using the blastula pool we will log the error and
435 // attempt to start the process through the Zygote.
436 Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
437 + ex.toString());
438 } finally {
439 try {
440 blastulaSessionSocket.close();
441 } catch (IOException ex) {
442 Log.e(LOG_TAG, "Failed to close blastula session socket: " + ex.getMessage());
Robert Sesek0b58f192016-10-10 18:34:42 -0400443 }
444 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800445 }
Robert Sesek0b58f192016-10-10 18:34:42 -0400446
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800447 try {
448 final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
449 final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400450
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800451 zygoteWriter.write(msgStr);
452 zygoteWriter.flush();
Robert Sesek0b58f192016-10-10 18:34:42 -0400453
454 // Always read the entire result from the input stream to avoid leaving
455 // bytes in the stream for future process starts to accidentally stumble
456 // upon.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800457 result.pid = zygoteInputStream.readInt();
458 result.usingWrapper = zygoteInputStream.readBoolean();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400459 } catch (IOException ex) {
460 zygoteState.close();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800461 Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
462 + ex.toString());
Robert Sesek8f8d1872016-03-18 16:52:57 -0400463 throw new ZygoteStartFailedEx(ex);
464 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800465
466 if (result.pid < 0) {
467 throw new ZygoteStartFailedEx("fork() failed");
468 }
469
470 return result;
471 }
472
473 /**
474 * Flags that may not be passed to a blastula.
475 */
476 private static final String[] INVALID_BLASTULA_FLAGS = {
477 "--query-abi-list",
478 "--get-pid",
479 "--preload-default",
480 "--preload-package",
481 "--preload-app",
482 "--start-child-zygote",
483 "--set-api-blacklist-exemptions",
484 "--hidden-api-log-sampling-rate",
485 "--invoke-with"
486 };
487
488 /**
489 * Tests a command list to see if it is valid to send to a blastula.
490 * @param args Zygote/Blastula command arguments
491 * @return True if the command can be passed to a blastula; false otherwise
492 */
493 private static boolean isValidBlastulaCommand(ArrayList<String> args) {
494 for (String flag : args) {
495 for (String badFlag : INVALID_BLASTULA_FLAGS) {
496 if (flag.startsWith(badFlag)) {
497 return false;
498 }
499 }
500 }
501
502 return true;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400503 }
504
505 /**
506 * Starts a new process via the zygote mechanism.
507 *
508 * @param processClass Class name whose static main() to run
509 * @param niceName 'nice' process name to appear in ps
510 * @param uid a POSIX uid that the new process should setuid() to
511 * @param gid a POSIX gid that the new process shuold setgid() to
512 * @param gids null-ok; a list of supplementary group IDs that the
513 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100514 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400515 * @param targetSdkVersion The target SDK version for the app.
516 * @param seInfo null-ok SELinux information for the new process.
517 * @param abi the ABI the process should use.
518 * @param instructionSet null-ok the instruction set to use.
519 * @param appDataDir null-ok the data directory of the app.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500520 * @param startChildZygote Start a sub-zygote. This creates a new zygote process
521 * that has its state cloned from this zygote process.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700522 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700523 * @param packagesForUid null-ok all the packages with the same uid as this process.
524 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400525 * @param extraArgs Additional arguments to supply to the zygote process.
526 * @return An object that describes the result of the attempt to start the process.
527 * @throws ZygoteStartFailedEx if process start failed for any reason
528 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700529 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
530 @Nullable final String niceName,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400531 final int uid, final int gid,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700532 @Nullable final int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100533 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400534 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700535 @Nullable String seInfo,
536 @NonNull String abi,
537 @Nullable String instructionSet,
538 @Nullable String appDataDir,
539 @Nullable String invokeWith,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500540 boolean startChildZygote,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700541 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700542 @Nullable String[] packagesForUid,
543 @Nullable String[] visibleVols,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800544 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700545 @Nullable String[] extraArgs)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400546 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400547 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400548
Robert Sesekded20982016-08-15 13:59:13 -0400549 // --runtime-args, --setuid=, --setgid=,
550 // and --setgroups= must go first
551 argsForZygote.add("--runtime-args");
552 argsForZygote.add("--setuid=" + uid);
553 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100554 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400555 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
556 argsForZygote.add("--mount-external-default");
557 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
558 argsForZygote.add("--mount-external-read");
559 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
560 argsForZygote.add("--mount-external-write");
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700561 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
562 argsForZygote.add("--mount-external-full");
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800563 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
564 argsForZygote.add("--mount-external-installer");
Sudheer Shanka0b6da532019-01-09 12:06:51 -0800565 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
566 argsForZygote.add("--mount-external-legacy");
Robert Sesekded20982016-08-15 13:59:13 -0400567 }
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700568
Robert Sesekded20982016-08-15 13:59:13 -0400569 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400570
Robert Sesekded20982016-08-15 13:59:13 -0400571 // --setgroups is a comma-separated list
572 if (gids != null && gids.length > 0) {
573 StringBuilder sb = new StringBuilder();
574 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400575
Robert Sesekded20982016-08-15 13:59:13 -0400576 int sz = gids.length;
577 for (int i = 0; i < sz; i++) {
578 if (i != 0) {
579 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400580 }
Robert Sesekded20982016-08-15 13:59:13 -0400581 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400582 }
583
Robert Sesekded20982016-08-15 13:59:13 -0400584 argsForZygote.add(sb.toString());
585 }
586
587 if (niceName != null) {
588 argsForZygote.add("--nice-name=" + niceName);
589 }
590
591 if (seInfo != null) {
592 argsForZygote.add("--seinfo=" + seInfo);
593 }
594
595 if (instructionSet != null) {
596 argsForZygote.add("--instruction-set=" + instructionSet);
597 }
598
599 if (appDataDir != null) {
600 argsForZygote.add("--app-data-dir=" + appDataDir);
601 }
602
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000603 if (invokeWith != null) {
604 argsForZygote.add("--invoke-with");
605 argsForZygote.add(invokeWith);
606 }
607
Robert Sesekd0a190df2018-02-12 18:46:01 -0500608 if (startChildZygote) {
609 argsForZygote.add("--start-child-zygote");
610 }
611
Sudheer Shanka154fe3f2018-07-30 14:44:26 -0700612 if (packageName != null) {
613 argsForZygote.add("--package-name=" + packageName);
614 }
615
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700616 if (packagesForUid != null && packagesForUid.length > 0) {
617 final StringBuilder sb = new StringBuilder();
618 sb.append("--packages-for-uid=");
619
620 for (int i = 0; i < packagesForUid.length; ++i) {
621 if (i != 0) {
622 sb.append(',');
623 }
624 sb.append(packagesForUid[i]);
625 }
626 argsForZygote.add(sb.toString());
627 }
628
629 if (visibleVols != null && visibleVols.length > 0) {
630 final StringBuilder sb = new StringBuilder();
631 sb.append("--visible-vols=");
632
633 for (int i = 0; i < visibleVols.length; ++i) {
634 if (i != 0) {
635 sb.append(',');
636 }
637 sb.append(visibleVols[i]);
638 }
639 argsForZygote.add(sb.toString());
640 }
641
Robert Sesekded20982016-08-15 13:59:13 -0400642 argsForZygote.add(processClass);
643
644 if (extraArgs != null) {
645 for (String arg : extraArgs) {
646 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400647 }
Robert Sesekded20982016-08-15 13:59:13 -0400648 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400649
Robert Sesekded20982016-08-15 13:59:13 -0400650 synchronized(mLock) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800651 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
652 useBlastulaPool,
653 argsForZygote);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400654 }
655 }
656
657 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500658 * Closes the connections to the zygote, if they exist.
659 */
660 public void close() {
661 if (primaryZygoteState != null) {
662 primaryZygoteState.close();
663 }
664 if (secondaryZygoteState != null) {
665 secondaryZygoteState.close();
666 }
667 }
668
669 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400670 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
671 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
672 * already open.
673 */
674 public void establishZygoteConnectionForAbi(String abi) {
675 try {
Robert Sesekded20982016-08-15 13:59:13 -0400676 synchronized(mLock) {
677 openZygoteSocketIfNeeded(abi);
678 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400679 } catch (ZygoteStartFailedEx ex) {
680 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
681 }
682 }
683
684 /**
Andreas Gampe8444dca2018-05-01 13:31:28 -0700685 * Attempt to retrieve the PID of the zygote serving the given abi.
686 */
687 public int getZygotePid(String abi) {
688 try {
689 synchronized (mLock) {
690 ZygoteState state = openZygoteSocketIfNeeded(abi);
691
692 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800693 state.mZygoteOutputWriter.write("1");
Andreas Gampe8444dca2018-05-01 13:31:28 -0700694 // ... followed by a new-line.
Chris Wailesefce9292019-01-11 13:19:20 -0800695 state.mZygoteOutputWriter.newLine();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700696 // ... followed by our only argument.
Chris Wailesefce9292019-01-11 13:19:20 -0800697 state.mZygoteOutputWriter.write("--get-pid");
698 state.mZygoteOutputWriter.newLine();
699 state.mZygoteOutputWriter.flush();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700700
701 // The response is a length prefixed stream of ASCII bytes.
Chris Wailesefce9292019-01-11 13:19:20 -0800702 int numBytes = state.mZygoteInputStream.readInt();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700703 byte[] bytes = new byte[numBytes];
Chris Wailesefce9292019-01-11 13:19:20 -0800704 state.mZygoteInputStream.readFully(bytes);
Andreas Gampe8444dca2018-05-01 13:31:28 -0700705
706 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
707 }
708 } catch (Exception ex) {
709 throw new RuntimeException("Failure retrieving pid", ex);
710 }
711 }
712
713 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000714 * Push hidden API blacklisting exemptions into the zygote process(es).
715 *
716 * <p>The list of exemptions will take affect for all new processes forked from the zygote after
717 * this call.
718 *
Mathew Inwood33d51382018-04-05 13:56:39 +0100719 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
720 * whitelisted/public APIs (i.e. allowed, no logging of usage).
Mathew Inwood8faeab82018-03-16 14:26:08 +0000721 */
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100722 public boolean setApiBlacklistExemptions(List<String> exemptions) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000723 synchronized (mLock) {
724 mApiBlacklistExemptions = exemptions;
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100725 boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
726 if (ok) {
727 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
728 }
729 return ok;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000730 }
731 }
732
Mathew Inwood04194fe2018-04-04 14:48:03 +0100733 /**
734 * Set the precentage of detected hidden API accesses that are logged to the event log.
735 *
736 * <p>This rate will take affect for all new processes forked from the zygote after this call.
737 *
738 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
739 */
740 public void setHiddenApiAccessLogSampleRate(int rate) {
741 synchronized (mLock) {
742 mHiddenApiAccessLogSampleRate = rate;
743 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
744 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
745 }
746 }
747
Mathew Inwood8faeab82018-03-16 14:26:08 +0000748 @GuardedBy("mLock")
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100749 private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000750 if (state == null || state.isClosed()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100751 Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
752 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000753 }
754 if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100755 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000756 }
757 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800758 state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
759 state.mZygoteOutputWriter.newLine();
760 state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
761 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000762 for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
Chris Wailesefce9292019-01-11 13:19:20 -0800763 state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
764 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000765 }
Chris Wailesefce9292019-01-11 13:19:20 -0800766 state.mZygoteOutputWriter.flush();
767 int status = state.mZygoteInputStream.readInt();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000768 if (status != 0) {
769 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
770 }
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100771 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000772 } catch (IOException ioe) {
773 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100774 mApiBlacklistExemptions = Collections.emptyList();
775 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000776 }
777 }
778
Mathew Inwood04194fe2018-04-04 14:48:03 +0100779 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
780 if (state == null || state.isClosed()) {
781 return;
782 }
783 if (mHiddenApiAccessLogSampleRate == -1) {
784 return;
785 }
786 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800787 state.mZygoteOutputWriter.write(Integer.toString(1));
788 state.mZygoteOutputWriter.newLine();
789 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
Mathew Inwood04194fe2018-04-04 14:48:03 +0100790 + Integer.toString(mHiddenApiAccessLogSampleRate));
Chris Wailesefce9292019-01-11 13:19:20 -0800791 state.mZygoteOutputWriter.newLine();
792 state.mZygoteOutputWriter.flush();
793 int status = state.mZygoteInputStream.readInt();
Mathew Inwood04194fe2018-04-04 14:48:03 +0100794 if (status != 0) {
795 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
796 }
797 } catch (IOException ioe) {
798 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
799 }
800 }
801
Mathew Inwood8faeab82018-03-16 14:26:08 +0000802 /**
Chris Wailesefce9292019-01-11 13:19:20 -0800803 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
804 * already open. If a compatible session socket is already open that session socket is returned.
805 * This function may block and may have to try connecting to multiple Zygotes to find the
806 * appropriate one. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400807 */
Robert Sesekded20982016-08-15 13:59:13 -0400808 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800809 private ZygoteState openZygoteSocketIfNeeded(String abi)
810 throws ZygoteStartFailedEx {
811
Robert Sesekded20982016-08-15 13:59:13 -0400812 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
813
Robert Sesek8f8d1872016-03-18 16:52:57 -0400814 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
815 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800816 primaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800817 ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400818 } catch (IOException ioe) {
819 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
820 }
Chris Wailesefce9292019-01-11 13:19:20 -0800821
Mathew Inwood8faeab82018-03-16 14:26:08 +0000822 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100823 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400824 }
Chris Wailesefce9292019-01-11 13:19:20 -0800825
Robert Sesek8f8d1872016-03-18 16:52:57 -0400826 if (primaryZygoteState.matches(abi)) {
827 return primaryZygoteState;
828 }
829
830 // The primary zygote didn't match. Try the secondary.
831 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
832 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800833 secondaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800834 ZygoteState.connect(mZygoteSecondarySocketAddress,
835 mBlastulaPoolSecondarySocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400836 } catch (IOException ioe) {
837 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
838 }
Chris Wailesefce9292019-01-11 13:19:20 -0800839
Mathew Inwood8faeab82018-03-16 14:26:08 +0000840 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100841 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400842 }
843
844 if (secondaryZygoteState.matches(abi)) {
845 return secondaryZygoteState;
846 }
847
848 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
849 }
Robert Sesekded20982016-08-15 13:59:13 -0400850
851 /**
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100852 * Instructs the zygote to pre-load the application code for the given Application.
853 * Only the app zygote supports this function.
854 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
855 */
856 public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
857 IOException {
858 synchronized (mLock) {
859 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800860 state.mZygoteOutputWriter.write("2");
861 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100862
Chris Wailesefce9292019-01-11 13:19:20 -0800863 state.mZygoteOutputWriter.write("--preload-app");
864 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100865
866 // Zygote args needs to be strings, so in order to pass ApplicationInfo,
867 // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
868 Parcel parcel = Parcel.obtain();
869 appInfo.writeToParcel(parcel, 0 /* flags */);
870 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
871 parcel.recycle();
Chris Wailesefce9292019-01-11 13:19:20 -0800872 state.mZygoteOutputWriter.write(encodedParcelData);
873 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100874
Chris Wailesefce9292019-01-11 13:19:20 -0800875 state.mZygoteOutputWriter.flush();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100876
Chris Wailesefce9292019-01-11 13:19:20 -0800877 return (state.mZygoteInputStream.readInt() == 0);
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100878 }
879 }
880
881 /**
Robert Sesekded20982016-08-15 13:59:13 -0400882 * Instructs the zygote to pre-load the classes and native libraries at the given paths
883 * for the specified abi. Not all zygotes support this function.
884 */
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500885 public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
886 String cacheKey, String abi) throws ZygoteStartFailedEx,
887 IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400888 synchronized(mLock) {
889 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800890 state.mZygoteOutputWriter.write("5");
891 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400892
Chris Wailesefce9292019-01-11 13:19:20 -0800893 state.mZygoteOutputWriter.write("--preload-package");
894 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400895
Chris Wailesefce9292019-01-11 13:19:20 -0800896 state.mZygoteOutputWriter.write(packagePath);
897 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400898
Chris Wailesefce9292019-01-11 13:19:20 -0800899 state.mZygoteOutputWriter.write(libsPath);
900 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400901
Chris Wailesefce9292019-01-11 13:19:20 -0800902 state.mZygoteOutputWriter.write(libFileName);
903 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500904
Chris Wailesefce9292019-01-11 13:19:20 -0800905 state.mZygoteOutputWriter.write(cacheKey);
906 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000907
Chris Wailesefce9292019-01-11 13:19:20 -0800908 state.mZygoteOutputWriter.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100909
Chris Wailesefce9292019-01-11 13:19:20 -0800910 return (state.mZygoteInputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400911 }
912 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000913
914 /**
915 * Instructs the zygote to preload the default set of classes and resources. Returns
916 * {@code true} if a preload was performed as a result of this call, and {@code false}
917 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
918 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
919 */
920 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
921 synchronized (mLock) {
922 ZygoteState state = openZygoteSocketIfNeeded(abi);
923 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800924 state.mZygoteOutputWriter.write("1");
925 state.mZygoteOutputWriter.newLine();
926 state.mZygoteOutputWriter.write("--preload-default");
927 state.mZygoteOutputWriter.newLine();
928 state.mZygoteOutputWriter.flush();
Narayan Kamath669afcc2017-02-06 20:24:08 +0000929
Chris Wailesefce9292019-01-11 13:19:20 -0800930 return (state.mZygoteInputStream.readInt() == 0);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000931 }
932 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100933
934 /**
935 * Try connecting to the Zygote over and over again until we hit a time-out.
936 * @param socketName The name of the socket to connect to.
937 */
Chris Wailesefce9292019-01-11 13:19:20 -0800938 public static void waitForConnectionToZygote(String zygoteSocketName) {
939 final LocalSocketAddress zygoteSocketAddress =
940 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
941 waitForConnectionToZygote(zygoteSocketAddress);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500942 }
943
944 /**
945 * Try connecting to the Zygote over and over again until we hit a time-out.
946 * @param address The name of the socket to connect to.
947 */
Chris Wailesefce9292019-01-11 13:19:20 -0800948 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
Martijn Coenen82dc85a2019-01-28 13:12:28 +0100949 int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS;
950 for (int n = numRetries; n >= 0; n--) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100951 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800952 final ZygoteState zs =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800953 ZygoteState.connect(zygoteSocketAddress, null);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100954 zs.close();
955 return;
956 } catch (IOException ioe) {
957 Log.w(LOG_TAG,
958 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
959 }
960
961 try {
Martijn Coenen82dc85a2019-01-28 13:12:28 +0100962 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100963 } catch (InterruptedException ie) {
964 }
965 }
Chris Wailesefce9292019-01-11 13:19:20 -0800966 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
967 + zygoteSocketAddress.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100968 }
Robert Sesekd0a190df2018-02-12 18:46:01 -0500969
970 /**
971 * Starts a new zygote process as a child of this zygote. This is used to create
972 * secondary zygotes that inherit data from the zygote that this object
973 * communicates with. This returns a new ZygoteProcess representing a connection
974 * to the newly created zygote. Throws an exception if the zygote cannot be started.
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100975 *
976 * @param processClass The class to use as the child zygote's main entry
977 * point.
978 * @param niceName A more readable name to use for the process.
979 * @param uid The user-id under which the child zygote will run.
980 * @param gid The group-id under which the child zygote will run.
981 * @param gids Additional group-ids associated with the child zygote process.
982 * @param runtimeFlags Additional flags.
983 * @param seInfo null-ok SELinux information for the child zygote process.
984 * @param abi non-null the ABI of the child zygote
985 * @param acceptedAbiList ABIs this child zygote will accept connections for; this
986 * may be different from <code>abi</code> in case the children
987 * spawned from this Zygote only communicate using ABI-safe methods.
988 * @param instructionSet null-ok the instruction set to use.
Martijn Coenen86f08a52019-01-03 16:23:01 +0100989 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
990 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
Robert Sesekd0a190df2018-02-12 18:46:01 -0500991 */
992 public ChildZygoteProcess startChildZygote(final String processClass,
993 final String niceName,
994 int uid, int gid, int[] gids,
995 int runtimeFlags,
996 String seInfo,
997 String abi,
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100998 String acceptedAbiList,
Martijn Coenen86f08a52019-01-03 16:23:01 +0100999 String instructionSet,
1000 int uidRangeStart,
1001 int uidRangeEnd) {
Robert Sesekd0a190df2018-02-12 18:46:01 -05001002 // Create an unguessable address in the global abstract namespace.
1003 final LocalSocketAddress serverAddress = new LocalSocketAddress(
1004 processClass + "/" + UUID.randomUUID().toString());
1005
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001006 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
Martijn Coenen86f08a52019-01-03 16:23:01 +01001007 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
1008 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
1009 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
Robert Sesekd0a190df2018-02-12 18:46:01 -05001010
1011 Process.ProcessStartResult result;
1012 try {
1013 result = startViaZygote(processClass, niceName, uid, gid,
1014 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
1015 abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001016 true /* startChildZygote */, null /* packageName */,
Chris Wailesba4c2eb2019-01-11 17:13:00 -08001017 null /* packagesForUid */, null /* visibleVolumes */,
1018 false /* useBlastulaPool */, extraArgs);
Robert Sesekd0a190df2018-02-12 18:46:01 -05001019 } catch (ZygoteStartFailedEx ex) {
1020 throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
1021 }
1022
1023 return new ChildZygoteProcess(serverAddress, result.pid);
1024 }
Robert Sesek8f8d1872016-03-18 16:52:57 -04001025}