blob: 251c5eebadc4db7adfaf3c0bc57131f225b3c20b [file] [log] [blame]
Robert Sesek8f8d1872016-03-18 16:52:57 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
18
Sudheer Shankad81b1d72018-09-05 16:37:30 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010021import android.content.pm.ApplicationInfo;
Robert Sesek8f8d1872016-03-18 16:52:57 -040022import android.net.LocalSocket;
23import android.net.LocalSocketAddress;
24import android.util.Log;
Gustav Senntonf0c52b52017-04-27 17:00:50 +010025import android.util.Slog;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010026
Robert Sesekded20982016-08-15 13:59:13 -040027import com.android.internal.annotations.GuardedBy;
Robert Sesek8f8d1872016-03-18 16:52:57 -040028import com.android.internal.os.Zygote;
Robert Sesekded20982016-08-15 13:59:13 -040029import com.android.internal.util.Preconditions;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010030
Robert Sesek8f8d1872016-03-18 16:52:57 -040031import java.io.BufferedWriter;
32import java.io.DataInputStream;
33import java.io.IOException;
34import java.io.OutputStreamWriter;
35import java.nio.charset.StandardCharsets;
36import java.util.ArrayList;
37import java.util.Arrays;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010038import java.util.Base64;
Mathew Inwood8faeab82018-03-16 14:26:08 +000039import java.util.Collections;
Robert Sesek8f8d1872016-03-18 16:52:57 -040040import java.util.List;
Robert Sesekd0a190df2018-02-12 18:46:01 -050041import java.util.UUID;
Robert Sesek8f8d1872016-03-18 16:52:57 -040042
43/*package*/ class ZygoteStartFailedEx extends Exception {
44 ZygoteStartFailedEx(String s) {
45 super(s);
46 }
47
48 ZygoteStartFailedEx(Throwable cause) {
49 super(cause);
50 }
51
52 ZygoteStartFailedEx(String s, Throwable cause) {
53 super(s, cause);
54 }
55}
56
57/**
58 * Maintains communication state with the zygote processes. This class is responsible
59 * for the sockets opened to the zygotes and for starting processes on behalf of the
60 * {@link android.os.Process} class.
61 *
62 * {@hide}
63 */
64public class ZygoteProcess {
65 private static final String LOG_TAG = "ZygoteProcess";
66
67 /**
68 * The name of the socket used to communicate with the primary zygote.
69 */
Robert Sesek5ac8abf2018-01-26 14:26:53 -050070 private final LocalSocketAddress mSocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -040071
72 /**
73 * The name of the secondary (alternate ABI) zygote socket.
74 */
Robert Sesek5ac8abf2018-01-26 14:26:53 -050075 private final LocalSocketAddress mSecondarySocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -040076
77 public ZygoteProcess(String primarySocket, String secondarySocket) {
Robert Sesek5ac8abf2018-01-26 14:26:53 -050078 this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
79 new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
80 }
81
82 public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
Robert Sesek8f8d1872016-03-18 16:52:57 -040083 mSocket = primarySocket;
84 mSecondarySocket = secondarySocket;
85 }
86
Robert Sesek5ac8abf2018-01-26 14:26:53 -050087 public LocalSocketAddress getPrimarySocketAddress() {
88 return mSocket;
89 }
90
Robert Sesek8f8d1872016-03-18 16:52:57 -040091 /**
92 * State for communicating with the zygote process.
93 */
94 public static class ZygoteState {
95 final LocalSocket socket;
96 final DataInputStream inputStream;
97 final BufferedWriter writer;
98 final List<String> abiList;
99
100 boolean mClosed;
101
102 private ZygoteState(LocalSocket socket, DataInputStream inputStream,
103 BufferedWriter writer, List<String> abiList) {
104 this.socket = socket;
105 this.inputStream = inputStream;
106 this.writer = writer;
107 this.abiList = abiList;
108 }
109
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500110 public static ZygoteState connect(LocalSocketAddress address) throws IOException {
Robert Sesek8f8d1872016-03-18 16:52:57 -0400111 DataInputStream zygoteInputStream = null;
112 BufferedWriter zygoteWriter = null;
113 final LocalSocket zygoteSocket = new LocalSocket();
114
115 try {
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500116 zygoteSocket.connect(address);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400117
118 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
119
120 zygoteWriter = new BufferedWriter(new OutputStreamWriter(
121 zygoteSocket.getOutputStream()), 256);
122 } catch (IOException ex) {
123 try {
124 zygoteSocket.close();
125 } catch (IOException ignore) {
126 }
127
128 throw ex;
129 }
130
131 String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500132 Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
133 + address.getName() + " opened, supported ABIS: " + abiListString);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400134
135 return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
136 Arrays.asList(abiListString.split(",")));
137 }
138
139 boolean matches(String abi) {
140 return abiList.contains(abi);
141 }
142
143 public void close() {
144 try {
145 socket.close();
146 } catch (IOException ex) {
147 Log.e(LOG_TAG,"I/O exception on routine close", ex);
148 }
149
150 mClosed = true;
151 }
152
153 boolean isClosed() {
154 return mClosed;
155 }
156 }
157
158 /**
Robert Sesekded20982016-08-15 13:59:13 -0400159 * Lock object to protect access to the two ZygoteStates below. This lock must be
160 * acquired while communicating over the ZygoteState's socket, to prevent
161 * interleaved access.
162 */
163 private final Object mLock = new Object();
164
165 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000166 * List of exemptions to the API blacklist. These are prefix matches on the runtime format
167 * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
168 * list.
169 */
170 private List<String> mApiBlacklistExemptions = Collections.emptyList();
171
172 /**
Mathew Inwood04194fe2018-04-04 14:48:03 +0100173 * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
174 */
175 private int mHiddenApiAccessLogSampleRate;
176
177 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400178 * The state of the connection to the primary zygote.
179 */
180 private ZygoteState primaryZygoteState;
181
182 /**
183 * The state of the connection to the secondary zygote.
184 */
185 private ZygoteState secondaryZygoteState;
186
187 /**
188 * Start a new process.
189 *
190 * <p>If processes are enabled, a new process is created and the
191 * static main() function of a <var>processClass</var> is executed there.
192 * The process will continue running after this function returns.
193 *
194 * <p>If processes are not enabled, a new thread in the caller's
Mathew Inwood8faeab82018-03-16 14:26:08 +0000195 * process is created and main() of <var>processclass</var> called there.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400196 *
197 * <p>The niceName parameter, if not an empty string, is a custom name to
198 * give to the process instead of using processClass. This allows you to
199 * make easily identifyable processes even if you are using the same base
200 * <var>processClass</var> to start them.
201 *
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000202 * When invokeWith is not null, the process will be started as a fresh app
Tamas Berghammer0ca16fa2016-11-11 16:08:26 +0000203 * and not a zygote fork. Note that this is only allowed for uid 0 or when
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100204 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000205 *
Robert Sesek8f8d1872016-03-18 16:52:57 -0400206 * @param processClass The class to use as the process's main entry
207 * point.
208 * @param niceName A more readable name to use for the process.
209 * @param uid The user-id under which the process will run.
210 * @param gid The group-id under which the process will run.
211 * @param gids Additional group-ids associated with the process.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100212 * @param runtimeFlags Additional flags.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400213 * @param targetSdkVersion The target SDK version for the app.
214 * @param seInfo null-ok SELinux information for the new process.
215 * @param abi non-null the ABI this app should be started with.
216 * @param instructionSet null-ok the instruction set to use.
217 * @param appDataDir null-ok the data directory of the app.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000218 * @param invokeWith null-ok the command to invoke with.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700219 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700220 * @param packagesForUid null-ok all the packages with the same uid as this process.
221 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400222 * @param zygoteArgs Additional arguments to supply to the zygote process.
223 *
224 * @return An object that describes the result of the attempt to start the process.
225 * @throws RuntimeException on fatal start failure
226 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700227 public final Process.ProcessStartResult start(@NonNull final String processClass,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400228 final String niceName,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700229 int uid, int gid, @Nullable int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100230 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400231 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700232 @Nullable String seInfo,
233 @NonNull String abi,
234 @Nullable String instructionSet,
235 @Nullable String appDataDir,
236 @Nullable String invokeWith,
237 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700238 @Nullable String[] packagesForUid,
239 @Nullable String[] visibleVols,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700240 @Nullable String[] zygoteArgs) {
Robert Sesek8f8d1872016-03-18 16:52:57 -0400241 try {
242 return startViaZygote(processClass, niceName, uid, gid, gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100243 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500244 abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700245 packageName, packagesForUid, visibleVols, zygoteArgs);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400246 } catch (ZygoteStartFailedEx ex) {
247 Log.e(LOG_TAG,
248 "Starting VM process through Zygote failed");
249 throw new RuntimeException(
250 "Starting VM process through Zygote failed", ex);
251 }
252 }
253
254 /** retry interval for opening a zygote socket */
255 static final int ZYGOTE_RETRY_MILLIS = 500;
256
257 /**
258 * Queries the zygote for the list of ABIS it supports.
259 *
260 * @throws ZygoteStartFailedEx if the query failed.
261 */
Robert Sesekded20982016-08-15 13:59:13 -0400262 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400263 private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
264 throws IOException {
265 // Each query starts with the argument count (1 in this case)
266 writer.write("1");
267 // ... followed by a new-line.
268 writer.newLine();
269 // ... followed by our only argument.
270 writer.write("--query-abi-list");
271 writer.newLine();
272 writer.flush();
273
274 // The response is a length prefixed stream of ASCII bytes.
275 int numBytes = inputStream.readInt();
276 byte[] bytes = new byte[numBytes];
277 inputStream.readFully(bytes);
278
279 return new String(bytes, StandardCharsets.US_ASCII);
280 }
281
282 /**
283 * Sends an argument list to the zygote process, which starts a new child
284 * and returns the child's pid. Please note: the present implementation
285 * replaces newlines in the argument list with spaces.
286 *
287 * @throws ZygoteStartFailedEx if process start failed for any reason
288 */
Robert Sesekded20982016-08-15 13:59:13 -0400289 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400290 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
291 ZygoteState zygoteState, ArrayList<String> args)
292 throws ZygoteStartFailedEx {
293 try {
Robert Sesek0b58f192016-10-10 18:34:42 -0400294 // Throw early if any of the arguments are malformed. This means we can
295 // avoid writing a partial response to the zygote.
296 int sz = args.size();
297 for (int i = 0; i < sz; i++) {
298 if (args.get(i).indexOf('\n') >= 0) {
299 throw new ZygoteStartFailedEx("embedded newlines not allowed");
300 }
301 }
302
Robert Sesek8f8d1872016-03-18 16:52:57 -0400303 /**
304 * See com.android.internal.os.SystemZygoteInit.readArgumentList()
305 * Presently the wire format to the zygote process is:
306 * a) a count of arguments (argc, in essence)
307 * b) a number of newline-separated argument strings equal to count
308 *
309 * After the zygote process reads these it will write the pid of
310 * the child or -1 on failure, followed by boolean to
311 * indicate whether a wrapper process was used.
312 */
313 final BufferedWriter writer = zygoteState.writer;
314 final DataInputStream inputStream = zygoteState.inputStream;
315
316 writer.write(Integer.toString(args.size()));
317 writer.newLine();
318
Robert Sesek8f8d1872016-03-18 16:52:57 -0400319 for (int i = 0; i < sz; i++) {
320 String arg = args.get(i);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400321 writer.write(arg);
322 writer.newLine();
323 }
324
325 writer.flush();
326
327 // Should there be a timeout on this?
328 Process.ProcessStartResult result = new Process.ProcessStartResult();
Robert Sesek0b58f192016-10-10 18:34:42 -0400329
330 // Always read the entire result from the input stream to avoid leaving
331 // bytes in the stream for future process starts to accidentally stumble
332 // upon.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400333 result.pid = inputStream.readInt();
Robert Sesek0b58f192016-10-10 18:34:42 -0400334 result.usingWrapper = inputStream.readBoolean();
335
Robert Sesek8f8d1872016-03-18 16:52:57 -0400336 if (result.pid < 0) {
337 throw new ZygoteStartFailedEx("fork() failed");
338 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400339 return result;
340 } catch (IOException ex) {
341 zygoteState.close();
342 throw new ZygoteStartFailedEx(ex);
343 }
344 }
345
346 /**
347 * Starts a new process via the zygote mechanism.
348 *
349 * @param processClass Class name whose static main() to run
350 * @param niceName 'nice' process name to appear in ps
351 * @param uid a POSIX uid that the new process should setuid() to
352 * @param gid a POSIX gid that the new process shuold setgid() to
353 * @param gids null-ok; a list of supplementary group IDs that the
354 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100355 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400356 * @param targetSdkVersion The target SDK version for the app.
357 * @param seInfo null-ok SELinux information for the new process.
358 * @param abi the ABI the process should use.
359 * @param instructionSet null-ok the instruction set to use.
360 * @param appDataDir null-ok the data directory of the app.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500361 * @param startChildZygote Start a sub-zygote. This creates a new zygote process
362 * that has its state cloned from this zygote process.
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700363 * @param packageName null-ok the name of the package this process belongs to.
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700364 * @param packagesForUid null-ok all the packages with the same uid as this process.
365 * @param visibleVols null-ok storage volumes that can be accessed by this process.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400366 * @param extraArgs Additional arguments to supply to the zygote process.
367 * @return An object that describes the result of the attempt to start the process.
368 * @throws ZygoteStartFailedEx if process start failed for any reason
369 */
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700370 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
371 @Nullable final String niceName,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400372 final int uid, final int gid,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700373 @Nullable final int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100374 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400375 int targetSdkVersion,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700376 @Nullable String seInfo,
377 @NonNull String abi,
378 @Nullable String instructionSet,
379 @Nullable String appDataDir,
380 @Nullable String invokeWith,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500381 boolean startChildZygote,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700382 @Nullable String packageName,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700383 @Nullable String[] packagesForUid,
384 @Nullable String[] visibleVols,
Sudheer Shankad81b1d72018-09-05 16:37:30 -0700385 @Nullable String[] extraArgs)
Robert Sesek8f8d1872016-03-18 16:52:57 -0400386 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400387 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400388
Robert Sesekded20982016-08-15 13:59:13 -0400389 // --runtime-args, --setuid=, --setgid=,
390 // and --setgroups= must go first
391 argsForZygote.add("--runtime-args");
392 argsForZygote.add("--setuid=" + uid);
393 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100394 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400395 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
396 argsForZygote.add("--mount-external-default");
397 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
398 argsForZygote.add("--mount-external-read");
399 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
400 argsForZygote.add("--mount-external-write");
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700401 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
402 argsForZygote.add("--mount-external-full");
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800403 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
404 argsForZygote.add("--mount-external-installer");
Robert Sesekded20982016-08-15 13:59:13 -0400405 }
Sudheer Shanka98cb3f02018-08-17 16:10:29 -0700406
Robert Sesekded20982016-08-15 13:59:13 -0400407 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400408
Robert Sesekded20982016-08-15 13:59:13 -0400409 // --setgroups is a comma-separated list
410 if (gids != null && gids.length > 0) {
411 StringBuilder sb = new StringBuilder();
412 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400413
Robert Sesekded20982016-08-15 13:59:13 -0400414 int sz = gids.length;
415 for (int i = 0; i < sz; i++) {
416 if (i != 0) {
417 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400418 }
Robert Sesekded20982016-08-15 13:59:13 -0400419 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400420 }
421
Robert Sesekded20982016-08-15 13:59:13 -0400422 argsForZygote.add(sb.toString());
423 }
424
425 if (niceName != null) {
426 argsForZygote.add("--nice-name=" + niceName);
427 }
428
429 if (seInfo != null) {
430 argsForZygote.add("--seinfo=" + seInfo);
431 }
432
433 if (instructionSet != null) {
434 argsForZygote.add("--instruction-set=" + instructionSet);
435 }
436
437 if (appDataDir != null) {
438 argsForZygote.add("--app-data-dir=" + appDataDir);
439 }
440
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000441 if (invokeWith != null) {
442 argsForZygote.add("--invoke-with");
443 argsForZygote.add(invokeWith);
444 }
445
Robert Sesekd0a190df2018-02-12 18:46:01 -0500446 if (startChildZygote) {
447 argsForZygote.add("--start-child-zygote");
448 }
449
Sudheer Shanka154fe3f2018-07-30 14:44:26 -0700450 if (packageName != null) {
451 argsForZygote.add("--package-name=" + packageName);
452 }
453
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700454 if (packagesForUid != null && packagesForUid.length > 0) {
455 final StringBuilder sb = new StringBuilder();
456 sb.append("--packages-for-uid=");
457
458 for (int i = 0; i < packagesForUid.length; ++i) {
459 if (i != 0) {
460 sb.append(',');
461 }
462 sb.append(packagesForUid[i]);
463 }
464 argsForZygote.add(sb.toString());
465 }
466
467 if (visibleVols != null && visibleVols.length > 0) {
468 final StringBuilder sb = new StringBuilder();
469 sb.append("--visible-vols=");
470
471 for (int i = 0; i < visibleVols.length; ++i) {
472 if (i != 0) {
473 sb.append(',');
474 }
475 sb.append(visibleVols[i]);
476 }
477 argsForZygote.add(sb.toString());
478 }
479
Robert Sesekded20982016-08-15 13:59:13 -0400480 argsForZygote.add(processClass);
481
482 if (extraArgs != null) {
483 for (String arg : extraArgs) {
484 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400485 }
Robert Sesekded20982016-08-15 13:59:13 -0400486 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400487
Robert Sesekded20982016-08-15 13:59:13 -0400488 synchronized(mLock) {
Robert Sesek8f8d1872016-03-18 16:52:57 -0400489 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
490 }
491 }
492
493 /**
Robert Sesekd0a190df2018-02-12 18:46:01 -0500494 * Closes the connections to the zygote, if they exist.
495 */
496 public void close() {
497 if (primaryZygoteState != null) {
498 primaryZygoteState.close();
499 }
500 if (secondaryZygoteState != null) {
501 secondaryZygoteState.close();
502 }
503 }
504
505 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400506 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
507 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
508 * already open.
509 */
510 public void establishZygoteConnectionForAbi(String abi) {
511 try {
Robert Sesekded20982016-08-15 13:59:13 -0400512 synchronized(mLock) {
513 openZygoteSocketIfNeeded(abi);
514 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400515 } catch (ZygoteStartFailedEx ex) {
516 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
517 }
518 }
519
520 /**
Andreas Gampe8444dca2018-05-01 13:31:28 -0700521 * Attempt to retrieve the PID of the zygote serving the given abi.
522 */
523 public int getZygotePid(String abi) {
524 try {
525 synchronized (mLock) {
526 ZygoteState state = openZygoteSocketIfNeeded(abi);
527
528 // Each query starts with the argument count (1 in this case)
529 state.writer.write("1");
530 // ... followed by a new-line.
531 state.writer.newLine();
532 // ... followed by our only argument.
533 state.writer.write("--get-pid");
534 state.writer.newLine();
535 state.writer.flush();
536
537 // The response is a length prefixed stream of ASCII bytes.
538 int numBytes = state.inputStream.readInt();
539 byte[] bytes = new byte[numBytes];
540 state.inputStream.readFully(bytes);
541
542 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
543 }
544 } catch (Exception ex) {
545 throw new RuntimeException("Failure retrieving pid", ex);
546 }
547 }
548
549 /**
Mathew Inwood8faeab82018-03-16 14:26:08 +0000550 * Push hidden API blacklisting exemptions into the zygote process(es).
551 *
552 * <p>The list of exemptions will take affect for all new processes forked from the zygote after
553 * this call.
554 *
Mathew Inwood33d51382018-04-05 13:56:39 +0100555 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
556 * whitelisted/public APIs (i.e. allowed, no logging of usage).
Mathew Inwood8faeab82018-03-16 14:26:08 +0000557 */
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100558 public boolean setApiBlacklistExemptions(List<String> exemptions) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000559 synchronized (mLock) {
560 mApiBlacklistExemptions = exemptions;
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100561 boolean ok = maybeSetApiBlacklistExemptions(primaryZygoteState, true);
562 if (ok) {
563 ok = maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
564 }
565 return ok;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000566 }
567 }
568
Mathew Inwood04194fe2018-04-04 14:48:03 +0100569 /**
570 * Set the precentage of detected hidden API accesses that are logged to the event log.
571 *
572 * <p>This rate will take affect for all new processes forked from the zygote after this call.
573 *
574 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
575 */
576 public void setHiddenApiAccessLogSampleRate(int rate) {
577 synchronized (mLock) {
578 mHiddenApiAccessLogSampleRate = rate;
579 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
580 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
581 }
582 }
583
Mathew Inwood8faeab82018-03-16 14:26:08 +0000584 @GuardedBy("mLock")
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100585 private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000586 if (state == null || state.isClosed()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100587 Slog.e(LOG_TAG, "Can't set API blacklist exemptions: no zygote connection");
588 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000589 }
590 if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100591 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000592 }
593 try {
594 state.writer.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
595 state.writer.newLine();
596 state.writer.write("--set-api-blacklist-exemptions");
597 state.writer.newLine();
598 for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
599 state.writer.write(mApiBlacklistExemptions.get(i));
600 state.writer.newLine();
601 }
602 state.writer.flush();
603 int status = state.inputStream.readInt();
604 if (status != 0) {
605 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
606 }
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100607 return true;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000608 } catch (IOException ioe) {
609 Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
Mathew Inwood9f6bb5b2018-04-09 17:29:12 +0100610 mApiBlacklistExemptions = Collections.emptyList();
611 return false;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000612 }
613 }
614
Mathew Inwood04194fe2018-04-04 14:48:03 +0100615 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
616 if (state == null || state.isClosed()) {
617 return;
618 }
619 if (mHiddenApiAccessLogSampleRate == -1) {
620 return;
621 }
622 try {
623 state.writer.write(Integer.toString(1));
624 state.writer.newLine();
625 state.writer.write("--hidden-api-log-sampling-rate="
626 + Integer.toString(mHiddenApiAccessLogSampleRate));
627 state.writer.newLine();
628 state.writer.flush();
629 int status = state.inputStream.readInt();
630 if (status != 0) {
631 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
632 }
633 } catch (IOException ioe) {
634 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
635 }
636 }
637
Mathew Inwood8faeab82018-03-16 14:26:08 +0000638 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400639 * Tries to open socket to Zygote process if not already open. If
Robert Sesekded20982016-08-15 13:59:13 -0400640 * already open, does nothing. May block and retry. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400641 */
Robert Sesekded20982016-08-15 13:59:13 -0400642 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400643 private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400644 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
645
Robert Sesek8f8d1872016-03-18 16:52:57 -0400646 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
647 try {
648 primaryZygoteState = ZygoteState.connect(mSocket);
649 } catch (IOException ioe) {
650 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
651 }
Mathew Inwood8faeab82018-03-16 14:26:08 +0000652 maybeSetApiBlacklistExemptions(primaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100653 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400654 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400655 if (primaryZygoteState.matches(abi)) {
656 return primaryZygoteState;
657 }
658
659 // The primary zygote didn't match. Try the secondary.
660 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
661 try {
662 secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
663 } catch (IOException ioe) {
664 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
665 }
Mathew Inwood8faeab82018-03-16 14:26:08 +0000666 maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100667 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400668 }
669
670 if (secondaryZygoteState.matches(abi)) {
671 return secondaryZygoteState;
672 }
673
674 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
675 }
Robert Sesekded20982016-08-15 13:59:13 -0400676
677 /**
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100678 * Instructs the zygote to pre-load the application code for the given Application.
679 * Only the app zygote supports this function.
680 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
681 */
682 public boolean preloadApp(ApplicationInfo appInfo, String abi) throws ZygoteStartFailedEx,
683 IOException {
684 synchronized (mLock) {
685 ZygoteState state = openZygoteSocketIfNeeded(abi);
686 state.writer.write("2");
687 state.writer.newLine();
688
689 state.writer.write("--preload-app");
690 state.writer.newLine();
691
692 // Zygote args needs to be strings, so in order to pass ApplicationInfo,
693 // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
694 Parcel parcel = Parcel.obtain();
695 appInfo.writeToParcel(parcel, 0 /* flags */);
696 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
697 parcel.recycle();
698 state.writer.write(encodedParcelData);
699 state.writer.newLine();
700
701 state.writer.flush();
702
703 return (state.inputStream.readInt() == 0);
704 }
705 }
706
707 /**
Robert Sesekded20982016-08-15 13:59:13 -0400708 * Instructs the zygote to pre-load the classes and native libraries at the given paths
709 * for the specified abi. Not all zygotes support this function.
710 */
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500711 public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName,
712 String cacheKey, String abi) throws ZygoteStartFailedEx,
713 IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400714 synchronized(mLock) {
715 ZygoteState state = openZygoteSocketIfNeeded(abi);
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500716 state.writer.write("5");
Robert Sesekded20982016-08-15 13:59:13 -0400717 state.writer.newLine();
718
719 state.writer.write("--preload-package");
720 state.writer.newLine();
721
722 state.writer.write(packagePath);
723 state.writer.newLine();
724
725 state.writer.write(libsPath);
726 state.writer.newLine();
727
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500728 state.writer.write(libFileName);
729 state.writer.newLine();
730
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000731 state.writer.write(cacheKey);
732 state.writer.newLine();
733
Robert Sesekded20982016-08-15 13:59:13 -0400734 state.writer.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100735
736 return (state.inputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400737 }
738 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000739
740 /**
741 * Instructs the zygote to preload the default set of classes and resources. Returns
742 * {@code true} if a preload was performed as a result of this call, and {@code false}
743 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
744 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
745 */
746 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
747 synchronized (mLock) {
748 ZygoteState state = openZygoteSocketIfNeeded(abi);
749 // Each query starts with the argument count (1 in this case)
750 state.writer.write("1");
751 state.writer.newLine();
752 state.writer.write("--preload-default");
753 state.writer.newLine();
754 state.writer.flush();
755
756 return (state.inputStream.readInt() == 0);
757 }
758 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100759
760 /**
761 * Try connecting to the Zygote over and over again until we hit a time-out.
762 * @param socketName The name of the socket to connect to.
763 */
764 public static void waitForConnectionToZygote(String socketName) {
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500765 final LocalSocketAddress address =
766 new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED);
767 waitForConnectionToZygote(address);
768 }
769
770 /**
771 * Try connecting to the Zygote over and over again until we hit a time-out.
772 * @param address The name of the socket to connect to.
773 */
774 public static void waitForConnectionToZygote(LocalSocketAddress address) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100775 for (int n = 20; n >= 0; n--) {
776 try {
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500777 final ZygoteState zs = ZygoteState.connect(address);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100778 zs.close();
779 return;
780 } catch (IOException ioe) {
781 Log.w(LOG_TAG,
782 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
783 }
784
785 try {
786 Thread.sleep(1000);
787 } catch (InterruptedException ie) {
788 }
789 }
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500790 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100791 }
Robert Sesekd0a190df2018-02-12 18:46:01 -0500792
793 /**
794 * Starts a new zygote process as a child of this zygote. This is used to create
795 * secondary zygotes that inherit data from the zygote that this object
796 * communicates with. This returns a new ZygoteProcess representing a connection
797 * to the newly created zygote. Throws an exception if the zygote cannot be started.
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100798 *
799 * @param processClass The class to use as the child zygote's main entry
800 * point.
801 * @param niceName A more readable name to use for the process.
802 * @param uid The user-id under which the child zygote will run.
803 * @param gid The group-id under which the child zygote will run.
804 * @param gids Additional group-ids associated with the child zygote process.
805 * @param runtimeFlags Additional flags.
806 * @param seInfo null-ok SELinux information for the child zygote process.
807 * @param abi non-null the ABI of the child zygote
808 * @param acceptedAbiList ABIs this child zygote will accept connections for; this
809 * may be different from <code>abi</code> in case the children
810 * spawned from this Zygote only communicate using ABI-safe methods.
811 * @param instructionSet null-ok the instruction set to use.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500812 */
813 public ChildZygoteProcess startChildZygote(final String processClass,
814 final String niceName,
815 int uid, int gid, int[] gids,
816 int runtimeFlags,
817 String seInfo,
818 String abi,
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100819 String acceptedAbiList,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500820 String instructionSet) {
821 // Create an unguessable address in the global abstract namespace.
822 final LocalSocketAddress serverAddress = new LocalSocketAddress(
823 processClass + "/" + UUID.randomUUID().toString());
824
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100825 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
826 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList};
Robert Sesekd0a190df2018-02-12 18:46:01 -0500827
828 Process.ProcessStartResult result;
829 try {
830 result = startViaZygote(processClass, niceName, uid, gid,
831 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
832 abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700833 true /* startChildZygote */, null /* packageName */,
834 null /* packagesForUid */, null /* visibleVolumes */, extraArgs);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500835 } catch (ZygoteStartFailedEx ex) {
836 throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
837 }
838
839 return new ChildZygoteProcess(serverAddress, result.pid);
840 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400841}