blob: 9e47179e9152d88376f534c3f724f6362e0b3393 [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 /**
77 * @hide for internal use only
78 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -080079 public static final String BLASTULA_POOL_SOCKET_NAME = "blastula_pool";
80
81 /**
82 * @hide for internal use only
83 */
84 public static final String BLASTULA_POOL_SECONDARY_SOCKET_NAME = "blastula_pool_secondary";
85
86 /**
87 * @hide for internal use only
88 */
Robert Sesek8f8d1872016-03-18 16:52:57 -040089 private static final String LOG_TAG = "ZygoteProcess";
90
91 /**
92 * The name of the socket used to communicate with the primary zygote.
93 */
Chris Wailesefce9292019-01-11 13:19:20 -080094 private final LocalSocketAddress mZygoteSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -040095
96 /**
97 * The name of the secondary (alternate ABI) zygote socket.
98 */
Chris Wailesefce9292019-01-11 13:19:20 -080099 private final LocalSocketAddress mZygoteSecondarySocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800100 /**
101 * The name of the socket used to communicate with the primary blastula pool.
102 */
103 private final LocalSocketAddress mBlastulaPoolSocketAddress;
104
105 /**
106 * The name of the socket used to communicate with the secondary (alternate ABI) blastula pool.
107 */
108 private final LocalSocketAddress mBlastulaPoolSecondarySocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400109
Chris Wailesefce9292019-01-11 13:19:20 -0800110 public ZygoteProcess() {
111 mZygoteSocketAddress =
112 new LocalSocketAddress(ZYGOTE_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
113 mZygoteSecondarySocketAddress =
114 new LocalSocketAddress(ZYGOTE_SECONDARY_SOCKET_NAME,
115 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800116
117 mBlastulaPoolSocketAddress =
118 new LocalSocketAddress(BLASTULA_POOL_SOCKET_NAME,
119 LocalSocketAddress.Namespace.RESERVED);
120 mBlastulaPoolSecondarySocketAddress =
121 new LocalSocketAddress(BLASTULA_POOL_SECONDARY_SOCKET_NAME,
122 LocalSocketAddress.Namespace.RESERVED);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500123 }
124
Chris Wailesefce9292019-01-11 13:19:20 -0800125 public ZygoteProcess(LocalSocketAddress primarySocketAddress,
126 LocalSocketAddress secondarySocketAddress) {
127 mZygoteSocketAddress = primarySocketAddress;
128 mZygoteSecondarySocketAddress = secondarySocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800129
130 mBlastulaPoolSocketAddress = null;
131 mBlastulaPoolSecondarySocketAddress = null;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400132 }
133
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500134 public LocalSocketAddress getPrimarySocketAddress() {
Chris Wailesefce9292019-01-11 13:19:20 -0800135 return mZygoteSocketAddress;
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500136 }
137
Robert Sesek8f8d1872016-03-18 16:52:57 -0400138 /**
139 * State for communicating with the zygote process.
140 */
141 public static class ZygoteState {
Chris Wailesefce9292019-01-11 13:19:20 -0800142 final LocalSocketAddress mZygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800143 final LocalSocketAddress mBlastulaSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400144
Chris Wailesefce9292019-01-11 13:19:20 -0800145 private final LocalSocket mZygoteSessionSocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400146
Chris Wailesefce9292019-01-11 13:19:20 -0800147 final DataInputStream mZygoteInputStream;
148 final BufferedWriter mZygoteOutputWriter;
149
150 private final List<String> mABIList;
151
152 private boolean mClosed;
153
154 private ZygoteState(LocalSocketAddress zygoteSocketAddress,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800155 LocalSocketAddress blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800156 LocalSocket zygoteSessionSocket,
157 DataInputStream zygoteInputStream,
158 BufferedWriter zygoteOutputWriter,
159 List<String> abiList) {
160 this.mZygoteSocketAddress = zygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800161 this.mBlastulaSocketAddress = blastulaSocketAddress;
Chris Wailesefce9292019-01-11 13:19:20 -0800162 this.mZygoteSessionSocket = zygoteSessionSocket;
163 this.mZygoteInputStream = zygoteInputStream;
164 this.mZygoteOutputWriter = zygoteOutputWriter;
165 this.mABIList = abiList;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400166 }
167
Chris Wailesefce9292019-01-11 13:19:20 -0800168 /**
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800169 * Create a new ZygoteState object by connecting to the given Zygote socket and saving the
170 * given blastula socket address.
Chris Wailesefce9292019-01-11 13:19:20 -0800171 *
172 * @param zygoteSocketAddress Zygote socket to connect to
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800173 * @param blastulaSocketAddress Blastula socket address to save for later
Chris Wailesefce9292019-01-11 13:19:20 -0800174 * @return A new ZygoteState object containing a session socket for the given Zygote socket
175 * address
176 * @throws IOException
177 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800178 public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress,
179 LocalSocketAddress blastulaSocketAddress)
Chris Wailesefce9292019-01-11 13:19:20 -0800180 throws IOException {
181
Robert Sesek8f8d1872016-03-18 16:52:57 -0400182 DataInputStream zygoteInputStream = null;
Chris Wailesefce9292019-01-11 13:19:20 -0800183 BufferedWriter zygoteOutputWriter = null;
184 final LocalSocket zygoteSessionSocket = new LocalSocket();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400185
186 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800187 zygoteSessionSocket.connect(zygoteSocketAddress);
188 zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
189 zygoteOutputWriter =
190 new BufferedWriter(
191 new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800192 Zygote.SOCKET_BUFFER_SIZE);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400193 } catch (IOException ex) {
194 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800195 zygoteSessionSocket.close();
196 } catch (IOException ignore) { }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400197
198 throw ex;
199 }
200
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800201 return new ZygoteState(zygoteSocketAddress, blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800202 zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
203 getAbiList(zygoteOutputWriter, zygoteInputStream));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400204 }
205
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800206 LocalSocket getBlastulaSessionSocket() throws IOException {
207 final LocalSocket blastulaSessionSocket = new LocalSocket();
208 blastulaSessionSocket.connect(this.mBlastulaSocketAddress);
209
210 return blastulaSessionSocket;
211 }
212
Robert Sesek8f8d1872016-03-18 16:52:57 -0400213 boolean matches(String abi) {
Chris Wailesefce9292019-01-11 13:19:20 -0800214 return mABIList.contains(abi);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400215 }
216
217 public void close() {
218 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800219 mZygoteSessionSocket.close();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400220 } catch (IOException ex) {
221 Log.e(LOG_TAG,"I/O exception on routine close", ex);
222 }
223
224 mClosed = true;
225 }
226
227 boolean isClosed() {
228 return mClosed;
229 }
230 }
231
232 /**
Robert Sesekded20982016-08-15 13:59:13 -0400233 * Lock object to protect access to the two ZygoteStates below. This lock must be
234 * acquired while communicating over the ZygoteState's socket, to prevent
235 * interleaved access.
236 */
237 private final Object mLock = new Object();
238
239 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000240 * List of exemptions to the API blacklist. These are prefix matches on the runtime format
241 * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
242 * list.
243 */
244 private List<String> mApiBlacklistExemptions = Collections.emptyList();
245
246 /**
Mathew Inwood04194fe2018-04-04 14:48:03 +0100247 * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
248 */
249 private int mHiddenApiAccessLogSampleRate;
250
251 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400252 * The state of the connection to the primary zygote.
253 */
254 private ZygoteState primaryZygoteState;
255
256 /**
257 * The state of the connection to the secondary zygote.
258 */
259 private ZygoteState secondaryZygoteState;
260
261 /**
262 * Start a new process.
263 *
264 * <p>If processes are enabled, a new process is created and the
265 * static main() function of a <var>processClass</var> is executed there.
266 * The process will continue running after this function returns.
267 *
268 * <p>If processes are not enabled, a new thread in the caller's
Mathew Inwood8faeab82018-03-16 14:26:08 +0000269 * process is created and main() of <var>processclass</var> called there.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400270 *
271 * <p>The niceName parameter, if not an empty string, is a custom name to
272 * give to the process instead of using processClass. This allows you to
273 * make easily identifyable processes even if you are using the same base
274 * <var>processClass</var> to start them.
275 *
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000276 * When invokeWith is not null, the process will be started as a fresh app
Tamas Berghammer0ca16fa2016-11-11 16:08:26 +0000277 * and not a zygote fork. Note that this is only allowed for uid 0 or when
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100278 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000279 *
Robert Sesek8f8d1872016-03-18 16:52:57 -0400280 * @param processClass The class to use as the process's main entry
281 * point.
282 * @param niceName A more readable name to use for the process.
283 * @param uid The user-id under which the process will run.
284 * @param gid The group-id under which the process will run.
285 * @param gids Additional group-ids associated with the process.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100286 * @param runtimeFlags Additional flags.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400287 * @param targetSdkVersion The target SDK version for the app.
288 * @param seInfo null-ok SELinux information for the new process.
289 * @param abi non-null the ABI this app should be started with.
290 * @param instructionSet null-ok the instruction set to use.
291 * @param appDataDir null-ok the data directory of the app.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000292 * @param invokeWith null-ok the command to invoke with.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700293 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700294 * @param packagesForUid null-ok all the packages with the same uid as this process.
295 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400296 * @param zygoteArgs Additional arguments to supply to the zygote process.
297 *
298 * @return An object that describes the result of the attempt to start the process.
299 * @throws RuntimeException on fatal start failure
300 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700301 public final Process.ProcessStartResult start(@NonNull final String processClass,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400302 final String niceName,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700303 int uid, int gid, @Nullable int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100304 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400305 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700306 @Nullable String seInfo,
307 @NonNull String abi,
308 @Nullable String instructionSet,
309 @Nullable String appDataDir,
310 @Nullable String invokeWith,
311 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700312 @Nullable String[] packagesForUid,
313 @Nullable String[] visibleVols,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800314 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700315 @Nullable String[] zygoteArgs) {
Robert Sesek8f8d1872016-03-18 16:52:57 -0400316 try {
317 return startViaZygote(processClass, niceName, uid, gid, gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100318 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
Chris Wailesefce9292019-01-11 13:19:20 -0800319 abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800320 packageName, packagesForUid, visibleVols, useBlastulaPool, zygoteArgs);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400321 } catch (ZygoteStartFailedEx ex) {
322 Log.e(LOG_TAG,
323 "Starting VM process through Zygote failed");
324 throw new RuntimeException(
325 "Starting VM process through Zygote failed", ex);
326 }
327 }
328
329 /** retry interval for opening a zygote socket */
330 static final int ZYGOTE_RETRY_MILLIS = 500;
331
332 /**
333 * Queries the zygote for the list of ABIS it supports.
334 *
335 * @throws ZygoteStartFailedEx if the query failed.
336 */
Robert Sesekded20982016-08-15 13:59:13 -0400337 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800338 private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400339 throws IOException {
340 // Each query starts with the argument count (1 in this case)
341 writer.write("1");
342 // ... followed by a new-line.
343 writer.newLine();
344 // ... followed by our only argument.
345 writer.write("--query-abi-list");
346 writer.newLine();
347 writer.flush();
348
349 // The response is a length prefixed stream of ASCII bytes.
350 int numBytes = inputStream.readInt();
351 byte[] bytes = new byte[numBytes];
352 inputStream.readFully(bytes);
353
Chris Wailesefce9292019-01-11 13:19:20 -0800354 String rawList = new String(bytes, StandardCharsets.US_ASCII);
355
356 return Arrays.asList(rawList.split(","));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400357 }
358
359 /**
360 * Sends an argument list to the zygote process, which starts a new child
361 * and returns the child's pid. Please note: the present implementation
362 * replaces newlines in the argument list with spaces.
363 *
364 * @throws ZygoteStartFailedEx if process start failed for any reason
365 */
Robert Sesekded20982016-08-15 13:59:13 -0400366 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400367 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800368 ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400369 throws ZygoteStartFailedEx {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800370 // Throw early if any of the arguments are malformed. This means we can
371 // avoid writing a partial response to the zygote.
372 for (String arg : args) {
373 if (arg.indexOf('\n') >= 0) {
374 throw new ZygoteStartFailedEx("embedded newlines not allowed");
375 }
376 }
377
378 /**
379 * See com.android.internal.os.SystemZygoteInit.readArgumentList()
380 * Presently the wire format to the zygote process is:
381 * a) a count of arguments (argc, in essence)
382 * b) a number of newline-separated argument strings equal to count
383 *
384 * After the zygote process reads these it will write the pid of
385 * the child or -1 on failure, followed by boolean to
386 * indicate whether a wrapper process was used.
387 */
388 String msgStr = Integer.toString(args.size()) + "\n"
389 + String.join("\n", args) + "\n";
390
391 // Should there be a timeout on this?
392 Process.ProcessStartResult result = new Process.ProcessStartResult();
393
394 // TODO (chriswailes): Move branch body into separate function.
395 if (useBlastulaPool && Zygote.BLASTULA_POOL_ENABLED && isValidBlastulaCommand(args)) {
396 LocalSocket blastulaSessionSocket = null;
397
398 try {
399 blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();
400
401 final BufferedWriter blastulaWriter =
402 new BufferedWriter(
403 new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
404 Zygote.SOCKET_BUFFER_SIZE);
405 final DataInputStream blastulaReader =
406 new DataInputStream(blastulaSessionSocket.getInputStream());
407
408 blastulaWriter.write(msgStr);
409 blastulaWriter.flush();
410
411 result.pid = blastulaReader.readInt();
412 // Blastulas can't be used to spawn processes that need wrappers.
413 result.usingWrapper = false;
414
415 if (result.pid < 0) {
416 throw new ZygoteStartFailedEx("Blastula specialization failed");
417 }
418
419 return result;
420 } catch (IOException ex) {
421 // If there was an IOException using the blastula pool we will log the error and
422 // attempt to start the process through the Zygote.
423 Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
424 + ex.toString());
425 } finally {
426 try {
427 blastulaSessionSocket.close();
428 } catch (IOException ex) {
429 Log.e(LOG_TAG, "Failed to close blastula session socket: " + ex.getMessage());
Robert Sesek0b58f192016-10-10 18:34:42 -0400430 }
431 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800432 }
Robert Sesek0b58f192016-10-10 18:34:42 -0400433
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800434 try {
435 final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
436 final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400437
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800438 zygoteWriter.write(msgStr);
439 zygoteWriter.flush();
Robert Sesek0b58f192016-10-10 18:34:42 -0400440
441 // Always read the entire result from the input stream to avoid leaving
442 // bytes in the stream for future process starts to accidentally stumble
443 // upon.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800444 result.pid = zygoteInputStream.readInt();
445 result.usingWrapper = zygoteInputStream.readBoolean();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400446 } catch (IOException ex) {
447 zygoteState.close();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800448 Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
449 + ex.toString());
Robert Sesek8f8d1872016-03-18 16:52:57 -0400450 throw new ZygoteStartFailedEx(ex);
451 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800452
453 if (result.pid < 0) {
454 throw new ZygoteStartFailedEx("fork() failed");
455 }
456
457 return result;
458 }
459
460 /**
461 * Flags that may not be passed to a blastula.
462 */
463 private static final String[] INVALID_BLASTULA_FLAGS = {
464 "--query-abi-list",
465 "--get-pid",
466 "--preload-default",
467 "--preload-package",
468 "--preload-app",
469 "--start-child-zygote",
470 "--set-api-blacklist-exemptions",
471 "--hidden-api-log-sampling-rate",
472 "--invoke-with"
473 };
474
475 /**
476 * Tests a command list to see if it is valid to send to a blastula.
477 * @param args Zygote/Blastula command arguments
478 * @return True if the command can be passed to a blastula; false otherwise
479 */
480 private static boolean isValidBlastulaCommand(ArrayList<String> args) {
481 for (String flag : args) {
482 for (String badFlag : INVALID_BLASTULA_FLAGS) {
483 if (flag.startsWith(badFlag)) {
484 return false;
485 }
486 }
487 }
488
489 return true;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400490 }
491
492 /**
493 * Starts a new process via the zygote mechanism.
494 *
495 * @param processClass Class name whose static main() to run
496 * @param niceName 'nice' process name to appear in ps
497 * @param uid a POSIX uid that the new process should setuid() to
498 * @param gid a POSIX gid that the new process shuold setgid() to
499 * @param gids null-ok; a list of supplementary group IDs that the
500 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100501 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400502 * @param targetSdkVersion The target SDK version for the app.
503 * @param seInfo null-ok SELinux information for the new process.
504 * @param abi the ABI the process should use.
505 * @param instructionSet null-ok the instruction set to use.
506 * @param appDataDir null-ok the data directory of the app.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500507 * @param startChildZygote Start a sub-zygote. This creates a new zygote process
508 * that has its state cloned from this zygote process.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700509 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700510 * @param packagesForUid null-ok all the packages with the same uid as this process.
511 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400512 * @param extraArgs Additional arguments to supply to the zygote process.
513 * @return An object that describes the result of the attempt to start the process.
514 * @throws ZygoteStartFailedEx if process start failed for any reason
515 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700516 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
517 @Nullable final String niceName,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400518 final int uid, final int gid,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700519 @Nullable final int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100520 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400521 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700522 @Nullable String seInfo,
523 @NonNull String abi,
524 @Nullable String instructionSet,
525 @Nullable String appDataDir,
526 @Nullable String invokeWith,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500527 boolean startChildZygote,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700528 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700529 @Nullable String[] packagesForUid,
530 @Nullable String[] visibleVols,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800531 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700532 @Nullable String[] extraArgs)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400533 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400534 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400535
Robert Sesekded20982016-08-15 13:59:13 -0400536 // --runtime-args, --setuid=, --setgid=,
537 // and --setgroups= must go first
538 argsForZygote.add("--runtime-args");
539 argsForZygote.add("--setuid=" + uid);
540 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100541 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400542 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
543 argsForZygote.add("--mount-external-default");
544 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
545 argsForZygote.add("--mount-external-read");
546 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
547 argsForZygote.add("--mount-external-write");
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700548 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
549 argsForZygote.add("--mount-external-full");
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800550 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
551 argsForZygote.add("--mount-external-installer");
Sudheer Shanka0b6da532019-01-09 12:06:51 -0800552 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
553 argsForZygote.add("--mount-external-legacy");
Robert Sesekded20982016-08-15 13:59:13 -0400554 }
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700555
Robert Sesekded20982016-08-15 13:59:13 -0400556 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400557
Robert Sesekded20982016-08-15 13:59:13 -0400558 // --setgroups is a comma-separated list
559 if (gids != null && gids.length > 0) {
560 StringBuilder sb = new StringBuilder();
561 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400562
Robert Sesekded20982016-08-15 13:59:13 -0400563 int sz = gids.length;
564 for (int i = 0; i < sz; i++) {
565 if (i != 0) {
566 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400567 }
Robert Sesekded20982016-08-15 13:59:13 -0400568 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400569 }
570
Robert Sesekded20982016-08-15 13:59:13 -0400571 argsForZygote.add(sb.toString());
572 }
573
574 if (niceName != null) {
575 argsForZygote.add("--nice-name=" + niceName);
576 }
577
578 if (seInfo != null) {
579 argsForZygote.add("--seinfo=" + seInfo);
580 }
581
582 if (instructionSet != null) {
583 argsForZygote.add("--instruction-set=" + instructionSet);
584 }
585
586 if (appDataDir != null) {
587 argsForZygote.add("--app-data-dir=" + appDataDir);
588 }
589
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000590 if (invokeWith != null) {
591 argsForZygote.add("--invoke-with");
592 argsForZygote.add(invokeWith);
593 }
594
Robert Sesekd0a190df2018-02-12 18:46:01 -0500595 if (startChildZygote) {
596 argsForZygote.add("--start-child-zygote");
597 }
598
Sudheer Shanka154fe3f2018-07-30 14:44:26 -0700599 if (packageName != null) {
600 argsForZygote.add("--package-name=" + packageName);
601 }
602
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700603 if (packagesForUid != null && packagesForUid.length > 0) {
604 final StringBuilder sb = new StringBuilder();
605 sb.append("--packages-for-uid=");
606
607 for (int i = 0; i < packagesForUid.length; ++i) {
608 if (i != 0) {
609 sb.append(',');
610 }
611 sb.append(packagesForUid[i]);
612 }
613 argsForZygote.add(sb.toString());
614 }
615
616 if (visibleVols != null && visibleVols.length > 0) {
617 final StringBuilder sb = new StringBuilder();
618 sb.append("--visible-vols=");
619
620 for (int i = 0; i < visibleVols.length; ++i) {
621 if (i != 0) {
622 sb.append(',');
623 }
624 sb.append(visibleVols[i]);
625 }
626 argsForZygote.add(sb.toString());
627 }
628
Robert Sesekded20982016-08-15 13:59:13 -0400629 argsForZygote.add(processClass);
630
631 if (extraArgs != null) {
632 for (String arg : extraArgs) {
633 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400634 }
Robert Sesekded20982016-08-15 13:59:13 -0400635 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400636
Robert Sesekded20982016-08-15 13:59:13 -0400637 synchronized(mLock) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800638 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
639 useBlastulaPool,
640 argsForZygote);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400641 }
642 }
643
644 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500645 * Closes the connections to the zygote, if they exist.
646 */
647 public void close() {
648 if (primaryZygoteState != null) {
649 primaryZygoteState.close();
650 }
651 if (secondaryZygoteState != null) {
652 secondaryZygoteState.close();
653 }
654 }
655
656 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400657 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
658 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
659 * already open.
660 */
661 public void establishZygoteConnectionForAbi(String abi) {
662 try {
Robert Sesekded20982016-08-15 13:59:13 -0400663 synchronized(mLock) {
664 openZygoteSocketIfNeeded(abi);
665 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400666 } catch (ZygoteStartFailedEx ex) {
667 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
668 }
669 }
670
671 /**
Andreas Gampe8444dca2018-05-01 13:31:28 -0700672 * Attempt to retrieve the PID of the zygote serving the given abi.
673 */
674 public int getZygotePid(String abi) {
675 try {
676 synchronized (mLock) {
677 ZygoteState state = openZygoteSocketIfNeeded(abi);
678
679 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800680 state.mZygoteOutputWriter.write("1");
Andreas Gampe8444dca2018-05-01 13:31:28 -0700681 // ... followed by a new-line.
Chris Wailesefce9292019-01-11 13:19:20 -0800682 state.mZygoteOutputWriter.newLine();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700683 // ... followed by our only argument.
Chris Wailesefce9292019-01-11 13:19:20 -0800684 state.mZygoteOutputWriter.write("--get-pid");
685 state.mZygoteOutputWriter.newLine();
686 state.mZygoteOutputWriter.flush();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700687
688 // The response is a length prefixed stream of ASCII bytes.
Chris Wailesefce9292019-01-11 13:19:20 -0800689 int numBytes = state.mZygoteInputStream.readInt();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700690 byte[] bytes = new byte[numBytes];
Chris Wailesefce9292019-01-11 13:19:20 -0800691 state.mZygoteInputStream.readFully(bytes);
Andreas Gampe8444dca2018-05-01 13:31:28 -0700692
693 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
694 }
695 } catch (Exception ex) {
696 throw new RuntimeException("Failure retrieving pid", ex);
697 }
698 }
699
700 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000701 * Push hidden API blacklisting exemptions into the zygote process(es).
702 *
703 * <p>The list of exemptions will take affect for all new processes forked from the zygote after
704 * this call.
705 *
Mathew Inwood33d51382018-04-05 13:56:39 +0100706 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
707 * whitelisted/public APIs (i.e. allowed, no logging of usage).
Mathew Inwood8faeab82018-03-16 14:26:08 +0000708 */
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100709 public boolean setApiBlacklistExemptions(List<String> exemptions) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000710 synchronized (mLock) {
711 mApiBlacklistExemptions = exemptions;
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100712 boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
713 if (ok) {
714 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
715 }
716 return ok;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000717 }
718 }
719
Mathew Inwood04194fe2018-04-04 14:48:03 +0100720 /**
721 * Set the precentage of detected hidden API accesses that are logged to the event log.
722 *
723 * <p>This rate will take affect for all new processes forked from the zygote after this call.
724 *
725 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
726 */
727 public void setHiddenApiAccessLogSampleRate(int rate) {
728 synchronized (mLock) {
729 mHiddenApiAccessLogSampleRate = rate;
730 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
731 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
732 }
733 }
734
Mathew Inwood8faeab82018-03-16 14:26:08 +0000735 @GuardedBy("mLock")
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100736 private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000737 if (state == null || state.isClosed()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100738 Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
739 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000740 }
741 if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100742 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000743 }
744 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800745 state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
746 state.mZygoteOutputWriter.newLine();
747 state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
748 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000749 for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
Chris Wailesefce9292019-01-11 13:19:20 -0800750 state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
751 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000752 }
Chris Wailesefce9292019-01-11 13:19:20 -0800753 state.mZygoteOutputWriter.flush();
754 int status = state.mZygoteInputStream.readInt();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000755 if (status != 0) {
756 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
757 }
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100758 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000759 } catch (IOException ioe) {
760 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100761 mApiBlacklistExemptions = Collections.emptyList();
762 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000763 }
764 }
765
Mathew Inwood04194fe2018-04-04 14:48:03 +0100766 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
767 if (state == null || state.isClosed()) {
768 return;
769 }
770 if (mHiddenApiAccessLogSampleRate == -1) {
771 return;
772 }
773 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800774 state.mZygoteOutputWriter.write(Integer.toString(1));
775 state.mZygoteOutputWriter.newLine();
776 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
Mathew Inwood04194fe2018-04-04 14:48:03 +0100777 + Integer.toString(mHiddenApiAccessLogSampleRate));
Chris Wailesefce9292019-01-11 13:19:20 -0800778 state.mZygoteOutputWriter.newLine();
779 state.mZygoteOutputWriter.flush();
780 int status = state.mZygoteInputStream.readInt();
Mathew Inwood04194fe2018-04-04 14:48:03 +0100781 if (status != 0) {
782 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
783 }
784 } catch (IOException ioe) {
785 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
786 }
787 }
788
Mathew Inwood8faeab82018-03-16 14:26:08 +0000789 /**
Chris Wailesefce9292019-01-11 13:19:20 -0800790 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
791 * already open. If a compatible session socket is already open that session socket is returned.
792 * This function may block and may have to try connecting to multiple Zygotes to find the
793 * appropriate one. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400794 */
Robert Sesekded20982016-08-15 13:59:13 -0400795 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800796 private ZygoteState openZygoteSocketIfNeeded(String abi)
797 throws ZygoteStartFailedEx {
798
Robert Sesekded20982016-08-15 13:59:13 -0400799 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
800
Robert Sesek8f8d1872016-03-18 16:52:57 -0400801 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
802 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800803 primaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800804 ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400805 } catch (IOException ioe) {
806 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
807 }
Chris Wailesefce9292019-01-11 13:19:20 -0800808
Mathew Inwood8faeab82018-03-16 14:26:08 +0000809 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100810 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400811 }
Chris Wailesefce9292019-01-11 13:19:20 -0800812
Robert Sesek8f8d1872016-03-18 16:52:57 -0400813 if (primaryZygoteState.matches(abi)) {
814 return primaryZygoteState;
815 }
816
817 // The primary zygote didn't match. Try the secondary.
818 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
819 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800820 secondaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800821 ZygoteState.connect(mZygoteSecondarySocketAddress,
822 mBlastulaPoolSecondarySocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400823 } catch (IOException ioe) {
824 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
825 }
Chris Wailesefce9292019-01-11 13:19:20 -0800826
Mathew Inwood8faeab82018-03-16 14:26:08 +0000827 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100828 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400829 }
830
831 if (secondaryZygoteState.matches(abi)) {
832 return secondaryZygoteState;
833 }
834
835 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
836 }
Robert Sesekded20982016-08-15 13:59:13 -0400837
838 /**
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100839 * Instructs the zygote to pre-load the application code for the given Application.
840 * Only the app zygote supports this function.
841 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
842 */
843 public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
844 IOException {
845 synchronized (mLock) {
846 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800847 state.mZygoteOutputWriter.write("2");
848 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100849
Chris Wailesefce9292019-01-11 13:19:20 -0800850 state.mZygoteOutputWriter.write("--preload-app");
851 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100852
853 // Zygote args needs to be strings, so in order to pass ApplicationInfo,
854 // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
855 Parcel parcel = Parcel.obtain();
856 appInfo.writeToParcel(parcel, 0 /* flags */);
857 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
858 parcel.recycle();
Chris Wailesefce9292019-01-11 13:19:20 -0800859 state.mZygoteOutputWriter.write(encodedParcelData);
860 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100861
Chris Wailesefce9292019-01-11 13:19:20 -0800862 state.mZygoteOutputWriter.flush();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100863
Chris Wailesefce9292019-01-11 13:19:20 -0800864 return (state.mZygoteInputStream.readInt() == 0);
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100865 }
866 }
867
868 /**
Robert Sesekded20982016-08-15 13:59:13 -0400869 * Instructs the zygote to pre-load the classes and native libraries at the given paths
870 * for the specified abi. Not all zygotes support this function.
871 */
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500872 public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
873 String cacheKey, String abi) throws ZygoteStartFailedEx,
874 IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400875 synchronized(mLock) {
876 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800877 state.mZygoteOutputWriter.write("5");
878 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400879
Chris Wailesefce9292019-01-11 13:19:20 -0800880 state.mZygoteOutputWriter.write("--preload-package");
881 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400882
Chris Wailesefce9292019-01-11 13:19:20 -0800883 state.mZygoteOutputWriter.write(packagePath);
884 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400885
Chris Wailesefce9292019-01-11 13:19:20 -0800886 state.mZygoteOutputWriter.write(libsPath);
887 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400888
Chris Wailesefce9292019-01-11 13:19:20 -0800889 state.mZygoteOutputWriter.write(libFileName);
890 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500891
Chris Wailesefce9292019-01-11 13:19:20 -0800892 state.mZygoteOutputWriter.write(cacheKey);
893 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000894
Chris Wailesefce9292019-01-11 13:19:20 -0800895 state.mZygoteOutputWriter.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100896
Chris Wailesefce9292019-01-11 13:19:20 -0800897 return (state.mZygoteInputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400898 }
899 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000900
901 /**
902 * Instructs the zygote to preload the default set of classes and resources. Returns
903 * {@code true} if a preload was performed as a result of this call, and {@code false}
904 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
905 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
906 */
907 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
908 synchronized (mLock) {
909 ZygoteState state = openZygoteSocketIfNeeded(abi);
910 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800911 state.mZygoteOutputWriter.write("1");
912 state.mZygoteOutputWriter.newLine();
913 state.mZygoteOutputWriter.write("--preload-default");
914 state.mZygoteOutputWriter.newLine();
915 state.mZygoteOutputWriter.flush();
Narayan Kamath669afcc2017-02-06 20:24:08 +0000916
Chris Wailesefce9292019-01-11 13:19:20 -0800917 return (state.mZygoteInputStream.readInt() == 0);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000918 }
919 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100920
921 /**
922 * Try connecting to the Zygote over and over again until we hit a time-out.
923 * @param socketName The name of the socket to connect to.
924 */
Chris Wailesefce9292019-01-11 13:19:20 -0800925 public static void waitForConnectionToZygote(String zygoteSocketName) {
926 final LocalSocketAddress zygoteSocketAddress =
927 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
928 waitForConnectionToZygote(zygoteSocketAddress);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500929 }
930
931 /**
932 * Try connecting to the Zygote over and over again until we hit a time-out.
933 * @param address The name of the socket to connect to.
934 */
Chris Wailesefce9292019-01-11 13:19:20 -0800935 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100936 for (int n = 20; n >= 0; n--) {
937 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800938 final ZygoteState zs =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800939 ZygoteState.connect(zygoteSocketAddress, null);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100940 zs.close();
941 return;
942 } catch (IOException ioe) {
943 Log.w(LOG_TAG,
944 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
945 }
946
947 try {
948 Thread.sleep(1000);
949 } catch (InterruptedException ie) {
950 }
951 }
Chris Wailesefce9292019-01-11 13:19:20 -0800952 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
953 + zygoteSocketAddress.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100954 }
Robert Sesekd0a190df2018-02-12 18:46:01 -0500955
956 /**
957 * Starts a new zygote process as a child of this zygote. This is used to create
958 * secondary zygotes that inherit data from the zygote that this object
959 * communicates with. This returns a new ZygoteProcess representing a connection
960 * to the newly created zygote. Throws an exception if the zygote cannot be started.
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100961 *
962 * @param processClass The class to use as the child zygote's main entry
963 * point.
964 * @param niceName A more readable name to use for the process.
965 * @param uid The user-id under which the child zygote will run.
966 * @param gid The group-id under which the child zygote will run.
967 * @param gids Additional group-ids associated with the child zygote process.
968 * @param runtimeFlags Additional flags.
969 * @param seInfo null-ok SELinux information for the child zygote process.
970 * @param abi non-null the ABI of the child zygote
971 * @param acceptedAbiList ABIs this child zygote will accept connections for; this
972 * may be different from <code>abi</code> in case the children
973 * spawned from this Zygote only communicate using ABI-safe methods.
974 * @param instructionSet null-ok the instruction set to use.
Martijn Coenen86f08a52019-01-03 16:23:01 +0100975 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
976 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
Robert Sesekd0a190df2018-02-12 18:46:01 -0500977 */
978 public ChildZygoteProcess startChildZygote(final String processClass,
979 final String niceName,
980 int uid, int gid, int[] gids,
981 int runtimeFlags,
982 String seInfo,
983 String abi,
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100984 String acceptedAbiList,
Martijn Coenen86f08a52019-01-03 16:23:01 +0100985 String instructionSet,
986 int uidRangeStart,
987 int uidRangeEnd) {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500988 // Create an unguessable address in the global abstract namespace.
989 final LocalSocketAddress serverAddress = new LocalSocketAddress(
990 processClass + "/" + UUID.randomUUID().toString());
991
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100992 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
Martijn Coenen86f08a52019-01-03 16:23:01 +0100993 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
994 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
995 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
Robert Sesekd0a190df2018-02-12 18:46:01 -0500996
997 Process.ProcessStartResult result;
998 try {
999 result = startViaZygote(processClass, niceName, uid, gid,
1000 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
1001 abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001002 true /* startChildZygote */, null /* packageName */,
Chris Wailesba4c2eb2019-01-11 17:13:00 -08001003 null /* packagesForUid */, null /* visibleVolumes */,
1004 false /* useBlastulaPool */, extraArgs);
Robert Sesekd0a190df2018-02-12 18:46:01 -05001005 } catch (ZygoteStartFailedEx ex) {
1006 throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
1007 }
1008
1009 return new ChildZygoteProcess(serverAddress, result.pid);
1010 }
Robert Sesek8f8d1872016-03-18 16:52:57 -04001011}