blob: 60f4f06c96178769f7e1d82c7654870b57a0c3e6 [file] [log] [blame]
Robert Sesek8f8d1872016-03-18 16:52:57 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
18
Sudheer Shankad81b1d72018-09-05 16:37:30 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010021import android.content.pm.ApplicationInfo;
Robert Sesek8f8d1872016-03-18 16:52:57 -040022import android.net.LocalSocket;
23import android.net.LocalSocketAddress;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080024import android.provider.DeviceConfig;
Robert Sesek8f8d1872016-03-18 16:52:57 -040025import android.util.Log;
Gustav Senntonf0c52b52017-04-27 17:00:50 +010026import android.util.Slog;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010027
Robert Sesekded20982016-08-15 13:59:13 -040028import com.android.internal.annotations.GuardedBy;
Robert Sesek8f8d1872016-03-18 16:52:57 -040029import com.android.internal.os.Zygote;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010030
Robert Sesek8f8d1872016-03-18 16:52:57 -040031import java.io.BufferedWriter;
32import java.io.DataInputStream;
33import java.io.IOException;
34import java.io.OutputStreamWriter;
35import java.nio.charset.StandardCharsets;
36import java.util.ArrayList;
37import java.util.Arrays;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010038import java.util.Base64;
Mathew Inwood8faeab82018-03-16 14:26:08 +000039import java.util.Collections;
Robert Sesek8f8d1872016-03-18 16:52:57 -040040import java.util.List;
Robert Sesekd0a190df2018-02-12 18:46:01 -050041import java.util.UUID;
Robert Sesek8f8d1872016-03-18 16:52:57 -040042
43/*package*/ class ZygoteStartFailedEx extends Exception {
44 ZygoteStartFailedEx(String s) {
45 super(s);
46 }
47
48 ZygoteStartFailedEx(Throwable cause) {
49 super(cause);
50 }
51
52 ZygoteStartFailedEx(String s, Throwable cause) {
53 super(s, cause);
54 }
55}
56
57/**
58 * Maintains communication state with the zygote processes. This class is responsible
59 * for the sockets opened to the zygotes and for starting processes on behalf of the
60 * {@link android.os.Process} class.
61 *
62 * {@hide}
63 */
64public class ZygoteProcess {
Chris Wailesefce9292019-01-11 13:19:20 -080065
66 /**
67 * @hide for internal use only.
68 */
Martijn Coenen82dc85a2019-01-28 13:12:28 +010069 public static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
70
71 /**
72 * @hide for internal use only.
73 *
74 * Use a relatively short delay, because for app zygote, this is in the critical path of
75 * service launch.
76 */
77 public static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
78
79 /**
Chris Wailesefce9292019-01-11 13:19:20 -080080 * @hide for internal use only
81 */
Robert Sesek8f8d1872016-03-18 16:52:57 -040082 private static final String LOG_TAG = "ZygoteProcess";
83
84 /**
Chris Wailes7e797b62019-02-22 18:29:22 -080085 * The default value for enabling the unspecialized app process (USAP) pool.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080086 */
Chris Wailes7e797b62019-02-22 18:29:22 -080087 private static final String USAP_POOL_ENABLED_DEFAULT = "false";
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080088
89 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -040090 * The name of the socket used to communicate with the primary zygote.
91 */
Chris Wailesefce9292019-01-11 13:19:20 -080092 private final LocalSocketAddress mZygoteSocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -040093
94 /**
95 * The name of the secondary (alternate ABI) zygote socket.
96 */
Chris Wailesefce9292019-01-11 13:19:20 -080097 private final LocalSocketAddress mZygoteSecondarySocketAddress;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -080098
Chris Wailesba4c2eb2019-01-11 17:13:00 -080099 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800100 * The name of the socket used to communicate with the primary USAP pool.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800101 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800102 private final LocalSocketAddress mUsapPoolSocketAddress;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800103
104 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800105 * The name of the socket used to communicate with the secondary (alternate ABI) USAP pool.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800106 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800107 private final LocalSocketAddress mUsapPoolSecondarySocketAddress;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400108
Chris Wailesefce9292019-01-11 13:19:20 -0800109 public ZygoteProcess() {
110 mZygoteSocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800111 new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME,
112 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesefce9292019-01-11 13:19:20 -0800113 mZygoteSecondarySocketAddress =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800114 new LocalSocketAddress(Zygote.SECONDARY_SOCKET_NAME,
Chris Wailesefce9292019-01-11 13:19:20 -0800115 LocalSocketAddress.Namespace.RESERVED);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800116
Chris Wailes7e797b62019-02-22 18:29:22 -0800117 mUsapPoolSocketAddress =
118 new LocalSocketAddress(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800119 LocalSocketAddress.Namespace.RESERVED);
Chris Wailes7e797b62019-02-22 18:29:22 -0800120 mUsapPoolSecondarySocketAddress =
121 new LocalSocketAddress(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800122 LocalSocketAddress.Namespace.RESERVED);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800123
Chris Wailes7e797b62019-02-22 18:29:22 -0800124 if (fetchUsapPoolEnabledProp()) {
125 informZygotesOfUsapPoolStatus();
Chris Wailesdb132a32019-02-20 10:49:27 -0800126 }
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
Chris Wailes7e797b62019-02-22 18:29:22 -0800134 mUsapPoolSocketAddress = null;
135 mUsapPoolSecondarySocketAddress = 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 Wailes7e797b62019-02-22 18:29:22 -0800147 final LocalSocketAddress mUsapSocketAddress;
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 Wailes7e797b62019-02-22 18:29:22 -0800159 LocalSocketAddress usapSocketAddress,
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 Wailes7e797b62019-02-22 18:29:22 -0800165 this.mUsapSocketAddress = usapSocketAddress;
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
Chris Wailes7e797b62019-02-22 18:29:22 -0800174 * given USAP socket address.
Chris Wailesefce9292019-01-11 13:19:20 -0800175 *
176 * @param zygoteSocketAddress Zygote socket to connect to
Chris Wailes7e797b62019-02-22 18:29:22 -0800177 * @param usapSocketAddress USAP 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,
Chris Wailes7e797b62019-02-22 18:29:22 -0800183 LocalSocketAddress usapSocketAddress)
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 Wailes7e797b62019-02-22 18:29:22 -0800205 return new ZygoteState(zygoteSocketAddress, usapSocketAddress,
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 Wailes7e797b62019-02-22 18:29:22 -0800210 LocalSocket getUsapSessionSocket() throws IOException {
211 final LocalSocket usapSessionSocket = new LocalSocket();
212 usapSessionSocket.connect(this.mUsapSocketAddress);
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800213
Chris Wailes7e797b62019-02-22 18:29:22 -0800214 return usapSessionSocket;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800215 }
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 /**
Andrei Oneae8e150d2019-02-18 18:27:11 +0000256 * Proportion of hidden API accesses that should be logged to statslog; 0 - 0x10000.
257 */
258 private int mHiddenApiAccessStatslogSampleRate;
259
260 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400261 * The state of the connection to the primary zygote.
262 */
263 private ZygoteState primaryZygoteState;
264
265 /**
266 * The state of the connection to the secondary zygote.
267 */
268 private ZygoteState secondaryZygoteState;
269
270 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800271 * If the USAP pool should be created and used to start applications.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800272 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800273 * Setting this value to false will disable the creation, maintenance, and use of the USAP
274 * pool. When the USAP pool is disabled the application lifecycle will be identical to
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800275 * previous versions of Android.
276 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800277 private boolean mUsapPoolEnabled = false;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800278
279 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400280 * Start a new process.
281 *
282 * <p>If processes are enabled, a new process is created and the
283 * static main() function of a <var>processClass</var> is executed there.
284 * The process will continue running after this function returns.
285 *
286 * <p>If processes are not enabled, a new thread in the caller's
Mathew Inwood8faeab82018-03-16 14:26:08 +0000287 * process is created and main() of <var>processclass</var> called there.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400288 *
289 * <p>The niceName parameter, if not an empty string, is a custom name to
290 * give to the process instead of using processClass. This allows you to
291 * make easily identifyable processes even if you are using the same base
292 * <var>processClass</var> to start them.
293 *
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000294 * When invokeWith is not null, the process will be started as a fresh app
Tamas Berghammer0ca16fa2016-11-11 16:08:26 +0000295 * and not a zygote fork. Note that this is only allowed for uid 0 or when
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100296 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000297 *
Robert Sesek8f8d1872016-03-18 16:52:57 -0400298 * @param processClass The class to use as the process's main entry
299 * point.
300 * @param niceName A more readable name to use for the process.
301 * @param uid The user-id under which the process will run.
302 * @param gid The group-id under which the process will run.
303 * @param gids Additional group-ids associated with the process.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100304 * @param runtimeFlags Additional flags.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400305 * @param targetSdkVersion The target SDK version for the app.
306 * @param seInfo null-ok SELinux information for the new process.
307 * @param abi non-null the ABI this app should be started with.
308 * @param instructionSet null-ok the instruction set to use.
309 * @param appDataDir null-ok the data directory of the app.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000310 * @param invokeWith null-ok the command to invoke with.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700311 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700312 * @param packagesForUid null-ok all the packages with the same uid as this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400313 * @param zygoteArgs Additional arguments to supply to the zygote process.
314 *
315 * @return An object that describes the result of the attempt to start the process.
316 * @throws RuntimeException on fatal start failure
317 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700318 public final Process.ProcessStartResult start(@NonNull final String processClass,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400319 final String niceName,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700320 int uid, int gid, @Nullable int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100321 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400322 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700323 @Nullable String seInfo,
324 @NonNull String abi,
325 @Nullable String instructionSet,
326 @Nullable String appDataDir,
327 @Nullable String invokeWith,
328 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700329 @Nullable String[] packagesForUid,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800330 @Nullable String sandboxId,
Chris Wailes7e797b62019-02-22 18:29:22 -0800331 boolean useUsapPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700332 @Nullable String[] zygoteArgs) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800333 // TODO (chriswailes): Is there a better place to check this value?
Chris Wailes7e797b62019-02-22 18:29:22 -0800334 if (fetchUsapPoolEnabledPropWithMinInterval()) {
335 informZygotesOfUsapPoolStatus();
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800336 }
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 Shankae51005d2019-02-24 10:24:09 -0800342 packageName, packagesForUid, sandboxId,
Chris Wailes7e797b62019-02-22 18:29:22 -0800343 useUsapPool, 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")
Chris Wailesdb132a32019-02-20 10:49:27 -0800390 private Process.ProcessStartResult zygoteSendArgsAndGetResult(
Chris Wailes7e797b62019-02-22 18:29:22 -0800391 ZygoteState zygoteState, boolean useUsapPool, 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.
Chris Wailes7e797b62019-02-22 18:29:22 -0800418 if (useUsapPool && mUsapPoolEnabled && isValidUsapCommand(args)) {
419 LocalSocket usapSessionSocket = null;
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800420
421 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800422 usapSessionSocket = zygoteState.getUsapSessionSocket();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800423
Chris Wailes7e797b62019-02-22 18:29:22 -0800424 final BufferedWriter usapWriter =
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800425 new BufferedWriter(
Chris Wailes7e797b62019-02-22 18:29:22 -0800426 new OutputStreamWriter(usapSessionSocket.getOutputStream()),
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800427 Zygote.SOCKET_BUFFER_SIZE);
Chris Wailes7e797b62019-02-22 18:29:22 -0800428 final DataInputStream usapReader =
429 new DataInputStream(usapSessionSocket.getInputStream());
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800430
Chris Wailes7e797b62019-02-22 18:29:22 -0800431 usapWriter.write(msgStr);
432 usapWriter.flush();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800433
Chris Wailes7e797b62019-02-22 18:29:22 -0800434 result.pid = usapReader.readInt();
435 // USAPs can't be used to spawn processes that need wrappers.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800436 result.usingWrapper = false;
437
438 if (result.pid < 0) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800439 throw new ZygoteStartFailedEx("USAP specialization failed");
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800440 }
441
442 return result;
443 } catch (IOException ex) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800444 // If there was an IOException using the USAP pool we will log the error and
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800445 // attempt to start the process through the Zygote.
Chris Wailes7e797b62019-02-22 18:29:22 -0800446 Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
Chris Wailesae937142019-01-24 12:57:33 -0800447 + ex.getMessage());
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800448 } finally {
449 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800450 usapSessionSocket.close();
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800451 } catch (IOException ex) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800452 Log.e(LOG_TAG, "Failed to close USAP 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 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800484 * Flags that may not be passed to a USAP.
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800485 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800486 private static final String[] INVALID_USAP_FLAGS = {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800487 "--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",
Andrei Oneae8e150d2019-02-18 18:27:11 +0000495 "--hidden-api-statslog-sampling-rate",
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800496 "--invoke-with"
497 };
498
499 /**
Chris Wailes7e797b62019-02-22 18:29:22 -0800500 * Tests a command list to see if it is valid to send to a USAP.
501 * @param args Zygote/USAP command arguments
502 * @return True if the command can be passed to a USAP; false otherwise
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800503 */
Chris Wailes7e797b62019-02-22 18:29:22 -0800504 private static boolean isValidUsapCommand(ArrayList<String> args) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800505 for (String flag : args) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800506 for (String badFlag : INVALID_USAP_FLAGS) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800507 if (flag.startsWith(badFlag)) {
508 return false;
509 }
510 }
511 }
512
513 return true;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400514 }
515
516 /**
517 * Starts a new process via the zygote mechanism.
518 *
519 * @param processClass Class name whose static main() to run
520 * @param niceName 'nice' process name to appear in ps
521 * @param uid a POSIX uid that the new process should setuid() to
522 * @param gid a POSIX gid that the new process shuold setgid() to
523 * @param gids null-ok; a list of supplementary group IDs that the
524 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100525 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400526 * @param targetSdkVersion The target SDK version for the app.
527 * @param seInfo null-ok SELinux information for the new process.
528 * @param abi the ABI the process should use.
529 * @param instructionSet null-ok the instruction set to use.
530 * @param appDataDir null-ok the data directory of the app.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500531 * @param startChildZygote Start a sub-zygote. This creates a new zygote process
532 * that has its state cloned from this zygote process.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700533 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700534 * @param packagesForUid null-ok all the packages with the same uid as 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,
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800553 @Nullable String sandboxId,
Chris Wailes7e797b62019-02-22 18:29:22 -0800554 boolean useUnspecializedAppProcessPool,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700555 @Nullable String[] extraArgs)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400556 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400557 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400558
Robert Sesekded20982016-08-15 13:59:13 -0400559 // --runtime-args, --setuid=, --setgid=,
560 // and --setgroups= must go first
561 argsForZygote.add("--runtime-args");
562 argsForZygote.add("--setuid=" + uid);
563 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100564 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400565 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
566 argsForZygote.add("--mount-external-default");
567 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
568 argsForZygote.add("--mount-external-read");
569 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
570 argsForZygote.add("--mount-external-write");
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700571 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
572 argsForZygote.add("--mount-external-full");
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800573 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
574 argsForZygote.add("--mount-external-installer");
Sudheer Shanka0b6da532019-01-09 12:06:51 -0800575 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
576 argsForZygote.add("--mount-external-legacy");
Robert Sesekded20982016-08-15 13:59:13 -0400577 }
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700578
Robert Sesekded20982016-08-15 13:59:13 -0400579 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400580
Robert Sesekded20982016-08-15 13:59:13 -0400581 // --setgroups is a comma-separated list
582 if (gids != null && gids.length > 0) {
583 StringBuilder sb = new StringBuilder();
584 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400585
Robert Sesekded20982016-08-15 13:59:13 -0400586 int sz = gids.length;
587 for (int i = 0; i < sz; i++) {
588 if (i != 0) {
589 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400590 }
Robert Sesekded20982016-08-15 13:59:13 -0400591 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400592 }
593
Robert Sesekded20982016-08-15 13:59:13 -0400594 argsForZygote.add(sb.toString());
595 }
596
597 if (niceName != null) {
598 argsForZygote.add("--nice-name=" + niceName);
599 }
600
601 if (seInfo != null) {
602 argsForZygote.add("--seinfo=" + seInfo);
603 }
604
605 if (instructionSet != null) {
606 argsForZygote.add("--instruction-set=" + instructionSet);
607 }
608
609 if (appDataDir != null) {
610 argsForZygote.add("--app-data-dir=" + appDataDir);
611 }
612
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000613 if (invokeWith != null) {
614 argsForZygote.add("--invoke-with");
615 argsForZygote.add(invokeWith);
616 }
617
Robert Sesekd0a190df2018-02-12 18:46:01 -0500618 if (startChildZygote) {
619 argsForZygote.add("--start-child-zygote");
620 }
621
Sudheer Shanka154fe3f2018-07-30 14:44:26 -0700622 if (packageName != null) {
623 argsForZygote.add("--package-name=" + packageName);
624 }
625
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700626 if (packagesForUid != null && packagesForUid.length > 0) {
627 final StringBuilder sb = new StringBuilder();
628 sb.append("--packages-for-uid=");
629
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800630 // TODO (chriswailes): Replace with String.join
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700631 for (int i = 0; i < packagesForUid.length; ++i) {
632 if (i != 0) {
633 sb.append(',');
634 }
635 sb.append(packagesForUid[i]);
636 }
637 argsForZygote.add(sb.toString());
638 }
639
Sudheer Shanka03fd40b2019-02-06 12:39:14 -0800640 if (sandboxId != null) {
641 argsForZygote.add("--sandbox-id=" + sandboxId);
642 }
643
Robert Sesekded20982016-08-15 13:59:13 -0400644 argsForZygote.add(processClass);
645
646 if (extraArgs != null) {
647 for (String arg : extraArgs) {
648 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400649 }
Robert Sesekded20982016-08-15 13:59:13 -0400650 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400651
Robert Sesekded20982016-08-15 13:59:13 -0400652 synchronized(mLock) {
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800653 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
Chris Wailes7e797b62019-02-22 18:29:22 -0800654 useUnspecializedAppProcessPool,
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800655 argsForZygote);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400656 }
657 }
658
Chris Wailes7e797b62019-02-22 18:29:22 -0800659 private boolean fetchUsapPoolEnabledProp() {
660 boolean origVal = mUsapPoolEnabled;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800661
662 final String propertyString =
663 Zygote.getSystemProperty(
Chris Wailes7e797b62019-02-22 18:29:22 -0800664 DeviceConfig.RuntimeNative.USAP_POOL_ENABLED,
665 USAP_POOL_ENABLED_DEFAULT);
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800666
667 if (!propertyString.isEmpty()) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800668 mUsapPoolEnabled =
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800669 Zygote.getSystemPropertyBoolean(
Chris Wailes7e797b62019-02-22 18:29:22 -0800670 DeviceConfig.RuntimeNative.USAP_POOL_ENABLED,
671 Boolean.parseBoolean(USAP_POOL_ENABLED_DEFAULT));
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800672 }
673
Chris Wailes7e797b62019-02-22 18:29:22 -0800674 if (origVal != mUsapPoolEnabled) {
675 Log.i(LOG_TAG, "usapPoolEnabled = " + mUsapPoolEnabled);
Chris Wailesdb132a32019-02-20 10:49:27 -0800676 }
677
Chris Wailes7e797b62019-02-22 18:29:22 -0800678 return origVal != mUsapPoolEnabled;
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800679 }
680
681 private long mLastPropCheckTimestamp = 0;
682
Chris Wailes7e797b62019-02-22 18:29:22 -0800683 private boolean fetchUsapPoolEnabledPropWithMinInterval() {
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800684 final long currentTimestamp = SystemClock.elapsedRealtime();
685
686 if (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL) {
687 mLastPropCheckTimestamp = currentTimestamp;
Chris Wailes7e797b62019-02-22 18:29:22 -0800688 return fetchUsapPoolEnabledProp();
Mathieu Chartier0bccbf72019-01-30 15:56:17 -0800689 }
690
691 return false;
692 }
693
Robert Sesek8f8d1872016-03-18 16:52:57 -0400694 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500695 * Closes the connections to the zygote, if they exist.
696 */
697 public void close() {
698 if (primaryZygoteState != null) {
699 primaryZygoteState.close();
700 }
701 if (secondaryZygoteState != null) {
702 secondaryZygoteState.close();
703 }
704 }
705
706 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400707 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
708 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
709 * already open.
710 */
711 public void establishZygoteConnectionForAbi(String abi) {
712 try {
Robert Sesekded20982016-08-15 13:59:13 -0400713 synchronized(mLock) {
714 openZygoteSocketIfNeeded(abi);
715 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400716 } catch (ZygoteStartFailedEx ex) {
717 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
718 }
719 }
720
721 /**
Andreas Gampe8444dca2018-05-01 13:31:28 -0700722 * Attempt to retrieve the PID of the zygote serving the given abi.
723 */
724 public int getZygotePid(String abi) {
725 try {
726 synchronized (mLock) {
727 ZygoteState state = openZygoteSocketIfNeeded(abi);
728
729 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -0800730 state.mZygoteOutputWriter.write("1");
Andreas Gampe8444dca2018-05-01 13:31:28 -0700731 // ... followed by a new-line.
Chris Wailesefce9292019-01-11 13:19:20 -0800732 state.mZygoteOutputWriter.newLine();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700733 // ... followed by our only argument.
Chris Wailesefce9292019-01-11 13:19:20 -0800734 state.mZygoteOutputWriter.write("--get-pid");
735 state.mZygoteOutputWriter.newLine();
736 state.mZygoteOutputWriter.flush();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700737
738 // The response is a length prefixed stream of ASCII bytes.
Chris Wailesefce9292019-01-11 13:19:20 -0800739 int numBytes = state.mZygoteInputStream.readInt();
Andreas Gampe8444dca2018-05-01 13:31:28 -0700740 byte[] bytes = new byte[numBytes];
Chris Wailesefce9292019-01-11 13:19:20 -0800741 state.mZygoteInputStream.readFully(bytes);
Andreas Gampe8444dca2018-05-01 13:31:28 -0700742
743 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
744 }
745 } catch (Exception ex) {
746 throw new RuntimeException("Failure retrieving pid", ex);
747 }
748 }
749
750 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000751 * Push hidden API blacklisting exemptions into the zygote process(es).
752 *
753 * <p>The list of exemptions will take affect for all new processes forked from the zygote after
754 * this call.
755 *
Mathew Inwood33d51382018-04-05 13:56:39 +0100756 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
757 * whitelisted/public APIs (i.e. allowed, no logging of usage).
Mathew Inwood8faeab82018-03-16 14:26:08 +0000758 */
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100759 public boolean setApiBlacklistExemptions(List<String> exemptions) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000760 synchronized (mLock) {
761 mApiBlacklistExemptions = exemptions;
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100762 boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
763 if (ok) {
764 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
765 }
766 return ok;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000767 }
768 }
769
Mathew Inwood04194fe2018-04-04 14:48:03 +0100770 /**
771 * Set the precentage of detected hidden API accesses that are logged to the event log.
772 *
773 * <p>This rate will take affect for all new processes forked from the zygote after this call.
774 *
775 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
776 */
777 public void setHiddenApiAccessLogSampleRate(int rate) {
778 synchronized (mLock) {
779 mHiddenApiAccessLogSampleRate = rate;
780 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
781 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
782 }
783 }
784
Andrei Oneae8e150d2019-02-18 18:27:11 +0000785 /**
786 * Set the precentage of detected hidden API accesses that are logged to the new event log.
787 *
788 * <p>This rate will take affect for all new processes forked from the zygote after this call.
789 *
790 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
791 */
792 public void setHiddenApiAccessStatslogSampleRate(int rate) {
793 synchronized (mLock) {
794 mHiddenApiAccessStatslogSampleRate = rate;
795 maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState);
796 maybeSetHiddenApiAccessStatslogSampleRate(secondaryZygoteState);
797 }
798 }
799
Mathew Inwood8faeab82018-03-16 14:26:08 +0000800 @GuardedBy("mLock")
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100801 private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000802 if (state == null || state.isClosed()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100803 Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
804 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000805 }
806 if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100807 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000808 }
809 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800810 state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
811 state.mZygoteOutputWriter.newLine();
812 state.mZygoteOutputWriter.write("--set-api-blacklist-exemptions");
813 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000814 for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
Chris Wailesefce9292019-01-11 13:19:20 -0800815 state.mZygoteOutputWriter.write(mApiBlacklistExemptions.get(i));
816 state.mZygoteOutputWriter.newLine();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000817 }
Chris Wailesefce9292019-01-11 13:19:20 -0800818 state.mZygoteOutputWriter.flush();
819 int status = state.mZygoteInputStream.readInt();
Mathew Inwood8faeab82018-03-16 14:26:08 +0000820 if (status != 0) {
821 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
822 }
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100823 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000824 } catch (IOException ioe) {
825 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100826 mApiBlacklistExemptions = Collections.emptyList();
827 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000828 }
829 }
830
Mathew Inwood04194fe2018-04-04 14:48:03 +0100831 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
832 if (state == null || state.isClosed()) {
833 return;
834 }
835 if (mHiddenApiAccessLogSampleRate == -1) {
836 return;
837 }
838 try {
Chris Wailesefce9292019-01-11 13:19:20 -0800839 state.mZygoteOutputWriter.write(Integer.toString(1));
840 state.mZygoteOutputWriter.newLine();
841 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
Mathew Inwood04194fe2018-04-04 14:48:03 +0100842 + Integer.toString(mHiddenApiAccessLogSampleRate));
Chris Wailesefce9292019-01-11 13:19:20 -0800843 state.mZygoteOutputWriter.newLine();
844 state.mZygoteOutputWriter.flush();
845 int status = state.mZygoteInputStream.readInt();
Mathew Inwood04194fe2018-04-04 14:48:03 +0100846 if (status != 0) {
847 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
848 }
849 } catch (IOException ioe) {
850 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
851 }
852 }
853
Andrei Oneae8e150d2019-02-18 18:27:11 +0000854 private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) {
855 if (state == null || state.isClosed()) {
856 return;
857 }
858 if (mHiddenApiAccessStatslogSampleRate == -1) {
859 return;
860 }
861 try {
862 state.mZygoteOutputWriter.write(Integer.toString(1));
863 state.mZygoteOutputWriter.newLine();
864 state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate="
865 + Integer.toString(mHiddenApiAccessStatslogSampleRate));
866 state.mZygoteOutputWriter.newLine();
867 state.mZygoteOutputWriter.flush();
868 int status = state.mZygoteInputStream.readInt();
869 if (status != 0) {
870 Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate; status "
871 + status);
872 }
873 } catch (IOException ioe) {
874 Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate", ioe);
875 }
876 }
877
Mathew Inwood8faeab82018-03-16 14:26:08 +0000878 /**
Chris Wailesdb132a32019-02-20 10:49:27 -0800879 * Creates a ZygoteState for the primary zygote if it doesn't exist or has been disconnected.
880 */
881 @GuardedBy("mLock")
882 private void attemptConnectionToPrimaryZygote() throws IOException {
883 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
884 primaryZygoteState =
Chris Wailes7e797b62019-02-22 18:29:22 -0800885 ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
Chris Wailesdb132a32019-02-20 10:49:27 -0800886
887 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
888 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
889 }
890 }
891
892 /**
893 * Creates a ZygoteState for the secondary zygote if it doesn't exist or has been disconnected.
894 */
895 @GuardedBy("mLock")
896 private void attemptConnectionToSecondaryZygote() throws IOException {
897 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
898 secondaryZygoteState =
899 ZygoteState.connect(mZygoteSecondarySocketAddress,
Chris Wailes7e797b62019-02-22 18:29:22 -0800900 mUsapPoolSecondarySocketAddress);
Chris Wailesdb132a32019-02-20 10:49:27 -0800901
902 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
903 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
904 }
905 }
906
907 /**
Chris Wailesefce9292019-01-11 13:19:20 -0800908 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
909 * already open. If a compatible session socket is already open that session socket is returned.
910 * This function may block and may have to try connecting to multiple Zygotes to find the
911 * appropriate one. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400912 */
Robert Sesekded20982016-08-15 13:59:13 -0400913 @GuardedBy("mLock")
Chris Wailesdb132a32019-02-20 10:49:27 -0800914 private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
915 try {
916 attemptConnectionToPrimaryZygote();
Chris Wailesefce9292019-01-11 13:19:20 -0800917
Chris Wailesdb132a32019-02-20 10:49:27 -0800918 if (primaryZygoteState.matches(abi)) {
919 return primaryZygoteState;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400920 }
Chris Wailesefce9292019-01-11 13:19:20 -0800921
Chris Wailesdb132a32019-02-20 10:49:27 -0800922 // The primary zygote didn't match. Try the secondary.
923 attemptConnectionToSecondaryZygote();
Chris Wailesefce9292019-01-11 13:19:20 -0800924
Chris Wailesdb132a32019-02-20 10:49:27 -0800925 if (secondaryZygoteState.matches(abi)) {
926 return secondaryZygoteState;
Robert Sesek8f8d1872016-03-18 16:52:57 -0400927 }
Chris Wailesdb132a32019-02-20 10:49:27 -0800928 } catch (IOException ioe) {
929 throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400930 }
931
932 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
933 }
Robert Sesekded20982016-08-15 13:59:13 -0400934
935 /**
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100936 * Instructs the zygote to pre-load the application code for the given Application.
937 * Only the app zygote supports this function.
938 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
939 */
940 public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
941 IOException {
942 synchronized (mLock) {
943 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800944 state.mZygoteOutputWriter.write("2");
945 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100946
Chris Wailesefce9292019-01-11 13:19:20 -0800947 state.mZygoteOutputWriter.write("--preload-app");
948 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100949
950 // Zygote args needs to be strings, so in order to pass ApplicationInfo,
951 // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
952 Parcel parcel = Parcel.obtain();
953 appInfo.writeToParcel(parcel, 0 /* flags */);
954 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
955 parcel.recycle();
Chris Wailesefce9292019-01-11 13:19:20 -0800956 state.mZygoteOutputWriter.write(encodedParcelData);
957 state.mZygoteOutputWriter.newLine();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100958
Chris Wailesefce9292019-01-11 13:19:20 -0800959 state.mZygoteOutputWriter.flush();
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100960
Chris Wailesefce9292019-01-11 13:19:20 -0800961 return (state.mZygoteInputStream.readInt() == 0);
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100962 }
963 }
964
965 /**
Robert Sesekded20982016-08-15 13:59:13 -0400966 * Instructs the zygote to pre-load the classes and native libraries at the given paths
967 * for the specified abi. Not all zygotes support this function.
968 */
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500969 public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
970 String cacheKey, String abi) throws ZygoteStartFailedEx,
971 IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400972 synchronized(mLock) {
973 ZygoteState state = openZygoteSocketIfNeeded(abi);
Chris Wailesefce9292019-01-11 13:19:20 -0800974 state.mZygoteOutputWriter.write("5");
975 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400976
Chris Wailesefce9292019-01-11 13:19:20 -0800977 state.mZygoteOutputWriter.write("--preload-package");
978 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400979
Chris Wailesefce9292019-01-11 13:19:20 -0800980 state.mZygoteOutputWriter.write(packagePath);
981 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400982
Chris Wailesefce9292019-01-11 13:19:20 -0800983 state.mZygoteOutputWriter.write(libsPath);
984 state.mZygoteOutputWriter.newLine();
Robert Sesekded20982016-08-15 13:59:13 -0400985
Chris Wailesefce9292019-01-11 13:19:20 -0800986 state.mZygoteOutputWriter.write(libFileName);
987 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500988
Chris Wailesefce9292019-01-11 13:19:20 -0800989 state.mZygoteOutputWriter.write(cacheKey);
990 state.mZygoteOutputWriter.newLine();
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000991
Chris Wailesefce9292019-01-11 13:19:20 -0800992 state.mZygoteOutputWriter.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100993
Chris Wailesefce9292019-01-11 13:19:20 -0800994 return (state.mZygoteInputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400995 }
996 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000997
998 /**
999 * Instructs the zygote to preload the default set of classes and resources. Returns
1000 * {@code true} if a preload was performed as a result of this call, and {@code false}
1001 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
1002 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
1003 */
1004 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
1005 synchronized (mLock) {
1006 ZygoteState state = openZygoteSocketIfNeeded(abi);
1007 // Each query starts with the argument count (1 in this case)
Chris Wailesefce9292019-01-11 13:19:20 -08001008 state.mZygoteOutputWriter.write("1");
1009 state.mZygoteOutputWriter.newLine();
1010 state.mZygoteOutputWriter.write("--preload-default");
1011 state.mZygoteOutputWriter.newLine();
1012 state.mZygoteOutputWriter.flush();
Narayan Kamath669afcc2017-02-06 20:24:08 +00001013
Chris Wailesefce9292019-01-11 13:19:20 -08001014 return (state.mZygoteInputStream.readInt() == 0);
Narayan Kamath669afcc2017-02-06 20:24:08 +00001015 }
1016 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001017
1018 /**
1019 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -08001020 * @param zygoteSocketName The name of the socket to connect to.
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001021 */
Chris Wailesefce9292019-01-11 13:19:20 -08001022 public static void waitForConnectionToZygote(String zygoteSocketName) {
1023 final LocalSocketAddress zygoteSocketAddress =
1024 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
1025 waitForConnectionToZygote(zygoteSocketAddress);
Robert Sesek5ac8abf2018-01-26 14:26:53 -05001026 }
1027
1028 /**
1029 * Try connecting to the Zygote over and over again until we hit a time-out.
Mathieu Chartier0bccbf72019-01-30 15:56:17 -08001030 * @param zygoteSocketAddress The name of the socket to connect to.
Robert Sesek5ac8abf2018-01-26 14:26:53 -05001031 */
Chris Wailesefce9292019-01-11 13:19:20 -08001032 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
Martijn Coenen82dc85a2019-01-28 13:12:28 +01001033 int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS;
1034 for (int n = numRetries; n >= 0; n--) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001035 try {
Chris Wailesefce9292019-01-11 13:19:20 -08001036 final ZygoteState zs =
Chris Wailesba4c2eb2019-01-11 17:13:00 -08001037 ZygoteState.connect(zygoteSocketAddress, null);
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001038 zs.close();
1039 return;
1040 } catch (IOException ioe) {
1041 Log.w(LOG_TAG,
1042 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
1043 }
1044
1045 try {
Martijn Coenen82dc85a2019-01-28 13:12:28 +01001046 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001047 } catch (InterruptedException ie) {
1048 }
1049 }
Chris Wailesefce9292019-01-11 13:19:20 -08001050 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
1051 + zygoteSocketAddress.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +01001052 }
Robert Sesekd0a190df2018-02-12 18:46:01 -05001053
1054 /**
Chris Wailes7e797b62019-02-22 18:29:22 -08001055 * Sends messages to the zygotes telling them to change the status of their USAP pools. If
Chris Wailesdb132a32019-02-20 10:49:27 -08001056 * this notification fails the ZygoteProcess will fall back to the previous behavior.
1057 */
Chris Wailes7e797b62019-02-22 18:29:22 -08001058 private void informZygotesOfUsapPoolStatus() {
1059 final String command = "1\n--usap-pool-enabled=" + mUsapPoolEnabled + "\n";
Chris Wailesdb132a32019-02-20 10:49:27 -08001060
1061 synchronized (mLock) {
1062 try {
1063 attemptConnectionToPrimaryZygote();
1064
1065 primaryZygoteState.mZygoteOutputWriter.write(command);
1066 primaryZygoteState.mZygoteOutputWriter.flush();
1067 } catch (IOException ioe) {
Chris Wailes7e797b62019-02-22 18:29:22 -08001068 mUsapPoolEnabled = !mUsapPoolEnabled;
1069 Log.w(LOG_TAG, "Failed to inform zygotes of USAP pool status: "
Chris Wailesdb132a32019-02-20 10:49:27 -08001070 + ioe.getMessage());
1071 return;
1072 }
1073
1074 try {
1075 attemptConnectionToSecondaryZygote();
1076
1077 try {
1078 secondaryZygoteState.mZygoteOutputWriter.write(command);
1079 secondaryZygoteState.mZygoteOutputWriter.flush();
1080
1081 // Wait for the secondary Zygote to finish its work.
1082 secondaryZygoteState.mZygoteInputStream.readInt();
1083 } catch (IOException ioe) {
1084 throw new IllegalStateException(
Chris Wailes7e797b62019-02-22 18:29:22 -08001085 "USAP pool state change cause an irrecoverable error",
Chris Wailesdb132a32019-02-20 10:49:27 -08001086 ioe);
1087 }
1088 } catch (IOException ioe) {
1089 // No secondary zygote present. This is expected on some devices.
1090 }
1091
1092 // Wait for the response from the primary zygote here so the primary/secondary zygotes
1093 // can work concurrently.
1094 try {
1095 // Wait for the primary zygote to finish its work.
1096 primaryZygoteState.mZygoteInputStream.readInt();
1097 } catch (IOException ioe) {
1098 throw new IllegalStateException(
Chris Wailes7e797b62019-02-22 18:29:22 -08001099 "USAP pool state change cause an irrecoverable error",
Chris Wailesdb132a32019-02-20 10:49:27 -08001100 ioe);
1101 }
1102 }
1103 }
1104
1105 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -05001106 * Starts a new zygote process as a child of this zygote. This is used to create
1107 * secondary zygotes that inherit data from the zygote that this object
1108 * communicates with. This returns a new ZygoteProcess representing a connection
1109 * to the newly created zygote. Throws an exception if the zygote cannot be started.
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001110 *
1111 * @param processClass The class to use as the child zygote's main entry
1112 * point.
1113 * @param niceName A more readable name to use for the process.
1114 * @param uid The user-id under which the child zygote will run.
1115 * @param gid The group-id under which the child zygote will run.
1116 * @param gids Additional group-ids associated with the child zygote process.
1117 * @param runtimeFlags Additional flags.
1118 * @param seInfo null-ok SELinux information for the child zygote process.
1119 * @param abi non-null the ABI of the child zygote
1120 * @param acceptedAbiList ABIs this child zygote will accept connections for; this
1121 * may be different from <code>abi</code> in case the children
1122 * spawned from this Zygote only communicate using ABI-safe methods.
1123 * @param instructionSet null-ok the instruction set to use.
Martijn Coenen86f08a52019-01-03 16:23:01 +01001124 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
1125 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
Robert Sesekd0a190df2018-02-12 18:46:01 -05001126 */
1127 public ChildZygoteProcess startChildZygote(final String processClass,
1128 final String niceName,
1129 int uid, int gid, int[] gids,
1130 int runtimeFlags,
1131 String seInfo,
1132 String abi,
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001133 String acceptedAbiList,
Martijn Coenen86f08a52019-01-03 16:23:01 +01001134 String instructionSet,
1135 int uidRangeStart,
1136 int uidRangeEnd) {
Robert Sesekd0a190df2018-02-12 18:46:01 -05001137 // Create an unguessable address in the global abstract namespace.
1138 final LocalSocketAddress serverAddress = new LocalSocketAddress(
1139 processClass + "/" + UUID.randomUUID().toString());
1140
Martijn Coenen7e6fa672018-11-05 11:45:26 +01001141 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
Martijn Coenen86f08a52019-01-03 16:23:01 +01001142 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
1143 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
1144 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
Robert Sesekd0a190df2018-02-12 18:46:01 -05001145
1146 Process.ProcessStartResult result;
1147 try {
1148 result = startViaZygote(processClass, niceName, uid, gid,
1149 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
1150 abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001151 true /* startChildZygote */, null /* packageName */,
Sudheer Shankae51005d2019-02-24 10:24:09 -08001152 null /* packagesForUid */, null /* sandboxId */,
Chris Wailes7e797b62019-02-22 18:29:22 -08001153 false /* useUsapPool */, extraArgs);
Robert Sesekd0a190df2018-02-12 18:46:01 -05001154 } catch (ZygoteStartFailedEx ex) {
1155 throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
1156 }
1157
1158 return new ChildZygoteProcess(serverAddress, result.pid);
1159 }
Robert Sesek8f8d1872016-03-18 16:52:57 -04001160}