blob: de378b0cd1bfd1f100a02242e0b3d813727cd053 [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.
308 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400309 * @param zygoteArgs Additional arguments to supply to the zygote process.
310 *
311 * @return An object that describes the result of the attempt to start the process.
312 * @throws RuntimeException on fatal start failure
313 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700314 public final Process.ProcessStartResult start(@NonNull final String processClass,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400315 final String niceName,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700316 int uid, int gid, @Nullable int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100317 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400318 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700319 @Nullable String seInfo,
320 @NonNull String abi,
321 @Nullable String instructionSet,
322 @Nullable String appDataDir,
323 @Nullable String invokeWith,
324 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700325 @Nullable String[] packagesForUid,
326 @Nullable String[] visibleVols,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800327 @Nullable String sandboxId,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800328 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700329 @Nullable String[] zygoteArgs) {
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800330 if (fetchBlastulaPoolEnabledProp()) {
331 // TODO (chriswailes): Send the appropriate command to the zygotes
332 Log.i(LOG_TAG, "Blastula pool enabled property set to: " + mBlastulaPoolEnabled);
333
334 // This can't be enabled yet, but we do want to test this code path.
335 mBlastulaPoolEnabled = false;
336 }
337
Robert Sesek8f8d1872016-03-18 16:52:57 -0400338 try {
339 return startViaZygote(processClass, niceName, uid, gid, gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100340 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
Chris Wailesefce9292019-01-11 13:19:20 -0800341 abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800342 packageName, packagesForUid, visibleVols, sandboxId,
343 useBlastulaPool, zygoteArgs);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400344 } catch (ZygoteStartFailedEx ex) {
345 Log.e(LOG_TAG,
346 "Starting VM process through Zygote failed");
347 throw new RuntimeException(
348 "Starting VM process through Zygote failed", ex);
349 }
350 }
351
352 /** retry interval for opening a zygote socket */
353 static final int ZYGOTE_RETRY_MILLIS = 500;
354
355 /**
356 * Queries the zygote for the list of ABIS it supports.
357 *
358 * @throws ZygoteStartFailedEx if the query failed.
359 */
Robert Sesekded20982016-08-15 13:59:13 -0400360 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800361 private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400362 throws IOException {
363 // Each query starts with the argument count (1 in this case)
364 writer.write("1");
365 // ... followed by a new-line.
366 writer.newLine();
367 // ... followed by our only argument.
368 writer.write("--query-abi-list");
369 writer.newLine();
370 writer.flush();
371
372 // The response is a length prefixed stream of ASCII bytes.
373 int numBytes = inputStream.readInt();
374 byte[] bytes = new byte[numBytes];
375 inputStream.readFully(bytes);
376
Chris Wailesefce9292019-01-11 13:19:20 -0800377 String rawList = new String(bytes, StandardCharsets.US_ASCII);
378
379 return Arrays.asList(rawList.split(","));
Robert Sesek8f8d1872016-03-18 16:52:57 -0400380 }
381
382 /**
383 * Sends an argument list to the zygote process, which starts a new child
384 * and returns the child's pid. Please note: the present implementation
385 * replaces newlines in the argument list with spaces.
386 *
387 * @throws ZygoteStartFailedEx if process start failed for any reason
388 */
Robert Sesekded20982016-08-15 13:59:13 -0400389 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400390 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800391 ZygoteState zygoteState, boolean useBlastulaPool, ArrayList<String> args)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400392 throws ZygoteStartFailedEx {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800393 // Throw early if any of the arguments are malformed. This means we can
394 // avoid writing a partial response to the zygote.
395 for (String arg : args) {
396 if (arg.indexOf('\n') >= 0) {
397 throw new ZygoteStartFailedEx("embedded newlines not allowed");
398 }
399 }
400
Chris Wailesb13bfc52019-02-20 11:19:48 -0800401 /*
402 * See com.android.internal.os.ZygoteArguments.parseArgs()
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800403 * Presently the wire format to the zygote process is:
404 * a) a count of arguments (argc, in essence)
405 * b) a number of newline-separated argument strings equal to count
406 *
407 * After the zygote process reads these it will write the pid of
408 * the child or -1 on failure, followed by boolean to
409 * indicate whether a wrapper process was used.
410 */
411 String msgStr = Integer.toString(args.size()) + "\n"
412 + String.join("\n", args) + "\n";
413
414 // Should there be a timeout on this?
415 Process.ProcessStartResult result = new Process.ProcessStartResult();
416
417 // TODO (chriswailes): Move branch body into separate function.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800418 if (useBlastulaPool && isValidBlastulaCommand(args)) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800419 LocalSocket blastulaSessionSocket = null;
420
421 try {
422 blastulaSessionSocket = zygoteState.getBlastulaSessionSocket();
423
424 final BufferedWriter blastulaWriter =
425 new BufferedWriter(
426 new OutputStreamWriter(blastulaSessionSocket.getOutputStream()),
427 Zygote.SOCKET_BUFFER_SIZE);
428 final DataInputStream blastulaReader =
429 new DataInputStream(blastulaSessionSocket.getInputStream());
430
431 blastulaWriter.write(msgStr);
432 blastulaWriter.flush();
433
434 result.pid = blastulaReader.readInt();
435 // Blastulas can't be used to spawn processes that need wrappers.
436 result.usingWrapper = false;
437
438 if (result.pid < 0) {
439 throw new ZygoteStartFailedEx("Blastula specialization failed");
440 }
441
442 return result;
443 } catch (IOException ex) {
444 // If there was an IOException using the blastula pool we will log the error and
445 // attempt to start the process through the Zygote.
446 Log.e(LOG_TAG, "IO Exception while communicating with blastula pool - "
447 + ex.toString());
448 } finally {
449 try {
450 blastulaSessionSocket.close();
451 } catch (IOException ex) {
452 Log.e(LOG_TAG, "Failed to close blastula session socket: " + ex.getMessage());
Robert Sesek0b58f192016-10-10 18:34:42 -0400453 }
454 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800455 }
Robert Sesek0b58f192016-10-10 18:34:42 -0400456
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800457 try {
458 final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
459 final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400460
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800461 zygoteWriter.write(msgStr);
462 zygoteWriter.flush();
Robert Sesek0b58f192016-10-10 18:34:42 -0400463
464 // Always read the entire result from the input stream to avoid leaving
465 // bytes in the stream for future process starts to accidentally stumble
466 // upon.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800467 result.pid = zygoteInputStream.readInt();
468 result.usingWrapper = zygoteInputStream.readBoolean();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400469 } catch (IOException ex) {
470 zygoteState.close();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800471 Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
472 + ex.toString());
Robert Sesek8f8d1872016-03-18 16:52:57 -0400473 throw new ZygoteStartFailedEx(ex);
474 }
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800475
476 if (result.pid < 0) {
477 throw new ZygoteStartFailedEx("fork() failed");
478 }
479
480 return result;
481 }
482
483 /**
484 * Flags that may not be passed to a blastula.
485 */
486 private static final String[] INVALID_BLASTULA_FLAGS = {
487 "--query-abi-list",
488 "--get-pid",
489 "--preload-default",
490 "--preload-package",
491 "--preload-app",
492 "--start-child-zygote",
493 "--set-api-blacklist-exemptions",
494 "--hidden-api-log-sampling-rate",
495 "--invoke-with"
496 };
497
498 /**
499 * Tests a command list to see if it is valid to send to a blastula.
500 * @param args Zygote/Blastula command arguments
501 * @return True if the command can be passed to a blastula; false otherwise
502 */
503 private static boolean isValidBlastulaCommand(ArrayList<String> args) {
504 for (String flag : args) {
505 for (String badFlag : INVALID_BLASTULA_FLAGS) {
506 if (flag.startsWith(badFlag)) {
507 return false;
508 }
509 }
510 }
511
512 return true;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400513 }
514
515 /**
516 * Starts a new process via the zygote mechanism.
517 *
518 * @param processClass Class name whose static main() to run
519 * @param niceName 'nice' process name to appear in ps
520 * @param uid a POSIX uid that the new process should setuid() to
521 * @param gid a POSIX gid that the new process shuold setgid() to
522 * @param gids null-ok; a list of supplementary group IDs that the
523 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100524 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400525 * @param targetSdkVersion The target SDK version for the app.
526 * @param seInfo null-ok SELinux information for the new process.
527 * @param abi the ABI the process should use.
528 * @param instructionSet null-ok the instruction set to use.
529 * @param appDataDir null-ok the data directory of the app.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500530 * @param startChildZygote Start a sub-zygote. This creates a new zygote process
531 * that has its state cloned from this zygote process.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700532 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700533 * @param packagesForUid null-ok all the packages with the same uid as this process.
534 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400535 * @param extraArgs Additional arguments to supply to the zygote process.
536 * @return An object that describes the result of the attempt to start the process.
537 * @throws ZygoteStartFailedEx if process start failed for any reason
538 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700539 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
540 @Nullable final String niceName,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400541 final int uid, final int gid,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700542 @Nullable final int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100543 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400544 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700545 @Nullable String seInfo,
546 @NonNull String abi,
547 @Nullable String instructionSet,
548 @Nullable String appDataDir,
549 @Nullable String invokeWith,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500550 boolean startChildZygote,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700551 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700552 @Nullable String[] packagesForUid,
553 @Nullable String[] visibleVols,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800554 @Nullable String sandboxId,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800555 boolean useBlastulaPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700556 @Nullable String[] extraArgs)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400557 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400558 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400559
Robert Sesekded20982016-08-15 13:59:13 -0400560 // --runtime-args, --setuid=, --setgid=,
561 // and --setgroups= must go first
562 argsForZygote.add("--runtime-args");
563 argsForZygote.add("--setuid=" + uid);
564 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100565 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400566 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
567 argsForZygote.add("--mount-external-default");
568 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
569 argsForZygote.add("--mount-external-read");
570 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
571 argsForZygote.add("--mount-external-write");
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700572 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
573 argsForZygote.add("--mount-external-full");
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800574 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
575 argsForZygote.add("--mount-external-installer");
Sudheer Shanka0b6da532019-01-09 12:06:51 -0800576 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
577 argsForZygote.add("--mount-external-legacy");
Robert Sesekded20982016-08-15 13:59:13 -0400578 }
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700579
Robert Sesekded20982016-08-15 13:59:13 -0400580 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400581
Robert Sesekded20982016-08-15 13:59:13 -0400582 // --setgroups is a comma-separated list
583 if (gids != null && gids.length > 0) {
584 StringBuilder sb = new StringBuilder();
585 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400586
Robert Sesekded20982016-08-15 13:59:13 -0400587 int sz = gids.length;
588 for (int i = 0; i < sz; i++) {
589 if (i != 0) {
590 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400591 }
Robert Sesekded20982016-08-15 13:59:13 -0400592 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400593 }
594
Robert Sesekded20982016-08-15 13:59:13 -0400595 argsForZygote.add(sb.toString());
596 }
597
598 if (niceName != null) {
599 argsForZygote.add("--nice-name=" + niceName);
600 }
601
602 if (seInfo != null) {
603 argsForZygote.add("--seinfo=" + seInfo);
604 }
605
606 if (instructionSet != null) {
607 argsForZygote.add("--instruction-set=" + instructionSet);
608 }
609
610 if (appDataDir != null) {
611 argsForZygote.add("--app-data-dir=" + appDataDir);
612 }
613
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000614 if (invokeWith != null) {
615 argsForZygote.add("--invoke-with");
616 argsForZygote.add(invokeWith);
617 }
618
Robert Sesekd0a190df2018-02-12 18:46:01 -0500619 if (startChildZygote) {
620 argsForZygote.add("--start-child-zygote");
621 }
622
Sudheer Shanka154fe3f2018-07-30 14:44:26 -0700623 if (packageName != null) {
624 argsForZygote.add("--package-name=" + packageName);
625 }
626
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700627 if (packagesForUid != null && packagesForUid.length > 0) {
628 final StringBuilder sb = new StringBuilder();
629 sb.append("--packages-for-uid=");
630
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800631 // TODO (chriswailes): Replace with String.join
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700632 for (int i = 0; i < packagesForUid.length; ++i) {
633 if (i != 0) {
634 sb.append(',');
635 }
636 sb.append(packagesForUid[i]);
637 }
638 argsForZygote.add(sb.toString());
639 }
640
641 if (visibleVols != null && visibleVols.length > 0) {
642 final StringBuilder sb = new StringBuilder();
643 sb.append("--visible-vols=");
644
645 for (int i = 0; i < visibleVols.length; ++i) {
646 if (i != 0) {
647 sb.append(',');
648 }
649 sb.append(visibleVols[i]);
650 }
651 argsForZygote.add(sb.toString());
652 }
653
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800654 if (sandboxId != null) {
655 argsForZygote.add("--sandbox-id=" + sandboxId);
656 }
657
Robert Sesekded20982016-08-15 13:59:13 -0400658 argsForZygote.add(processClass);
659
660 if (extraArgs != null) {
661 for (String arg : extraArgs) {
662 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400663 }
Robert Sesekded20982016-08-15 13:59:13 -0400664 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400665
Robert Sesekded20982016-08-15 13:59:13 -0400666 synchronized(mLock) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800667 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800668 useBlastulaPool && mBlastulaPoolEnabled,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800669 argsForZygote);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400670 }
671 }
672
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800673 private boolean fetchBlastulaPoolEnabledProp() {
674 boolean origVal = mBlastulaPoolEnabled;
675
676 final String propertyString =
677 Zygote.getSystemProperty(
678 DeviceConfig.RuntimeNative.BLASTULA_POOL_ENABLED,
679 BLASTULA_POOL_ENABLED_DEFAULT);
680
681 if (!propertyString.isEmpty()) {
682 mBlastulaPoolEnabled =
683 Zygote.getSystemPropertyBoolean(
684 DeviceConfig.RuntimeNative.BLASTULA_POOL_ENABLED,
685 Boolean.parseBoolean(BLASTULA_POOL_ENABLED_DEFAULT));
686 }
687
688 return origVal != mBlastulaPoolEnabled;
689 }
690
691 private long mLastPropCheckTimestamp = 0;
692
693 private boolean fetchBlastulaPoolEnabledPropWithMinInterval() {
694 final long currentTimestamp = SystemClock.elapsedRealtime();
695
696 if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
697 mLastPropCheckTimestamp = currentTimestamp;
698 return fetchBlastulaPoolEnabledProp();
699 }
700
701 return false;
702 }
703
Robert Sesek8f8d1872016-03-18 16:52:57 -0400704 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500705 * Closes the connections to the zygote, if they exist.
706 */
707 public void close() {
708 if (primaryZygoteState != null) {
709 primaryZygoteState.close();
710 }
711 if (secondaryZygoteState != null) {
712 secondaryZygoteState.close();
713 }
714 }
715
716 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400717 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
718 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
719 * already open.
720 */
721 public void establishZygoteConnectionForAbi(String abi) {
722 try {
Robert Sesekded20982016-08-15 13:59:13 -0400723 synchronized(mLock) {
724 openZygoteSocketIfNeeded(abi);
725 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400726 } catch (ZygoteStartFailedEx ex) {
727 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
728 }
729 }
730
731 /**
Andreas Gampe8444dca2018-05-01 13:31:28 -0700732 * Attempt to retrieve the PID of the zygote serving the given abi.
733 */
734 public int getZygotePid(String abi) {
735 try {
736 synchronized (mLock) {
737 ZygoteState state = openZygoteSocketIfNeeded(abi);
738
739 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800740 state.mZygoteOutputWriter.write("1");
Andreas Gampe8444dca2018-05-01 13:31:28 -0700741 // ... followed by a new-line.
Chris Wailesefce9292019-01-11 13:19:20 -0800742 state.mZygoteOutputWriter.newLine();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700743 // ... followed by our only argument.
Chris Wailesefce9292019-01-11 13:19:20 -0800744 state.mZygoteOutputWriter.write("--get-pid");
745 state.mZygoteOutputWriter.newLine();
746 state.mZygoteOutputWriter.flush();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700747
748 // The response is a length prefixed stream of ASCII bytes.
Chris Wailesefce9292019-01-11 13:19:20 -0800749 int numBytes = state.mZygoteInputStream.readInt();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700750 byte[] bytes = new byte[numBytes];
Chris Wailesefce9292019-01-11 13:19:20 -0800751 state.mZygoteInputStream.readFully(bytes);
Andreas Gampe8444dca2018-05-01 13:31:28 -0700752
753 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
754 }
755 } catch (Exception ex) {
756 throw new RuntimeException("Failure retrieving pid", ex);
757 }
758 }
759
760 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000761 * Push hidden API blacklisting exemptions into the zygote process(es).
762 *
763 * <p>The list of exemptions will take affect for all new processes forked from the zygote after
764 * this call.
765 *
Mathew Inwood33d51382018-04-05 13:56:39 +0100766 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
767 * whitelisted/public APIs (i.e. allowed, no logging of usage).
Mathew Inwood8faeab82018-03-16 14:26:08 +0000768 */
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100769 public boolean setApiBlacklistExemptions(List<String> exemptions) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000770 synchronized (mLock) {
771 mApiBlacklistExemptions = exemptions;
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100772 boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
773 if (ok) {
774 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
775 }
776 return ok;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000777 }
778 }
779
Mathew Inwood04194fe2018-04-04 14:48:03 +0100780 /**
781 * Set the precentage of detected hidden API accesses that are logged to the event log.
782 *
783 * <p>This rate will take affect for all new processes forked from the zygote after this call.
784 *
785 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
786 */
787 public void setHiddenApiAccessLogSampleRate(int rate) {
788 synchronized (mLock) {
789 mHiddenApiAccessLogSampleRate = rate;
790 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
791 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
792 }
793 }
794
Mathew Inwood8faeab82018-03-16 14:26:08 +0000795 @GuardedBy("mLock")
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100796 private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000797 if (state == null || state.isClosed()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100798 Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
799 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000800 }
801 if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100802 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000803 }
804 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800805 state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
806 state.mZygoteOutputWriter.newLine();
807 state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
808 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000809 for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
Chris Wailesefce9292019-01-11 13:19:20 -0800810 state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
811 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000812 }
Chris Wailesefce9292019-01-11 13:19:20 -0800813 state.mZygoteOutputWriter.flush();
814 int status = state.mZygoteInputStream.readInt();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000815 if (status != 0) {
816 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
817 }
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100818 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000819 } catch (IOException ioe) {
820 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100821 mApiBlacklistExemptions = Collections.emptyList();
822 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000823 }
824 }
825
Mathew Inwood04194fe2018-04-04 14:48:03 +0100826 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
827 if (state == null || state.isClosed()) {
828 return;
829 }
830 if (mHiddenApiAccessLogSampleRate == -1) {
831 return;
832 }
833 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800834 state.mZygoteOutputWriter.write(Integer.toString(1));
835 state.mZygoteOutputWriter.newLine();
836 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
Mathew Inwood04194fe2018-04-04 14:48:03 +0100837 + Integer.toString(mHiddenApiAccessLogSampleRate));
Chris Wailesefce9292019-01-11 13:19:20 -0800838 state.mZygoteOutputWriter.newLine();
839 state.mZygoteOutputWriter.flush();
840 int status = state.mZygoteInputStream.readInt();
Mathew Inwood04194fe2018-04-04 14:48:03 +0100841 if (status != 0) {
842 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
843 }
844 } catch (IOException ioe) {
845 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
846 }
847 }
848
Mathew Inwood8faeab82018-03-16 14:26:08 +0000849 /**
Chris Wailesefce9292019-01-11 13:19:20 -0800850 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
851 * already open. If a compatible session socket is already open that session socket is returned.
852 * This function may block and may have to try connecting to multiple Zygotes to find the
853 * appropriate one. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400854 */
Robert Sesekded20982016-08-15 13:59:13 -0400855 @GuardedBy("mLock")
Chris Wailesefce9292019-01-11 13:19:20 -0800856 private ZygoteState openZygoteSocketIfNeeded(String abi)
857 throws ZygoteStartFailedEx {
858
Robert Sesekded20982016-08-15 13:59:13 -0400859 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
860
Robert Sesek8f8d1872016-03-18 16:52:57 -0400861 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
862 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800863 primaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800864 ZygoteState.connect(mZygoteSocketAddress, mBlastulaPoolSocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400865 } catch (IOException ioe) {
866 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
867 }
Chris Wailesefce9292019-01-11 13:19:20 -0800868
Mathew Inwood8faeab82018-03-16 14:26:08 +0000869 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100870 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400871 }
Chris Wailesefce9292019-01-11 13:19:20 -0800872
Robert Sesek8f8d1872016-03-18 16:52:57 -0400873 if (primaryZygoteState.matches(abi)) {
874 return primaryZygoteState;
875 }
876
877 // The primary zygote didn't match. Try the secondary.
878 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
879 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800880 secondaryZygoteState =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800881 ZygoteState.connect(mZygoteSecondarySocketAddress,
882 mBlastulaPoolSecondarySocketAddress);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400883 } catch (IOException ioe) {
884 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
885 }
Chris Wailesefce9292019-01-11 13:19:20 -0800886
Mathew Inwood8faeab82018-03-16 14:26:08 +0000887 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100888 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400889 }
890
891 if (secondaryZygoteState.matches(abi)) {
892 return secondaryZygoteState;
893 }
894
895 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
896 }
Robert Sesekded20982016-08-15 13:59:13 -0400897
898 /**
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100899 * Instructs the zygote to pre-load the application code for the given Application.
900 * Only the app zygote supports this function.
901 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
902 */
903 public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
904 IOException {
905 synchronized (mLock) {
906 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800907 state.mZygoteOutputWriter.write("2");
908 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100909
Chris Wailesefce9292019-01-11 13:19:20 -0800910 state.mZygoteOutputWriter.write("--preload-app");
911 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100912
913 // Zygote args needs to be strings, so in order to pass ApplicationInfo,
914 // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
915 Parcel parcel = Parcel.obtain();
916 appInfo.writeToParcel(parcel, 0 /* flags */);
917 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
918 parcel.recycle();
Chris Wailesefce9292019-01-11 13:19:20 -0800919 state.mZygoteOutputWriter.write(encodedParcelData);
920 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100921
Chris Wailesefce9292019-01-11 13:19:20 -0800922 state.mZygoteOutputWriter.flush();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100923
Chris Wailesefce9292019-01-11 13:19:20 -0800924 return (state.mZygoteInputStream.readInt() == 0);
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100925 }
926 }
927
928 /**
Robert Sesekded20982016-08-15 13:59:13 -0400929 * Instructs the zygote to pre-load the classes and native libraries at the given paths
930 * for the specified abi. Not all zygotes support this function.
931 */
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500932 public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
933 String cacheKey, String abi) throws ZygoteStartFailedEx,
934 IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400935 synchronized(mLock) {
936 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800937 state.mZygoteOutputWriter.write("5");
938 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400939
Chris Wailesefce9292019-01-11 13:19:20 -0800940 state.mZygoteOutputWriter.write("--preload-package");
941 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400942
Chris Wailesefce9292019-01-11 13:19:20 -0800943 state.mZygoteOutputWriter.write(packagePath);
944 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400945
Chris Wailesefce9292019-01-11 13:19:20 -0800946 state.mZygoteOutputWriter.write(libsPath);
947 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400948
Chris Wailesefce9292019-01-11 13:19:20 -0800949 state.mZygoteOutputWriter.write(libFileName);
950 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500951
Chris Wailesefce9292019-01-11 13:19:20 -0800952 state.mZygoteOutputWriter.write(cacheKey);
953 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000954
Chris Wailesefce9292019-01-11 13:19:20 -0800955 state.mZygoteOutputWriter.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100956
Chris Wailesefce9292019-01-11 13:19:20 -0800957 return (state.mZygoteInputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400958 }
959 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000960
961 /**
962 * Instructs the zygote to preload the default set of classes and resources. Returns
963 * {@code true} if a preload was performed as a result of this call, and {@code false}
964 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
965 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
966 */
967 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
968 synchronized (mLock) {
969 ZygoteState state = openZygoteSocketIfNeeded(abi);
970 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800971 state.mZygoteOutputWriter.write("1");
972 state.mZygoteOutputWriter.newLine();
973 state.mZygoteOutputWriter.write("--preload-default");
974 state.mZygoteOutputWriter.newLine();
975 state.mZygoteOutputWriter.flush();
Narayan Kamath669afcc2017-02-06 20:24:08 +0000976
Chris Wailesefce9292019-01-11 13:19:20 -0800977 return (state.mZygoteInputStream.readInt() == 0);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000978 }
979 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100980
981 /**
982 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800983 * @param zygoteSocketName The name of the socket to connect to.
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100984 */
Chris Wailesefce9292019-01-11 13:19:20 -0800985 public static void waitForConnectionToZygote(String zygoteSocketName) {
986 final LocalSocketAddress zygoteSocketAddress =
987 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
988 waitForConnectionToZygote(zygoteSocketAddress);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500989 }
990
991 /**
992 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800993 * @param zygoteSocketAddress The name of the socket to connect to.
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500994 */
Chris Wailesefce9292019-01-11 13:19:20 -0800995 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
Martijn Coenen82dc85a2019-01-28 13:12:28 +0100996 int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS;
997 for (int n = numRetries; n >= 0; n--) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100998 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800999 final ZygoteState zs =
Chris Wailesba4c2eb2019-01-11 17:13:00 -08001000 ZygoteState.connect(zygoteSocketAddress, null);
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001001 zs.close();
1002 return;
1003 } catch (IOException ioe) {
1004 Log.w(LOG_TAG,
1005 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
1006 }
1007
1008 try {
Martijn Coenen82dc85a2019-01-28 13:12:28 +01001009 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001010 } catch (InterruptedException ie) {
1011 }
1012 }
Chris Wailesefce9292019-01-11 13:19:20 -08001013 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
1014 + zygoteSocketAddress.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001015 }
Robert Sesekd0a190df2018-02-12 18:46:01 -05001016
1017 /**
1018 * Starts a new zygote process as a child of this zygote. This is used to create
1019 * secondary zygotes that inherit data from the zygote that this object
1020 * communicates with. This returns a new ZygoteProcess representing a connection
1021 * to the newly created zygote. Throws an exception if the zygote cannot be started.
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001022 *
1023 * @param processClass The class to use as the child zygote's main entry
1024 * point.
1025 * @param niceName A more readable name to use for the process.
1026 * @param uid The user-id under which the child zygote will run.
1027 * @param gid The group-id under which the child zygote will run.
1028 * @param gids Additional group-ids associated with the child zygote process.
1029 * @param runtimeFlags Additional flags.
1030 * @param seInfo null-ok SELinux information for the child zygote process.
1031 * @param abi non-null the ABI of the child zygote
1032 * @param acceptedAbiList ABIs this child zygote will accept connections for; this
1033 * may be different from <code>abi</code> in case the children
1034 * spawned from this Zygote only communicate using ABI-safe methods.
1035 * @param instructionSet null-ok the instruction set to use.
Martijn Coenen86f08a52019-01-03 16:23:01 +01001036 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
1037 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
Robert Sesekd0a190df2018-02-12 18:46:01 -05001038 */
1039 public ChildZygoteProcess startChildZygote(final String processClass,
1040 final String niceName,
1041 int uid, int gid, int[] gids,
1042 int runtimeFlags,
1043 String seInfo,
1044 String abi,
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001045 String acceptedAbiList,
Martijn Coenen86f08a52019-01-03 16:23:01 +01001046 String instructionSet,
1047 int uidRangeStart,
1048 int uidRangeEnd) {
Robert Sesekd0a190df2018-02-12 18:46:01 -05001049 // Create an unguessable address in the global abstract namespace.
1050 final LocalSocketAddress serverAddress = new LocalSocketAddress(
1051 processClass + "/" + UUID.randomUUID().toString());
1052
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001053 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
Martijn Coenen86f08a52019-01-03 16:23:01 +01001054 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
1055 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
1056 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
Robert Sesekd0a190df2018-02-12 18:46:01 -05001057
1058 Process.ProcessStartResult result;
1059 try {
1060 result = startViaZygote(processClass, niceName, uid, gid,
1061 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
1062 abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001063 true /* startChildZygote */, null /* packageName */,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -08001064 null /* packagesForUid */, null /* visibleVolumes */, null /* sandboxId */,
Chris Wailesba4c2eb2019-01-11 17:13:00 -08001065 false /* useBlastulaPool */, extraArgs);
Robert Sesekd0a190df2018-02-12 18:46:01 -05001066 } catch (ZygoteStartFailedEx ex) {
1067 throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
1068 }
1069
1070 return new ChildZygoteProcess(serverAddress, result.pid);
1071 }
Robert Sesek8f8d1872016-03-18 16:52:57 -04001072}