blob: 370381c9cb109d176d1c0705f6849750564698aa [file] [log] [blame]
Robert Sesek8f8d1872016-03-18 16:52:57 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
18
Sudheer Shankad81b1d72018-09-05 16:37:30 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010021import android.content.pm.ApplicationInfo;
Robert Sesek8f8d1872016-03-18 16:52:57 -040022import android.net.LocalSocket;
23import android.net.LocalSocketAddress;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080024import android.provider.DeviceConfig;
Robert Sesek8f8d1872016-03-18 16:52:57 -040025import android.util.Log;
Gustav Senntonf0c52b52017-04-27 17:00:50 +010026import android.util.Slog;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010027
Robert Sesekded20982016-08-15 13:59:13 -040028import com.android.internal.annotations.GuardedBy;
Robert Sesek8f8d1872016-03-18 16:52:57 -040029import com.android.internal.os.Zygote;
Robert Sesekded20982016-08-15 13:59:13 -040030import com.android.internal.util.Preconditions;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010031
Robert Sesek8f8d1872016-03-18 16:52:57 -040032import java.io.BufferedWriter;
33import java.io.DataInputStream;
34import java.io.IOException;
35import java.io.OutputStreamWriter;
36import java.nio.charset.StandardCharsets;
37import java.util.ArrayList;
38import java.util.Arrays;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010039import java.util.Base64;
Mathew Inwood8faeab82018-03-16 14:26:08 +000040import java.util.Collections;
Robert Sesek8f8d1872016-03-18 16:52:57 -040041import java.util.List;
Robert Sesekd0a190df2018-02-12 18:46:01 -050042import java.util.UUID;
Robert Sesek8f8d1872016-03-18 16:52:57 -040043
44/*package*/ class ZygoteStartFailedEx extends Exception {
45 ZygoteStartFailedEx(String s) {
46 super(s);
47 }
48
49 ZygoteStartFailedEx(Throwable cause) {
50 super(cause);
51 }
52
53 ZygoteStartFailedEx(String s, Throwable cause) {
54 super(s, cause);
55 }
56}
57
58/**
59 * Maintains communication state with the zygote processes. This class is responsible
60 * for the sockets opened to the zygotes and for starting processes on behalf of the
61 * {@link android.os.Process} class.
62 *
63 * {@hide}
64 */
65public class ZygoteProcess {
Chris Wailesefce9292019-01-11 13:19:20 -080066
67 /**
68 * @hide for internal use only.
69 */
Martijn Coenen82dc85a2019-01-28 13:12:28 +010070 public static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
71
72 /**
73 * @hide for internal use only.
74 *
75 * Use a relatively short delay, because for app zygote, this is in the critical path of
76 * service launch.
77 */
78 public static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
79
80 /**
Chris Wailesefce9292019-01-11 13:19:20 -080081 * @hide for internal use only
82 */
Robert Sesek8f8d1872016-03-18 16:52:57 -040083 private static final String LOG_TAG = "ZygoteProcess";
84
85 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080086 * The default value for enabling the blastula pool.
87 */
88 private static final String BLASTULA_POOL_ENABLED_DEFAULT = "false";
89
90 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -040091 * The name of the socket used to communicate with the primary zygote.
92 */
Chris Wailesefce9292019-01-11 13:19:20 -080093 private final LocalSocketAddress mZygoteSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -040094
95 /**
96 * The name of the secondary (alternate ABI) zygote socket.
97 */
Chris Wailesefce9292019-01-11 13:19:20 -080098 private final LocalSocketAddress mZygoteSecondarySocketAddress;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080099
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 =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800112 new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME,
113 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesefce9292019-01-11 13:19:20 -0800114 mZygoteSecondarySocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800115 new LocalSocketAddress(Zygote.SECONDARY_SOCKET_NAME,
Chris Wailesefce9292019-01-11 13:19:20 -0800116 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800117
118 mBlastulaPoolSocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800119 new LocalSocketAddress(Zygote.BLASTULA_POOL_PRIMARY_SOCKET_NAME,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800120 LocalSocketAddress.Namespace.RESERVED);
121 mBlastulaPoolSecondarySocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800122 new LocalSocketAddress(Zygote.BLASTULA_POOL_SECONDARY_SOCKET_NAME,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800123 LocalSocketAddress.Namespace.RESERVED);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800124
125 // TODO (chriswailes): Uncomment when the blastula pool can be enabled.
126// fetchBlastulaPoolEnabledProp();
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500127 }
128
Chris Wailesefce9292019-01-11 13:19:20 -0800129 public ZygoteProcess(LocalSocketAddress primarySocketAddress,
130 LocalSocketAddress secondarySocketAddress) {
131 mZygoteSocketAddress = primarySocketAddress;
132 mZygoteSecondarySocketAddress = secondarySocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800133
134 mBlastulaPoolSocketAddress = null;
135 mBlastulaPoolSecondarySocketAddress = null;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400136 }
137
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500138 public LocalSocketAddress getPrimarySocketAddress() {
Chris Wailesefce9292019-01-11 13:19:20 -0800139 return mZygoteSocketAddress;
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500140 }
141
Robert Sesek8f8d1872016-03-18 16:52:57 -0400142 /**
143 * State for communicating with the zygote process.
144 */
145 public static class ZygoteState {
Chris Wailesefce9292019-01-11 13:19:20 -0800146 final LocalSocketAddress mZygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800147 final LocalSocketAddress mBlastulaSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400148
Chris Wailesefce9292019-01-11 13:19:20 -0800149 private final LocalSocket mZygoteSessionSocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400150
Chris Wailesefce9292019-01-11 13:19:20 -0800151 final DataInputStream mZygoteInputStream;
152 final BufferedWriter mZygoteOutputWriter;
153
154 private final List<String> mABIList;
155
156 private boolean mClosed;
157
158 private ZygoteState(LocalSocketAddress zygoteSocketAddress,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800159 LocalSocketAddress blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800160 LocalSocket zygoteSessionSocket,
161 DataInputStream zygoteInputStream,
162 BufferedWriter zygoteOutputWriter,
163 List<String> abiList) {
164 this.mZygoteSocketAddress = zygoteSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800165 this.mBlastulaSocketAddress = blastulaSocketAddress;
Chris Wailesefce9292019-01-11 13:19:20 -0800166 this.mZygoteSessionSocket = zygoteSessionSocket;
167 this.mZygoteInputStream = zygoteInputStream;
168 this.mZygoteOutputWriter = zygoteOutputWriter;
169 this.mABIList = abiList;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400170 }
171
Chris Wailesefce9292019-01-11 13:19:20 -0800172 /**
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800173 * Create a new ZygoteState object by connecting to the given Zygote socket and saving the
174 * given blastula socket address.
Chris Wailesefce9292019-01-11 13:19:20 -0800175 *
176 * @param zygoteSocketAddress Zygote socket to connect to
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800177 * @param blastulaSocketAddress Blastula socket address to save for later
Chris Wailesefce9292019-01-11 13:19:20 -0800178 * @return A new ZygoteState object containing a session socket for the given Zygote socket
179 * address
180 * @throws IOException
181 */
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800182 public static ZygoteState connect(LocalSocketAddress zygoteSocketAddress,
183 LocalSocketAddress blastulaSocketAddress)
Chris Wailesefce9292019-01-11 13:19:20 -0800184 throws IOException {
185
Robert Sesek8f8d1872016-03-18 16:52:57 -0400186 DataInputStream zygoteInputStream = null;
Chris Wailesefce9292019-01-11 13:19:20 -0800187 BufferedWriter zygoteOutputWriter = null;
188 final LocalSocket zygoteSessionSocket = new LocalSocket();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400189
190 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800191 zygoteSessionSocket.connect(zygoteSocketAddress);
192 zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
193 zygoteOutputWriter =
194 new BufferedWriter(
195 new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800196 Zygote.SOCKET_BUFFER_SIZE);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400197 } catch (IOException ex) {
198 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800199 zygoteSessionSocket.close();
200 } catch (IOException ignore) { }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400201
202 throw ex;
203 }
204
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800205 return new ZygoteState(zygoteSocketAddress, blastulaSocketAddress,
Chris Wailesefce9292019-01-11 13:19:20 -0800206 zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
207 getAbiList(zygoteOutputWriter, zygoteInputStream));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400208 }
209
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800210 LocalSocket getBlastulaSessionSocket() throws IOException {
211 final LocalSocket blastulaSessionSocket = new LocalSocket();
212 blastulaSessionSocket.connect(this.mBlastulaSocketAddress);
213
214 return blastulaSessionSocket;
215 }
216
Robert Sesek8f8d1872016-03-18 16:52:57 -0400217 boolean matches(String abi) {
Chris Wailesefce9292019-01-11 13:19:20 -0800218 return mABIList.contains(abi);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400219 }
220
221 public void close() {
222 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800223 mZygoteSessionSocket.close();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400224 } catch (IOException ex) {
225 Log.e(LOG_TAG,"I/O exception on routine close", ex);
226 }
227
228 mClosed = true;
229 }
230
231 boolean isClosed() {
232 return mClosed;
233 }
234 }
235
236 /**
Robert Sesekded20982016-08-15 13:59:13 -0400237 * Lock object to protect access to the two ZygoteStates below. This lock must be
238 * acquired while communicating over the ZygoteState's socket, to prevent
239 * interleaved access.
240 */
241 private final Object mLock = new Object();
242
243 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000244 * List of exemptions to the API blacklist. These are prefix matches on the runtime format
245 * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
246 * list.
247 */
248 private List<String> mApiBlacklistExemptions = Collections.emptyList();
249
250 /**
Mathew Inwood04194fe2018-04-04 14:48:03 +0100251 * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
252 */
253 private int mHiddenApiAccessLogSampleRate;
254
255 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400256 * The state of the connection to the primary zygote.
257 */
258 private ZygoteState primaryZygoteState;
259
260 /**
261 * The state of the connection to the secondary zygote.
262 */
263 private ZygoteState secondaryZygoteState;
264
265 /**
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800266 * If the blastula pool should be created and used to start applications.
267 *
268 * Setting this value to false will disable the creation, maintenance, and use of the blastula
269 * pool. When the blastula pool is disabled the application lifecycle will be identical to
270 * previous versions of Android.
271 */
272 private boolean mBlastulaPoolEnabled = false;
273
274 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400275 * Start a new process.
276 *
277 * <p>If processes are enabled, a new process is created and the
278 * static main() function of a <var>processClass</var> is executed there.
279 * The process will continue running after this function returns.
280 *
281 * <p>If processes are not enabled, a new thread in the caller's
Mathew Inwood8faeab82018-03-16 14:26:08 +0000282 * process is created and main() of <var>processclass</var> called there.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400283 *
284 * <p>The niceName parameter, if not an empty string, is a custom name to
285 * give to the process instead of using processClass. This allows you to
286 * make easily identifyable processes even if you are using the same base
287 * <var>processClass</var> to start them.
288 *
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000289 * When invokeWith is not null, the process will be started as a fresh app
Tamas Berghammer0ca16fa2016-11-11 16:08:26 +0000290 * and not a zygote fork. Note that this is only allowed for uid 0 or when
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100291 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000292 *
Robert Sesek8f8d1872016-03-18 16:52:57 -0400293 * @param processClass The class to use as the process's main entry
294 * point.
295 * @param niceName A more readable name to use for the process.
296 * @param uid The user-id under which the process will run.
297 * @param gid The group-id under which the process will run.
298 * @param gids Additional group-ids associated with the process.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100299 * @param runtimeFlags Additional flags.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400300 * @param targetSdkVersion The target SDK version for the app.
301 * @param seInfo null-ok SELinux information for the new process.
302 * @param abi non-null the ABI this app should be started with.
303 * @param instructionSet null-ok the instruction set to use.
304 * @param appDataDir null-ok the data directory of the app.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000305 * @param invokeWith null-ok the command to invoke with.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700306 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700307 * @param packagesForUid null-ok all the packages with the same uid as this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400308 * @param zygoteArgs Additional arguments to supply to the zygote process.
309 *
310 * @return An object that describes the result of the attempt to start the process.
311 * @throws RuntimeException on fatal start failure
312 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700313 public final Process.ProcessStartResult start(@NonNull final String processClass,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400314 final String niceName,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700315 int uid, int gid, @Nullable int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100316 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400317 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700318 @Nullable String seInfo,
319 @NonNull String abi,
320 @Nullable String instructionSet,
321 @Nullable String appDataDir,
322 @Nullable String invokeWith,
323 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700324 @Nullable String[] packagesForUid,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800325 @Nullable String sandboxId,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800326 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700327 @Nullable String[] zygoteArgs) {
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800328 if (fetchBlastulaPoolEnabledProp()) {
329 // TODO (chriswailes): Send the appropriate command to the zygotes
330 Log.i(LOG_TAG, "Blastula pool enabled property set to: " + mBlastulaPoolEnabled);
331
332 // This can't be enabled yet, but we do want to test this code path.
333 mBlastulaPoolEnabled = false;
334 }
335
Robert Sesek8f8d1872016-03-18 16:52:57 -0400336 try {
337 return startViaZygote(processClass, niceName, uid, gid, gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100338 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
Chris Wailesefce9292019-01-11 13:19:20 -0800339 abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
Sudheer Shankae51005d2019-02-24 10:24:09 -0800340 packageName, packagesForUid, sandboxId,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800341 useBlastulaPool, zygoteArgs);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400342 } catch (ZygoteStartFailedEx ex) {
343 Log.e(LOG_TAG,
344 "Starting VM process through Zygote failed");
345 throw new RuntimeException(
346 "Starting VM process through Zygote failed", ex);
347 }
348 }
349
350 /** retry interval for opening a zygote socket */
351 static final int ZYGOTE_RETRY_MILLIS = 500;
352
353 /**
354 * Queries the zygote for the list of ABIS it supports.
355 *
356 * @throws ZygoteStartFailedEx if the query failed.
357 */
Robert Sesekded20982016-08-15 13:59:13 -0400358 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800359 private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400360 throws IOException {
361 // Each query starts with the argument count (1 in this case)
362 writer.write("1");
363 // ... followed by a new-line.
364 writer.newLine();
365 // ... followed by our only argument.
366 writer.write("--query-abi-list");
367 writer.newLine();
368 writer.flush();
369
370 // The response is a length prefixed stream of ASCII bytes.
371 int numBytes = inputStream.readInt();
372 byte[] bytes = new byte[numBytes];
373 inputStream.readFully(bytes);
374
Chris Wailesefce9292019-01-11 13:19:20 -0800375 String rawList = new String(bytes, StandardCharsets.US_ASCII);
376
377 return Arrays.asList(rawList.split(","));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400378 }
379
380 /**
381 * Sends an argument list to the zygote process, which starts a new child
382 * and returns the child's pid. Please note: the present implementation
383 * replaces newlines in the argument list with spaces.
384 *
385 * @throws ZygoteStartFailedEx if process start failed for any reason
386 */
Robert Sesekded20982016-08-15 13:59:13 -0400387 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400388 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800389 ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400390 throws ZygoteStartFailedEx {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800391 // Throw early if any of the arguments are malformed. This means we can
392 // avoid writing a partial response to the zygote.
393 for (String arg : args) {
394 if (arg.indexOf('\n') >= 0) {
395 throw new ZygoteStartFailedEx("embedded newlines not allowed");
396 }
397 }
398
Chris Wailesb13bfc52019-02-20 11:19:48 -0800399 /*
400 * See com.android.internal.os.ZygoteArguments.parseArgs()
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800401 * Presently the wire format to the zygote process is:
402 * a) a count of arguments (argc, in essence)
403 * b) a number of newline-separated argument strings equal to count
404 *
405 * After the zygote process reads these it will write the pid of
406 * the child or -1 on failure, followed by boolean to
407 * indicate whether a wrapper process was used.
408 */
409 String msgStr = Integer.toString(args.size()) + "\n"
410 + String.join("\n", args) + "\n";
411
412 // Should there be a timeout on this?
413 Process.ProcessStartResult result = new Process.ProcessStartResult();
414
415 // TODO (chriswailes): Move branch body into separate function.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800416 if (useBlastulaPool && isValidBlastulaCommand(args)) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800417 LocalSocket blastulaSessionSocket = null;
418
419 try {
420 blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();
421
422 final BufferedWriter blastulaWriter =
423 new BufferedWriter(
424 new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
425 Zygote.SOCKET_BUFFER_SIZE);
426 final DataInputStream blastulaReader =
427 new DataInputStream(blastulaSessionSocket.getInputStream());
428
429 blastulaWriter.write(msgStr);
430 blastulaWriter.flush();
431
432 result.pid = blastulaReader.readInt();
433 // Blastulas can't be used to spawn processes that need wrappers.
434 result.usingWrapper = false;
435
436 if (result.pid < 0) {
437 throw new ZygoteStartFailedEx("Blastula specialization failed");
438 }
439
440 return result;
441 } catch (IOException ex) {
442 // If there was an IOException using the blastula pool we will log the error and
443 // attempt to start the process through the Zygote.
444 Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
445 + ex.toString());
446 } finally {
447 try {
448 blastulaSessionSocket.close();
449 } catch (IOException ex) {
450 Log.e(LOG_TAG, "Failed to close blastula session socket: " + ex.getMessage());
Robert Sesek0b58f192016-10-10 18:34:42 -0400451 }
452 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800453 }
Robert Sesek0b58f192016-10-10 18:34:42 -0400454
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800455 try {
456 final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
457 final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400458
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800459 zygoteWriter.write(msgStr);
460 zygoteWriter.flush();
Robert Sesek0b58f192016-10-10 18:34:42 -0400461
462 // Always read the entire result from the input stream to avoid leaving
463 // bytes in the stream for future process starts to accidentally stumble
464 // upon.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800465 result.pid = zygoteInputStream.readInt();
466 result.usingWrapper = zygoteInputStream.readBoolean();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400467 } catch (IOException ex) {
468 zygoteState.close();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800469 Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
470 + ex.toString());
Robert Sesek8f8d1872016-03-18 16:52:57 -0400471 throw new ZygoteStartFailedEx(ex);
472 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800473
474 if (result.pid < 0) {
475 throw new ZygoteStartFailedEx("fork() failed");
476 }
477
478 return result;
479 }
480
481 /**
482 * Flags that may not be passed to a blastula.
483 */
484 private static final String[] INVALID_BLASTULA_FLAGS = {
485 "--query-abi-list",
486 "--get-pid",
487 "--preload-default",
488 "--preload-package",
489 "--preload-app",
490 "--start-child-zygote",
491 "--set-api-blacklist-exemptions",
492 "--hidden-api-log-sampling-rate",
493 "--invoke-with"
494 };
495
496 /**
497 * Tests a command list to see if it is valid to send to a blastula.
498 * @param args Zygote/Blastula command arguments
499 * @return True if the command can be passed to a blastula; false otherwise
500 */
501 private static boolean isValidBlastulaCommand(ArrayList<String> args) {
502 for (String flag : args) {
503 for (String badFlag : INVALID_BLASTULA_FLAGS) {
504 if (flag.startsWith(badFlag)) {
505 return false;
506 }
507 }
508 }
509
510 return true;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400511 }
512
513 /**
514 * Starts a new process via the zygote mechanism.
515 *
516 * @param processClass Class name whose static main() to run
517 * @param niceName 'nice' process name to appear in ps
518 * @param uid a POSIX uid that the new process should setuid() to
519 * @param gid a POSIX gid that the new process shuold setgid() to
520 * @param gids null-ok; a list of supplementary group IDs that the
521 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100522 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400523 * @param targetSdkVersion The target SDK version for the app.
524 * @param seInfo null-ok SELinux information for the new process.
525 * @param abi the ABI the process should use.
526 * @param instructionSet null-ok the instruction set to use.
527 * @param appDataDir null-ok the data directory of the app.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500528 * @param startChildZygote Start a sub-zygote. This creates a new zygote process
529 * that has its state cloned from this zygote process.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700530 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700531 * @param packagesForUid null-ok all the packages with the same uid as this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400532 * @param extraArgs Additional arguments to supply to the zygote process.
533 * @return An object that describes the result of the attempt to start the process.
534 * @throws ZygoteStartFailedEx if process start failed for any reason
535 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700536 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
537 @Nullable final String niceName,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400538 final int uid, final int gid,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700539 @Nullable final int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100540 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400541 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700542 @Nullable String seInfo,
543 @NonNull String abi,
544 @Nullable String instructionSet,
545 @Nullable String appDataDir,
546 @Nullable String invokeWith,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500547 boolean startChildZygote,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700548 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700549 @Nullable String[] packagesForUid,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800550 @Nullable String sandboxId,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800551 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700552 @Nullable String[] extraArgs)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400553 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400554 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400555
Robert Sesekded20982016-08-15 13:59:13 -0400556 // --runtime-args, --setuid=, --setgid=,
557 // and --setgroups= must go first
558 argsForZygote.add("--runtime-args");
559 argsForZygote.add("--setuid=" + uid);
560 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100561 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400562 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
563 argsForZygote.add("--mount-external-default");
564 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
565 argsForZygote.add("--mount-external-read");
566 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
567 argsForZygote.add("--mount-external-write");
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700568 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
569 argsForZygote.add("--mount-external-full");
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800570 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
571 argsForZygote.add("--mount-external-installer");
Sudheer Shanka0b6da532019-01-09 12:06:51 -0800572 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
573 argsForZygote.add("--mount-external-legacy");
Robert Sesekded20982016-08-15 13:59:13 -0400574 }
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700575
Robert Sesekded20982016-08-15 13:59:13 -0400576 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400577
Robert Sesekded20982016-08-15 13:59:13 -0400578 // --setgroups is a comma-separated list
579 if (gids != null && gids.length > 0) {
580 StringBuilder sb = new StringBuilder();
581 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400582
Robert Sesekded20982016-08-15 13:59:13 -0400583 int sz = gids.length;
584 for (int i = 0; i < sz; i++) {
585 if (i != 0) {
586 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400587 }
Robert Sesekded20982016-08-15 13:59:13 -0400588 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400589 }
590
Robert Sesekded20982016-08-15 13:59:13 -0400591 argsForZygote.add(sb.toString());
592 }
593
594 if (niceName != null) {
595 argsForZygote.add("--nice-name=" + niceName);
596 }
597
598 if (seInfo != null) {
599 argsForZygote.add("--seinfo=" + seInfo);
600 }
601
602 if (instructionSet != null) {
603 argsForZygote.add("--instruction-set=" + instructionSet);
604 }
605
606 if (appDataDir != null) {
607 argsForZygote.add("--app-data-dir=" + appDataDir);
608 }
609
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000610 if (invokeWith != null) {
611 argsForZygote.add("--invoke-with");
612 argsForZygote.add(invokeWith);
613 }
614
Robert Sesekd0a190df2018-02-12 18:46:01 -0500615 if (startChildZygote) {
616 argsForZygote.add("--start-child-zygote");
617 }
618
Sudheer Shanka154fe3f2018-07-30 14:44:26 -0700619 if (packageName != null) {
620 argsForZygote.add("--package-name=" + packageName);
621 }
622
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700623 if (packagesForUid != null && packagesForUid.length > 0) {
624 final StringBuilder sb = new StringBuilder();
625 sb.append("--packages-for-uid=");
626
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800627 // TODO (chriswailes): Replace with String.join
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700628 for (int i = 0; i < packagesForUid.length; ++i) {
629 if (i != 0) {
630 sb.append(',');
631 }
632 sb.append(packagesForUid[i]);
633 }
634 argsForZygote.add(sb.toString());
635 }
636
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800637 if (sandboxId != null) {
638 argsForZygote.add("--sandbox-id=" + sandboxId);
639 }
640
Robert Sesekded20982016-08-15 13:59:13 -0400641 argsForZygote.add(processClass);
642
643 if (extraArgs != null) {
644 for (String arg : extraArgs) {
645 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400646 }
Robert Sesekded20982016-08-15 13:59:13 -0400647 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400648
Robert Sesekded20982016-08-15 13:59:13 -0400649 synchronized(mLock) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800650 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800651 useBlastulaPool && mBlastulaPoolEnabled,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800652 argsForZygote);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400653 }
654 }
655
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800656 private boolean fetchBlastulaPoolEnabledProp() {
657 boolean origVal = mBlastulaPoolEnabled;
658
659 final String propertyString =
660 Zygote.getSystemProperty(
661 DeviceConfig.RuntimeNative.BLASTULA_POOL_ENABLED,
662 BLASTULA_POOL_ENABLED_DEFAULT);
663
664 if (!propertyString.isEmpty()) {
665 mBlastulaPoolEnabled =
666 Zygote.getSystemPropertyBoolean(
667 DeviceConfig.RuntimeNative.BLASTULA_POOL_ENABLED,
668 Boolean.parseBoolean(BLASTULA_POOL_ENABLED_DEFAULT));
669 }
670
671 return origVal != mBlastulaPoolEnabled;
672 }
673
674 private long mLastPropCheckTimestamp = 0;
675
676 private boolean fetchBlastulaPoolEnabledPropWithMinInterval() {
677 final long currentTimestamp = SystemClock.elapsedRealtime();
678
679 if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
680 mLastPropCheckTimestamp = currentTimestamp;
681 return fetchBlastulaPoolEnabledProp();
682 }
683
684 return false;
685 }
686
Robert Sesek8f8d1872016-03-18 16:52:57 -0400687 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500688 * Closes the connections to the zygote, if they exist.
689 */
690 public void close() {
691 if (primaryZygoteState != null) {
692 primaryZygoteState.close();
693 }
694 if (secondaryZygoteState != null) {
695 secondaryZygoteState.close();
696 }
697 }
698
699 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400700 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
701 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
702 * already open.
703 */
704 public void establishZygoteConnectionForAbi(String abi) {
705 try {
Robert Sesekded20982016-08-15 13:59:13 -0400706 synchronized(mLock) {
707 openZygoteSocketIfNeeded(abi);
708 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400709 } catch (ZygoteStartFailedEx ex) {
710 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
711 }
712 }
713
714 /**
Andreas Gampe8444dca2018-05-01 13:31:28 -0700715 * Attempt to retrieve the PID of the zygote serving the given abi.
716 */
717 public int getZygotePid(String abi) {
718 try {
719 synchronized (mLock) {
720 ZygoteState state = openZygoteSocketIfNeeded(abi);
721
722 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800723 state.mZygoteOutputWriter.write("1");
Andreas Gampe8444dca2018-05-01 13:31:28 -0700724 // ... followed by a new-line.
Chris Wailesefce9292019-01-11 13:19:20 -0800725 state.mZygoteOutputWriter.newLine();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700726 // ... followed by our only argument.
Chris Wailesefce9292019-01-11 13:19:20 -0800727 state.mZygoteOutputWriter.write("--get-pid");
728 state.mZygoteOutputWriter.newLine();
729 state.mZygoteOutputWriter.flush();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700730
731 // The response is a length prefixed stream of ASCII bytes.
Chris Wailesefce9292019-01-11 13:19:20 -0800732 int numBytes = state.mZygoteInputStream.readInt();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700733 byte[] bytes = new byte[numBytes];
Chris Wailesefce9292019-01-11 13:19:20 -0800734 state.mZygoteInputStream.readFully(bytes);
Andreas Gampe8444dca2018-05-01 13:31:28 -0700735
736 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
737 }
738 } catch (Exception ex) {
739 throw new RuntimeException("Failure retrieving pid", ex);
740 }
741 }
742
743 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000744 * Push hidden API blacklisting exemptions into the zygote process(es).
745 *
746 * <p>The list of exemptions will take affect for all new processes forked from the zygote after
747 * this call.
748 *
Mathew Inwood33d51382018-04-05 13:56:39 +0100749 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
750 * whitelisted/public APIs (i.e. allowed, no logging of usage).
Mathew Inwood8faeab82018-03-16 14:26:08 +0000751 */
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100752 public boolean setApiBlacklistExemptions(List<String> exemptions) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000753 synchronized (mLock) {
754 mApiBlacklistExemptions = exemptions;
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100755 boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
756 if (ok) {
757 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
758 }
759 return ok;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000760 }
761 }
762
Mathew Inwood04194fe2018-04-04 14:48:03 +0100763 /**
764 * Set the precentage of detected hidden API accesses that are logged to the event log.
765 *
766 * <p>This rate will take affect for all new processes forked from the zygote after this call.
767 *
768 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
769 */
770 public void setHiddenApiAccessLogSampleRate(int rate) {
771 synchronized (mLock) {
772 mHiddenApiAccessLogSampleRate = rate;
773 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
774 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
775 }
776 }
777
Mathew Inwood8faeab82018-03-16 14:26:08 +0000778 @GuardedBy("mLock")
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100779 private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000780 if (state == null || state.isClosed()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100781 Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
782 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000783 }
784 if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100785 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000786 }
787 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800788 state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
789 state.mZygoteOutputWriter.newLine();
790 state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
791 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000792 for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
Chris Wailesefce9292019-01-11 13:19:20 -0800793 state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
794 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000795 }
Chris Wailesefce9292019-01-11 13:19:20 -0800796 state.mZygoteOutputWriter.flush();
797 int status = state.mZygoteInputStream.readInt();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000798 if (status != 0) {
799 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
800 }
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100801 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000802 } catch (IOException ioe) {
803 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100804 mApiBlacklistExemptions = Collections.emptyList();
805 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000806 }
807 }
808
Mathew Inwood04194fe2018-04-04 14:48:03 +0100809 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
810 if (state == null || state.isClosed()) {
811 return;
812 }
813 if (mHiddenApiAccessLogSampleRate == -1) {
814 return;
815 }
816 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800817 state.mZygoteOutputWriter.write(Integer.toString(1));
818 state.mZygoteOutputWriter.newLine();
819 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
Mathew Inwood04194fe2018-04-04 14:48:03 +0100820 + Integer.toString(mHiddenApiAccessLogSampleRate));
Chris Wailesefce9292019-01-11 13:19:20 -0800821 state.mZygoteOutputWriter.newLine();
822 state.mZygoteOutputWriter.flush();
823 int status = state.mZygoteInputStream.readInt();
Mathew Inwood04194fe2018-04-04 14:48:03 +0100824 if (status != 0) {
825 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
826 }
827 } catch (IOException ioe) {
828 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
829 }
830 }
831
Mathew Inwood8faeab82018-03-16 14:26:08 +0000832 /**
Chris Wailesefce9292019-01-11 13:19:20 -0800833 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
834 * already open. If a compatible session socket is already open that session socket is returned.
835 * This function may block and may have to try connecting to multiple Zygotes to find the
836 * appropriate one. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400837 */
Robert Sesekded20982016-08-15 13:59:13 -0400838 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800839 private ZygoteState openZygoteSocketIfNeeded(String abi)
840 throws ZygoteStartFailedEx {
841
Robert Sesekded20982016-08-15 13:59:13 -0400842 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
843
Robert Sesek8f8d1872016-03-18 16:52:57 -0400844 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
845 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800846 primaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800847 ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400848 } catch (IOException ioe) {
849 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
850 }
Chris Wailesefce9292019-01-11 13:19:20 -0800851
Mathew Inwood8faeab82018-03-16 14:26:08 +0000852 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100853 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400854 }
Chris Wailesefce9292019-01-11 13:19:20 -0800855
Robert Sesek8f8d1872016-03-18 16:52:57 -0400856 if (primaryZygoteState.matches(abi)) {
857 return primaryZygoteState;
858 }
859
860 // The primary zygote didn't match. Try the secondary.
861 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
862 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800863 secondaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800864 ZygoteState.connect(mZygoteSecondarySocketAddress,
865 mBlastulaPoolSecondarySocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400866 } catch (IOException ioe) {
867 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
868 }
Chris Wailesefce9292019-01-11 13:19:20 -0800869
Mathew Inwood8faeab82018-03-16 14:26:08 +0000870 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100871 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400872 }
873
874 if (secondaryZygoteState.matches(abi)) {
875 return secondaryZygoteState;
876 }
877
878 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
879 }
Robert Sesekded20982016-08-15 13:59:13 -0400880
881 /**
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100882 * Instructs the zygote to pre-load the application code for the given Application.
883 * Only the app zygote supports this function.
884 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
885 */
886 public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
887 IOException {
888 synchronized (mLock) {
889 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800890 state.mZygoteOutputWriter.write("2");
891 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100892
Chris Wailesefce9292019-01-11 13:19:20 -0800893 state.mZygoteOutputWriter.write("--preload-app");
894 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100895
896 // Zygote args needs to be strings, so in order to pass ApplicationInfo,
897 // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
898 Parcel parcel = Parcel.obtain();
899 appInfo.writeToParcel(parcel, 0 /* flags */);
900 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
901 parcel.recycle();
Chris Wailesefce9292019-01-11 13:19:20 -0800902 state.mZygoteOutputWriter.write(encodedParcelData);
903 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100904
Chris Wailesefce9292019-01-11 13:19:20 -0800905 state.mZygoteOutputWriter.flush();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100906
Chris Wailesefce9292019-01-11 13:19:20 -0800907 return (state.mZygoteInputStream.readInt() == 0);
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100908 }
909 }
910
911 /**
Robert Sesekded20982016-08-15 13:59:13 -0400912 * Instructs the zygote to pre-load the classes and native libraries at the given paths
913 * for the specified abi. Not all zygotes support this function.
914 */
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500915 public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
916 String cacheKey, String abi) throws ZygoteStartFailedEx,
917 IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400918 synchronized(mLock) {
919 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800920 state.mZygoteOutputWriter.write("5");
921 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400922
Chris Wailesefce9292019-01-11 13:19:20 -0800923 state.mZygoteOutputWriter.write("--preload-package");
924 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400925
Chris Wailesefce9292019-01-11 13:19:20 -0800926 state.mZygoteOutputWriter.write(packagePath);
927 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400928
Chris Wailesefce9292019-01-11 13:19:20 -0800929 state.mZygoteOutputWriter.write(libsPath);
930 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400931
Chris Wailesefce9292019-01-11 13:19:20 -0800932 state.mZygoteOutputWriter.write(libFileName);
933 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500934
Chris Wailesefce9292019-01-11 13:19:20 -0800935 state.mZygoteOutputWriter.write(cacheKey);
936 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000937
Chris Wailesefce9292019-01-11 13:19:20 -0800938 state.mZygoteOutputWriter.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100939
Chris Wailesefce9292019-01-11 13:19:20 -0800940 return (state.mZygoteInputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400941 }
942 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000943
944 /**
945 * Instructs the zygote to preload the default set of classes and resources. Returns
946 * {@code true} if a preload was performed as a result of this call, and {@code false}
947 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
948 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
949 */
950 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
951 synchronized (mLock) {
952 ZygoteState state = openZygoteSocketIfNeeded(abi);
953 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800954 state.mZygoteOutputWriter.write("1");
955 state.mZygoteOutputWriter.newLine();
956 state.mZygoteOutputWriter.write("--preload-default");
957 state.mZygoteOutputWriter.newLine();
958 state.mZygoteOutputWriter.flush();
Narayan Kamath669afcc2017-02-06 20:24:08 +0000959
Chris Wailesefce9292019-01-11 13:19:20 -0800960 return (state.mZygoteInputStream.readInt() == 0);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000961 }
962 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100963
964 /**
965 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800966 * @param zygoteSocketName The name of the socket to connect to.
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100967 */
Chris Wailesefce9292019-01-11 13:19:20 -0800968 public static void waitForConnectionToZygote(String zygoteSocketName) {
969 final LocalSocketAddress zygoteSocketAddress =
970 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
971 waitForConnectionToZygote(zygoteSocketAddress);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500972 }
973
974 /**
975 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800976 * @param zygoteSocketAddress The name of the socket to connect to.
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500977 */
Chris Wailesefce9292019-01-11 13:19:20 -0800978 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
Martijn Coenen82dc85a2019-01-28 13:12:28 +0100979 int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS;
980 for (int n = numRetries; n >= 0; n--) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100981 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800982 final ZygoteState zs =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800983 ZygoteState.connect(zygoteSocketAddress, null);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100984 zs.close();
985 return;
986 } catch (IOException ioe) {
987 Log.w(LOG_TAG,
988 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
989 }
990
991 try {
Martijn Coenen82dc85a2019-01-28 13:12:28 +0100992 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100993 } catch (InterruptedException ie) {
994 }
995 }
Chris Wailesefce9292019-01-11 13:19:20 -0800996 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
997 + zygoteSocketAddress.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100998 }
Robert Sesekd0a190df2018-02-12 18:46:01 -0500999
1000 /**
1001 * Starts a new zygote process as a child of this zygote. This is used to create
1002 * secondary zygotes that inherit data from the zygote that this object
1003 * communicates with. This returns a new ZygoteProcess representing a connection
1004 * to the newly created zygote. Throws an exception if the zygote cannot be started.
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001005 *
1006 * @param processClass The class to use as the child zygote's main entry
1007 * point.
1008 * @param niceName A more readable name to use for the process.
1009 * @param uid The user-id under which the child zygote will run.
1010 * @param gid The group-id under which the child zygote will run.
1011 * @param gids Additional group-ids associated with the child zygote process.
1012 * @param runtimeFlags Additional flags.
1013 * @param seInfo null-ok SELinux information for the child zygote process.
1014 * @param abi non-null the ABI of the child zygote
1015 * @param acceptedAbiList ABIs this child zygote will accept connections for; this
1016 * may be different from <code>abi</code> in case the children
1017 * spawned from this Zygote only communicate using ABI-safe methods.
1018 * @param instructionSet null-ok the instruction set to use.
Martijn Coenen86f08a52019-01-03 16:23:01 +01001019 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
1020 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
Robert Sesekd0a190df2018-02-12 18:46:01 -05001021 */
1022 public ChildZygoteProcess startChildZygote(final String processClass,
1023 final String niceName,
1024 int uid, int gid, int[] gids,
1025 int runtimeFlags,
1026 String seInfo,
1027 String abi,
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001028 String acceptedAbiList,
Martijn Coenen86f08a52019-01-03 16:23:01 +01001029 String instructionSet,
1030 int uidRangeStart,
1031 int uidRangeEnd) {
Robert Sesekd0a190df2018-02-12 18:46:01 -05001032 // Create an unguessable address in the global abstract namespace.
1033 final LocalSocketAddress serverAddress = new LocalSocketAddress(
1034 processClass + "/" + UUID.randomUUID().toString());
1035
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001036 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
Martijn Coenen86f08a52019-01-03 16:23:01 +01001037 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
1038 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
1039 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
Robert Sesekd0a190df2018-02-12 18:46:01 -05001040
1041 Process.ProcessStartResult result;
1042 try {
1043 result = startViaZygote(processClass, niceName, uid, gid,
1044 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
1045 abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001046 true /* startChildZygote */, null /* packageName */,
Sudheer Shankae51005d2019-02-24 10:24:09 -08001047 null /* packagesForUid */, null /* sandboxId */,
Chris Wailesba4c2eb2019-01-11 17:13:00 -08001048 false /* useBlastulaPool */, extraArgs);
Robert Sesekd0a190df2018-02-12 18:46:01 -05001049 } catch (ZygoteStartFailedEx ex) {
1050 throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
1051 }
1052
1053 return new ChildZygoteProcess(serverAddress, result.pid);
1054 }
Robert Sesek8f8d1872016-03-18 16:52:57 -04001055}