1 /* 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 17 package android.os; 18 19 import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; 20 import static android.os.Process.ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.compat.annotation.UnsupportedAppUsage; 25 import android.content.pm.ApplicationInfo; 26 import android.net.LocalSocket; 27 import android.net.LocalSocketAddress; 28 import android.util.Log; 29 import android.util.Pair; 30 import android.util.Slog; 31 32 import com.android.internal.annotations.GuardedBy; 33 import com.android.internal.os.Zygote; 34 import com.android.internal.os.ZygoteConfig; 35 36 import java.io.BufferedWriter; 37 import java.io.DataInputStream; 38 import java.io.IOException; 39 import java.io.OutputStreamWriter; 40 import java.nio.charset.StandardCharsets; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.Base64; 44 import java.util.Collections; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.UUID; 48 49 /*package*/ class ZygoteStartFailedEx extends Exception { 50 @UnsupportedAppUsage ZygoteStartFailedEx(String s)51 ZygoteStartFailedEx(String s) { 52 super(s); 53 } 54 55 @UnsupportedAppUsage ZygoteStartFailedEx(Throwable cause)56 ZygoteStartFailedEx(Throwable cause) { 57 super(cause); 58 } 59 ZygoteStartFailedEx(String s, Throwable cause)60 ZygoteStartFailedEx(String s, Throwable cause) { 61 super(s, cause); 62 } 63 } 64 65 /** 66 * Maintains communication state with the zygote processes. This class is responsible 67 * for the sockets opened to the zygotes and for starting processes on behalf of the 68 * {@link android.os.Process} class. 69 * 70 * {@hide} 71 */ 72 public class ZygoteProcess { 73 74 private static final int ZYGOTE_CONNECT_TIMEOUT_MS = 60000; 75 76 /** 77 * Use a relatively short delay, because for app zygote, this is in the critical path of 78 * service launch. 79 */ 80 private static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50; 81 82 private static final String LOG_TAG = "ZygoteProcess"; 83 84 /** 85 * The name of the socket used to communicate with the primary zygote. 86 */ 87 private final LocalSocketAddress mZygoteSocketAddress; 88 89 /** 90 * The name of the secondary (alternate ABI) zygote socket. 91 */ 92 private final LocalSocketAddress mZygoteSecondarySocketAddress; 93 94 /** 95 * The name of the socket used to communicate with the primary USAP pool. 96 */ 97 private final LocalSocketAddress mUsapPoolSocketAddress; 98 99 /** 100 * The name of the socket used to communicate with the secondary (alternate ABI) USAP pool. 101 */ 102 private final LocalSocketAddress mUsapPoolSecondarySocketAddress; 103 ZygoteProcess()104 public ZygoteProcess() { 105 mZygoteSocketAddress = 106 new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME, 107 LocalSocketAddress.Namespace.RESERVED); 108 mZygoteSecondarySocketAddress = 109 new LocalSocketAddress(Zygote.SECONDARY_SOCKET_NAME, 110 LocalSocketAddress.Namespace.RESERVED); 111 112 mUsapPoolSocketAddress = 113 new LocalSocketAddress(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME, 114 LocalSocketAddress.Namespace.RESERVED); 115 mUsapPoolSecondarySocketAddress = 116 new LocalSocketAddress(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME, 117 LocalSocketAddress.Namespace.RESERVED); 118 119 // This constructor is used to create the primary and secondary Zygotes, which can support 120 // Unspecialized App Process Pools. 121 mUsapPoolSupported = true; 122 } 123 ZygoteProcess(LocalSocketAddress primarySocketAddress, LocalSocketAddress secondarySocketAddress)124 public ZygoteProcess(LocalSocketAddress primarySocketAddress, 125 LocalSocketAddress secondarySocketAddress) { 126 mZygoteSocketAddress = primarySocketAddress; 127 mZygoteSecondarySocketAddress = secondarySocketAddress; 128 129 mUsapPoolSocketAddress = null; 130 mUsapPoolSecondarySocketAddress = null; 131 132 // This constructor is used to create the primary and secondary Zygotes, which CAN NOT 133 // support Unspecialized App Process Pools. 134 mUsapPoolSupported = false; 135 } 136 getPrimarySocketAddress()137 public LocalSocketAddress getPrimarySocketAddress() { 138 return mZygoteSocketAddress; 139 } 140 141 /** 142 * State for communicating with the zygote process. 143 */ 144 private static class ZygoteState implements AutoCloseable { 145 final LocalSocketAddress mZygoteSocketAddress; 146 final LocalSocketAddress mUsapSocketAddress; 147 148 private final LocalSocket mZygoteSessionSocket; 149 150 final DataInputStream mZygoteInputStream; 151 final BufferedWriter mZygoteOutputWriter; 152 153 private final List<String> mAbiList; 154 155 private boolean mClosed; 156 ZygoteState(LocalSocketAddress zygoteSocketAddress, LocalSocketAddress usapSocketAddress, LocalSocket zygoteSessionSocket, DataInputStream zygoteInputStream, BufferedWriter zygoteOutputWriter, List<String> abiList)157 private ZygoteState(LocalSocketAddress zygoteSocketAddress, 158 LocalSocketAddress usapSocketAddress, 159 LocalSocket zygoteSessionSocket, 160 DataInputStream zygoteInputStream, 161 BufferedWriter zygoteOutputWriter, 162 List<String> abiList) { 163 this.mZygoteSocketAddress = zygoteSocketAddress; 164 this.mUsapSocketAddress = usapSocketAddress; 165 this.mZygoteSessionSocket = zygoteSessionSocket; 166 this.mZygoteInputStream = zygoteInputStream; 167 this.mZygoteOutputWriter = zygoteOutputWriter; 168 this.mAbiList = abiList; 169 } 170 171 /** 172 * Create a new ZygoteState object by connecting to the given Zygote socket and saving the 173 * given USAP socket address. 174 * 175 * @param zygoteSocketAddress Zygote socket to connect to 176 * @param usapSocketAddress USAP socket address to save for later 177 * @return A new ZygoteState object containing a session socket for the given Zygote socket 178 * address 179 * @throws IOException 180 */ connect(@onNull LocalSocketAddress zygoteSocketAddress, @Nullable LocalSocketAddress usapSocketAddress)181 static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress, 182 @Nullable LocalSocketAddress usapSocketAddress) 183 throws IOException { 184 185 DataInputStream zygoteInputStream; 186 BufferedWriter zygoteOutputWriter; 187 final LocalSocket zygoteSessionSocket = new LocalSocket(); 188 189 if (zygoteSocketAddress == null) { 190 throw new IllegalArgumentException("zygoteSocketAddress can't be null"); 191 } 192 193 try { 194 zygoteSessionSocket.connect(zygoteSocketAddress); 195 zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream()); 196 zygoteOutputWriter = 197 new BufferedWriter( 198 new OutputStreamWriter(zygoteSessionSocket.getOutputStream()), 199 Zygote.SOCKET_BUFFER_SIZE); 200 } catch (IOException ex) { 201 try { 202 zygoteSessionSocket.close(); 203 } catch (IOException ignore) { } 204 205 throw ex; 206 } 207 208 return new ZygoteState(zygoteSocketAddress, usapSocketAddress, 209 zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter, 210 getAbiList(zygoteOutputWriter, zygoteInputStream)); 211 } 212 getUsapSessionSocket()213 LocalSocket getUsapSessionSocket() throws IOException { 214 final LocalSocket usapSessionSocket = new LocalSocket(); 215 usapSessionSocket.connect(this.mUsapSocketAddress); 216 217 return usapSessionSocket; 218 } 219 matches(String abi)220 boolean matches(String abi) { 221 return mAbiList.contains(abi); 222 } 223 close()224 public void close() { 225 try { 226 mZygoteSessionSocket.close(); 227 } catch (IOException ex) { 228 Log.e(LOG_TAG,"I/O exception on routine close", ex); 229 } 230 231 mClosed = true; 232 } 233 isClosed()234 boolean isClosed() { 235 return mClosed; 236 } 237 } 238 239 /** 240 * Lock object to protect access to the two ZygoteStates below. This lock must be 241 * acquired while communicating over the ZygoteState's socket, to prevent 242 * interleaved access. 243 */ 244 private final Object mLock = new Object(); 245 246 /** 247 * List of exemptions to the API deny list. These are prefix matches on the runtime format 248 * symbol signature. Any matching symbol is treated by the runtime as being on the light grey 249 * list. 250 */ 251 private List<String> mApiDenylistExemptions = Collections.emptyList(); 252 253 /** 254 * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000. 255 */ 256 private int mHiddenApiAccessLogSampleRate; 257 258 /** 259 * Proportion of hidden API accesses that should be logged to statslog; 0 - 0x10000. 260 */ 261 private int mHiddenApiAccessStatslogSampleRate; 262 263 /** 264 * The state of the connection to the primary zygote. 265 */ 266 private ZygoteState primaryZygoteState; 267 268 /** 269 * The state of the connection to the secondary zygote. 270 */ 271 private ZygoteState secondaryZygoteState; 272 273 /** 274 * If this Zygote supports the creation and maintenance of a USAP pool. 275 * 276 * Currently only the primary and secondary Zygotes support USAP pools. Any 277 * child Zygotes will be unable to create or use a USAP pool. 278 */ 279 private final boolean mUsapPoolSupported; 280 281 /** 282 * If the USAP pool should be created and used to start applications. 283 * 284 * Setting this value to false will disable the creation, maintenance, and use of the USAP 285 * pool. When the USAP pool is disabled the application lifecycle will be identical to 286 * previous versions of Android. 287 */ 288 private boolean mUsapPoolEnabled = false; 289 290 /** 291 * Start a new process. 292 * 293 * <p>If processes are enabled, a new process is created and the 294 * static main() function of a <var>processClass</var> is executed there. 295 * The process will continue running after this function returns. 296 * 297 * <p>If processes are not enabled, a new thread in the caller's 298 * process is created and main() of <var>processclass</var> called there. 299 * 300 * <p>The niceName parameter, if not an empty string, is a custom name to 301 * give to the process instead of using processClass. This allows you to 302 * make easily identifyable processes even if you are using the same base 303 * <var>processClass</var> to start them. 304 * 305 * When invokeWith is not null, the process will be started as a fresh app 306 * and not a zygote fork. Note that this is only allowed for uid 0 or when 307 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER. 308 * 309 * @param processClass The class to use as the process's main entry 310 * point. 311 * @param niceName A more readable name to use for the process. 312 * @param uid The user-id under which the process will run. 313 * @param gid The group-id under which the process will run. 314 * @param gids Additional group-ids associated with the process. 315 * @param runtimeFlags Additional flags. 316 * @param targetSdkVersion The target SDK version for the app. 317 * @param seInfo null-ok SELinux information for the new process. 318 * @param abi non-null the ABI this app should be started with. 319 * @param instructionSet null-ok the instruction set to use. 320 * @param appDataDir null-ok the data directory of the app. 321 * @param invokeWith null-ok the command to invoke with. 322 * @param packageName null-ok the name of the package this process belongs to. 323 * @param zygotePolicyFlags Flags used to determine how to launch the application. 324 * @param isTopApp Whether the process starts for high priority application. 325 * @param disabledCompatChanges null-ok list of disabled compat changes for the process being 326 * started. 327 * @param pkgDataInfoMap Map from related package names to private data directory 328 * volume UUID and inode number. 329 * @param allowlistedDataInfoList Map from allowlisted package names to private data directory 330 * volume UUID and inode number. 331 * @param bindMountAppsData whether zygote needs to mount CE and DE data. 332 * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. 333 * 334 * @param zygoteArgs Additional arguments to supply to the Zygote process. 335 * @return An object that describes the result of the attempt to start the process. 336 * @throws RuntimeException on fatal start failure 337 */ start(@onNull final String processClass, final String niceName, int uid, int gid, @Nullable int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, int zygotePolicyFlags, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, boolean bindOverrideSysprops, @Nullable String[] zygoteArgs)338 public final Process.ProcessStartResult start(@NonNull final String processClass, 339 final String niceName, 340 int uid, int gid, @Nullable int[] gids, 341 int runtimeFlags, int mountExternal, 342 int targetSdkVersion, 343 @Nullable String seInfo, 344 @NonNull String abi, 345 @Nullable String instructionSet, 346 @Nullable String appDataDir, 347 @Nullable String invokeWith, 348 @Nullable String packageName, 349 int zygotePolicyFlags, 350 boolean isTopApp, 351 @Nullable long[] disabledCompatChanges, 352 @Nullable Map<String, Pair<String, Long>> 353 pkgDataInfoMap, 354 @Nullable Map<String, Pair<String, Long>> 355 allowlistedDataInfoList, 356 boolean bindMountAppsData, 357 boolean bindMountAppStorageDirs, 358 boolean bindOverrideSysprops, 359 @Nullable String[] zygoteArgs) { 360 // TODO (chriswailes): Is there a better place to check this value? 361 if (fetchUsapPoolEnabledPropWithMinInterval()) { 362 informZygotesOfUsapPoolStatus(); 363 } 364 365 try { 366 return startViaZygote(processClass, niceName, uid, gid, gids, 367 runtimeFlags, mountExternal, targetSdkVersion, seInfo, 368 abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, 369 packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, 370 pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData, 371 bindMountAppStorageDirs, bindOverrideSysprops, zygoteArgs); 372 } catch (ZygoteStartFailedEx ex) { 373 Log.e(LOG_TAG, 374 "Starting VM process through Zygote failed"); 375 throw new RuntimeException( 376 "Starting VM process through Zygote failed", ex); 377 } 378 } 379 380 /** retry interval for opening a zygote socket */ 381 static final int ZYGOTE_RETRY_MILLIS = 500; 382 383 /** 384 * Queries the zygote for the list of ABIS it supports. 385 */ 386 @GuardedBy("mLock") getAbiList(BufferedWriter writer, DataInputStream inputStream)387 private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream) 388 throws IOException { 389 // Each query starts with the argument count (1 in this case) 390 writer.write("1"); 391 // ... followed by a new-line. 392 writer.newLine(); 393 // ... followed by our only argument. 394 writer.write("--query-abi-list"); 395 writer.newLine(); 396 writer.flush(); 397 398 // The response is a length prefixed stream of ASCII bytes. 399 int numBytes = inputStream.readInt(); 400 byte[] bytes = new byte[numBytes]; 401 inputStream.readFully(bytes); 402 403 final String rawList = new String(bytes, StandardCharsets.US_ASCII); 404 405 return Arrays.asList(rawList.split(",")); 406 } 407 408 /** 409 * Sends an argument list to the zygote process, which starts a new child 410 * and returns the child's pid. Please note: the present implementation 411 * replaces newlines in the argument list with spaces. 412 * 413 * @throws ZygoteStartFailedEx if process start failed for any reason 414 */ 415 @GuardedBy("mLock") zygoteSendArgsAndGetResult( ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)416 private Process.ProcessStartResult zygoteSendArgsAndGetResult( 417 ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args) 418 throws ZygoteStartFailedEx { 419 // Throw early if any of the arguments are malformed. This means we can 420 // avoid writing a partial response to the zygote. 421 for (String arg : args) { 422 // Making two indexOf calls here is faster than running a manually fused loop due 423 // to the fact that indexOf is an optimized intrinsic. 424 if (arg.indexOf('\n') >= 0) { 425 throw new ZygoteStartFailedEx("Embedded newlines not allowed"); 426 } else if (arg.indexOf('\r') >= 0) { 427 throw new ZygoteStartFailedEx("Embedded carriage returns not allowed"); 428 } else if (arg.indexOf('\u0000') >= 0) { 429 throw new ZygoteStartFailedEx("Embedded nulls not allowed"); 430 } 431 } 432 433 /* 434 * See com.android.internal.os.ZygoteArguments.parseArgs() 435 * Presently the wire format to the zygote process is: 436 * a) a count of arguments (argc, in essence) 437 * b) a number of newline-separated argument strings equal to count 438 * 439 * After the zygote process reads these it will write the pid of 440 * the child or -1 on failure, followed by boolean to 441 * indicate whether a wrapper process was used. 442 */ 443 String msgStr = args.size() + "\n" + String.join("\n", args) + "\n"; 444 445 if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) { 446 try { 447 return attemptUsapSendArgsAndGetResult(zygoteState, msgStr); 448 } catch (IOException ex) { 449 // If there was an IOException using the USAP pool we will log the error and 450 // attempt to start the process through the Zygote. 451 Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - " 452 + ex.getMessage()); 453 } 454 } 455 456 return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr); 457 } 458 attemptZygoteSendArgsAndGetResult( ZygoteState zygoteState, String msgStr)459 private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult( 460 ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx { 461 try { 462 final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter; 463 final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream; 464 465 zygoteWriter.write(msgStr); 466 zygoteWriter.flush(); 467 468 // Always read the entire result from the input stream to avoid leaving 469 // bytes in the stream for future process starts to accidentally stumble 470 // upon. 471 Process.ProcessStartResult result = new Process.ProcessStartResult(); 472 result.pid = zygoteInputStream.readInt(); 473 result.usingWrapper = zygoteInputStream.readBoolean(); 474 475 if (result.pid < 0) { 476 throw new ZygoteStartFailedEx("fork() failed"); 477 } 478 479 return result; 480 } catch (IOException ex) { 481 zygoteState.close(); 482 Log.e(LOG_TAG, "IO Exception while communicating with Zygote - " 483 + ex.toString()); 484 throw new ZygoteStartFailedEx(ex); 485 } 486 } 487 attemptUsapSendArgsAndGetResult( ZygoteState zygoteState, String msgStr)488 private Process.ProcessStartResult attemptUsapSendArgsAndGetResult( 489 ZygoteState zygoteState, String msgStr) 490 throws ZygoteStartFailedEx, IOException { 491 try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) { 492 final BufferedWriter usapWriter = 493 new BufferedWriter( 494 new OutputStreamWriter(usapSessionSocket.getOutputStream()), 495 Zygote.SOCKET_BUFFER_SIZE); 496 final DataInputStream usapReader = 497 new DataInputStream(usapSessionSocket.getInputStream()); 498 499 usapWriter.write(msgStr); 500 usapWriter.flush(); 501 502 Process.ProcessStartResult result = new Process.ProcessStartResult(); 503 result.pid = usapReader.readInt(); 504 // USAPs can't be used to spawn processes that need wrappers. 505 result.usingWrapper = false; 506 507 if (result.pid >= 0) { 508 return result; 509 } else { 510 throw new ZygoteStartFailedEx("USAP specialization failed"); 511 } 512 } 513 } 514 515 /** 516 * Test various member properties and parameters to determine if a launch event should be 517 * handled using an Unspecialized App Process Pool or not. 518 * 519 * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the 520 * Zygote command 521 * @param args Arguments that will be passed to the Zygote 522 * @return If the command should be sent to a USAP Pool member or an actual Zygote 523 */ shouldAttemptUsapLaunch(int zygotePolicyFlags, ArrayList<String> args)524 private boolean shouldAttemptUsapLaunch(int zygotePolicyFlags, ArrayList<String> args) { 525 return mUsapPoolSupported 526 && mUsapPoolEnabled 527 && policySpecifiesUsapPoolLaunch(zygotePolicyFlags) 528 && commandSupportedByUsap(args); 529 } 530 531 /** 532 * Tests a Zygote policy flag set for various properties that determine if it is eligible for 533 * being handled by an Unspecialized App Process Pool. 534 * 535 * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the 536 * Zygote command 537 * @return If the policy allows for use of a USAP pool 538 */ policySpecifiesUsapPoolLaunch(int zygotePolicyFlags)539 private static boolean policySpecifiesUsapPoolLaunch(int zygotePolicyFlags) { 540 /* 541 * Zygote USAP Pool Policy: Launch the new process from the USAP Pool iff the launch event 542 * is latency sensitive but *NOT* a system process. All system processes are equally 543 * important so we don't want to prioritize one over another. 544 */ 545 return (zygotePolicyFlags 546 & (ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS | ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE)) 547 == ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; 548 } 549 550 /** 551 * Flags that may not be passed to a USAP. These may appear as prefixes to individual Zygote 552 * arguments. 553 */ 554 private static final String[] INVALID_USAP_FLAGS = { 555 "--query-abi-list", 556 "--get-pid", 557 "--preload-default", 558 "--preload-package", 559 "--preload-app", 560 "--start-child-zygote", 561 "--set-api-denylist-exemptions", 562 "--hidden-api-log-sampling-rate", 563 "--hidden-api-statslog-sampling-rate", 564 "--invoke-with" 565 }; 566 567 /** 568 * Tests a command list to see if it is valid to send to a USAP. 569 * 570 * @param args Zygote/USAP command arguments 571 * @return True if the command can be passed to a USAP; false otherwise 572 */ commandSupportedByUsap(ArrayList<String> args)573 private static boolean commandSupportedByUsap(ArrayList<String> args) { 574 for (String flag : args) { 575 for (String badFlag : INVALID_USAP_FLAGS) { 576 if (flag.startsWith(badFlag)) { 577 return false; 578 } 579 } 580 if (flag.startsWith("--nice-name=")) { 581 // Check if the wrap property is set, usap would ignore it. 582 if (Zygote.getWrapProperty(flag.substring(12)) != null) { 583 return false; 584 } 585 } 586 } 587 588 return true; 589 } 590 591 /** 592 * Starts a new process via the zygote mechanism. 593 * 594 * @param processClass Class name whose static main() to run 595 * @param niceName 'nice' process name to appear in ps 596 * @param uid a POSIX uid that the new process should setuid() to 597 * @param gid a POSIX gid that the new process shuold setgid() to 598 * @param gids null-ok; a list of supplementary group IDs that the 599 * new process should setgroup() to. 600 * @param runtimeFlags Additional flags for the runtime. 601 * @param targetSdkVersion The target SDK version for the app. 602 * @param seInfo null-ok SELinux information for the new process. 603 * @param abi the ABI the process should use. 604 * @param instructionSet null-ok the instruction set to use. 605 * @param appDataDir null-ok the data directory of the app. 606 * @param startChildZygote Start a sub-zygote. This creates a new zygote process 607 * that has its state cloned from this zygote process. 608 * @param packageName null-ok the name of the package this process belongs to. 609 * @param zygotePolicyFlags Flags used to determine how to launch the application. 610 * @param isTopApp Whether the process starts for high priority application. 611 * @param disabledCompatChanges a list of disabled compat changes for the process being started. 612 * @param pkgDataInfoMap Map from related package names to private data directory volume UUID 613 * and inode number. 614 * @param allowlistedDataInfoList Map from allowlisted package names to private data directory 615 * volume UUID and inode number. 616 * @param bindMountAppsData whether zygote needs to mount CE and DE data. 617 * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. 618 * @param extraArgs Additional arguments to supply to the zygote process. 619 * @return An object that describes the result of the attempt to start the process. 620 * @throws ZygoteStartFailedEx if process start failed for any reason 621 */ startViaZygote(@onNull final String processClass, @Nullable final String niceName, final int uid, final int gid, @Nullable final int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String invokeWith, boolean startChildZygote, @Nullable String packageName, int zygotePolicyFlags, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, boolean bindMountOverrideSysprops, @Nullable String[] extraArgs)622 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass, 623 @Nullable final String niceName, 624 final int uid, final int gid, 625 @Nullable final int[] gids, 626 int runtimeFlags, int mountExternal, 627 int targetSdkVersion, 628 @Nullable String seInfo, 629 @NonNull String abi, 630 @Nullable String instructionSet, 631 @Nullable String appDataDir, 632 @Nullable String invokeWith, 633 boolean startChildZygote, 634 @Nullable String packageName, 635 int zygotePolicyFlags, 636 boolean isTopApp, 637 @Nullable long[] disabledCompatChanges, 638 @Nullable Map<String, Pair<String, Long>> 639 pkgDataInfoMap, 640 @Nullable Map<String, Pair<String, Long>> 641 allowlistedDataInfoList, 642 boolean bindMountAppsData, 643 boolean bindMountAppStorageDirs, 644 boolean bindMountOverrideSysprops, 645 @Nullable String[] extraArgs) 646 throws ZygoteStartFailedEx { 647 ArrayList<String> argsForZygote = new ArrayList<>(); 648 649 // --runtime-args, --setuid=, --setgid=, 650 // and --setgroups= must go first 651 argsForZygote.add("--runtime-args"); 652 argsForZygote.add("--setuid=" + uid); 653 argsForZygote.add("--setgid=" + gid); 654 argsForZygote.add("--runtime-flags=" + runtimeFlags); 655 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) { 656 argsForZygote.add("--mount-external-default"); 657 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) { 658 argsForZygote.add("--mount-external-installer"); 659 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) { 660 argsForZygote.add("--mount-external-pass-through"); 661 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) { 662 argsForZygote.add("--mount-external-android-writable"); 663 } 664 665 argsForZygote.add("--target-sdk-version=" + targetSdkVersion); 666 667 // --setgroups is a comma-separated list 668 if (gids != null && gids.length > 0) { 669 final StringBuilder sb = new StringBuilder(); 670 sb.append("--setgroups="); 671 672 final int sz = gids.length; 673 for (int i = 0; i < sz; i++) { 674 if (i != 0) { 675 sb.append(','); 676 } 677 sb.append(gids[i]); 678 } 679 680 argsForZygote.add(sb.toString()); 681 } 682 683 if (niceName != null) { 684 argsForZygote.add("--nice-name=" + niceName); 685 } 686 687 if (seInfo != null) { 688 argsForZygote.add("--seinfo=" + seInfo); 689 } 690 691 if (instructionSet != null) { 692 argsForZygote.add("--instruction-set=" + instructionSet); 693 } 694 695 if (appDataDir != null) { 696 argsForZygote.add("--app-data-dir=" + appDataDir); 697 } 698 699 if (invokeWith != null) { 700 argsForZygote.add("--invoke-with"); 701 argsForZygote.add(invokeWith); 702 } 703 704 if (startChildZygote) { 705 argsForZygote.add("--start-child-zygote"); 706 } 707 708 if (packageName != null) { 709 argsForZygote.add("--package-name=" + packageName); 710 } 711 712 if (isTopApp) { 713 argsForZygote.add(Zygote.START_AS_TOP_APP_ARG); 714 } 715 if (pkgDataInfoMap != null && pkgDataInfoMap.size() > 0) { 716 StringBuilder sb = new StringBuilder(); 717 sb.append(Zygote.PKG_DATA_INFO_MAP); 718 sb.append("="); 719 boolean started = false; 720 for (Map.Entry<String, Pair<String, Long>> entry : pkgDataInfoMap.entrySet()) { 721 if (started) { 722 sb.append(','); 723 } 724 started = true; 725 sb.append(entry.getKey()); 726 sb.append(','); 727 sb.append(entry.getValue().first); 728 sb.append(','); 729 sb.append(entry.getValue().second); 730 } 731 argsForZygote.add(sb.toString()); 732 } 733 if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) { 734 StringBuilder sb = new StringBuilder(); 735 sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP); 736 sb.append("="); 737 boolean started = false; 738 for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) { 739 if (started) { 740 sb.append(','); 741 } 742 started = true; 743 sb.append(entry.getKey()); 744 sb.append(','); 745 sb.append(entry.getValue().first); 746 sb.append(','); 747 sb.append(entry.getValue().second); 748 } 749 argsForZygote.add(sb.toString()); 750 } 751 752 if (bindMountAppStorageDirs) { 753 argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS); 754 } 755 756 if (bindMountAppsData) { 757 argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS); 758 } 759 760 if (bindMountOverrideSysprops) { 761 argsForZygote.add(Zygote.BIND_MOUNT_SYSPROP_OVERRIDES); 762 } 763 764 if (disabledCompatChanges != null && disabledCompatChanges.length > 0) { 765 StringBuilder sb = new StringBuilder(); 766 sb.append("--disabled-compat-changes="); 767 768 int sz = disabledCompatChanges.length; 769 for (int i = 0; i < sz; i++) { 770 if (i != 0) { 771 sb.append(','); 772 } 773 sb.append(disabledCompatChanges[i]); 774 } 775 776 argsForZygote.add(sb.toString()); 777 } 778 779 argsForZygote.add(processClass); 780 781 if (extraArgs != null) { 782 Collections.addAll(argsForZygote, extraArgs); 783 } 784 785 synchronized(mLock) { 786 // The USAP pool can not be used if the application will not use the systems graphics 787 // driver. If that driver is requested use the Zygote application start path. 788 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), 789 zygotePolicyFlags, 790 argsForZygote); 791 } 792 } 793 fetchUsapPoolEnabledProp()794 private boolean fetchUsapPoolEnabledProp() { 795 boolean origVal = mUsapPoolEnabled; 796 797 mUsapPoolEnabled = ZygoteConfig.getBool( 798 ZygoteConfig.USAP_POOL_ENABLED, ZygoteConfig.USAP_POOL_ENABLED_DEFAULT); 799 800 boolean valueChanged = origVal != mUsapPoolEnabled; 801 802 if (valueChanged) { 803 Log.i(LOG_TAG, "usapPoolEnabled = " + mUsapPoolEnabled); 804 } 805 806 return valueChanged; 807 } 808 809 private boolean mIsFirstPropCheck = true; 810 private long mLastPropCheckTimestamp = 0; 811 fetchUsapPoolEnabledPropWithMinInterval()812 private boolean fetchUsapPoolEnabledPropWithMinInterval() { 813 // If this Zygote doesn't support USAPs there is no need to fetch any 814 // properties. 815 if (!mUsapPoolSupported) return false; 816 817 final long currentTimestamp = SystemClock.elapsedRealtime(); 818 819 if (mIsFirstPropCheck 820 || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) { 821 mIsFirstPropCheck = false; 822 mLastPropCheckTimestamp = currentTimestamp; 823 return fetchUsapPoolEnabledProp(); 824 } 825 826 return false; 827 } 828 829 /** 830 * Closes the connections to the zygote, if they exist. 831 */ close()832 public void close() { 833 if (primaryZygoteState != null) { 834 primaryZygoteState.close(); 835 } 836 if (secondaryZygoteState != null) { 837 secondaryZygoteState.close(); 838 } 839 } 840 841 /** 842 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block 843 * and retry if the zygote is unresponsive. This method is a no-op if a connection is 844 * already open. 845 */ establishZygoteConnectionForAbi(String abi)846 public void establishZygoteConnectionForAbi(String abi) { 847 try { 848 synchronized(mLock) { 849 openZygoteSocketIfNeeded(abi); 850 } 851 } catch (ZygoteStartFailedEx ex) { 852 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex); 853 } 854 } 855 856 /** 857 * Attempt to retrieve the PID of the zygote serving the given abi. 858 */ getZygotePid(String abi)859 public int getZygotePid(String abi) { 860 try { 861 synchronized (mLock) { 862 ZygoteState state = openZygoteSocketIfNeeded(abi); 863 864 // Each query starts with the argument count (1 in this case) 865 state.mZygoteOutputWriter.write("1"); 866 // ... followed by a new-line. 867 state.mZygoteOutputWriter.newLine(); 868 // ... followed by our only argument. 869 state.mZygoteOutputWriter.write("--get-pid"); 870 state.mZygoteOutputWriter.newLine(); 871 state.mZygoteOutputWriter.flush(); 872 873 // The response is a length prefixed stream of ASCII bytes. 874 int numBytes = state.mZygoteInputStream.readInt(); 875 byte[] bytes = new byte[numBytes]; 876 state.mZygoteInputStream.readFully(bytes); 877 878 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII)); 879 } 880 } catch (Exception ex) { 881 throw new RuntimeException("Failure retrieving pid", ex); 882 } 883 } 884 885 /** 886 * Notify the Zygote processes that boot completed. 887 */ bootCompleted()888 public void bootCompleted() { 889 // Notify both the 32-bit and 64-bit zygote. 890 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 891 bootCompleted(Build.SUPPORTED_32_BIT_ABIS[0]); 892 } 893 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { 894 bootCompleted(Build.SUPPORTED_64_BIT_ABIS[0]); 895 } 896 } 897 bootCompleted(String abi)898 private void bootCompleted(String abi) { 899 try { 900 synchronized (mLock) { 901 ZygoteState state = openZygoteSocketIfNeeded(abi); 902 state.mZygoteOutputWriter.write("1\n--boot-completed\n"); 903 state.mZygoteOutputWriter.flush(); 904 state.mZygoteInputStream.readInt(); 905 } 906 } catch (Exception ex) { 907 throw new RuntimeException("Failed to inform zygote of boot_completed", ex); 908 } 909 } 910 911 /** 912 * Push hidden API deny-listing exemptions into the zygote process(es). 913 * 914 * <p>The list of exemptions will take affect for all new processes forked from the zygote after 915 * this call. 916 * 917 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as 918 * allowed/public APIs (i.e. allowed, no logging of usage). 919 */ setApiDenylistExemptions(List<String> exemptions)920 public boolean setApiDenylistExemptions(List<String> exemptions) { 921 synchronized (mLock) { 922 mApiDenylistExemptions = exemptions; 923 boolean ok = maybeSetApiDenylistExemptions(primaryZygoteState, true); 924 if (ok) { 925 ok = maybeSetApiDenylistExemptions(secondaryZygoteState, true); 926 } 927 return ok; 928 } 929 } 930 931 /** 932 * Set the precentage of detected hidden API accesses that are logged to the event log. 933 * 934 * <p>This rate will take affect for all new processes forked from the zygote after this call. 935 * 936 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging. 937 */ setHiddenApiAccessLogSampleRate(int rate)938 public void setHiddenApiAccessLogSampleRate(int rate) { 939 synchronized (mLock) { 940 mHiddenApiAccessLogSampleRate = rate; 941 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState); 942 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState); 943 } 944 } 945 946 /** 947 * Set the precentage of detected hidden API accesses that are logged to the new event log. 948 * 949 * <p>This rate will take affect for all new processes forked from the zygote after this call. 950 * 951 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging. 952 */ setHiddenApiAccessStatslogSampleRate(int rate)953 public void setHiddenApiAccessStatslogSampleRate(int rate) { 954 synchronized (mLock) { 955 mHiddenApiAccessStatslogSampleRate = rate; 956 maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState); 957 maybeSetHiddenApiAccessStatslogSampleRate(secondaryZygoteState); 958 } 959 } 960 961 @GuardedBy("mLock") maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty)962 private boolean maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty) { 963 if (state == null || state.isClosed()) { 964 Slog.e(LOG_TAG, "Can't set API denylist exemptions: no zygote connection"); 965 return false; 966 } else if (!sendIfEmpty && mApiDenylistExemptions.isEmpty()) { 967 return true; 968 } 969 970 for (/* NonNull */ String s : mApiDenylistExemptions) { 971 // indexOf() is intrinsified and faster than contains(). 972 if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0 || s.indexOf('\u0000') >= 0) { 973 Slog.e(LOG_TAG, "Failed to set API denylist exemptions: Bad character"); 974 mApiDenylistExemptions = Collections.emptyList(); 975 return false; 976 } 977 } 978 try { 979 state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1)); 980 state.mZygoteOutputWriter.newLine(); 981 state.mZygoteOutputWriter.write("--set-api-denylist-exemptions"); 982 state.mZygoteOutputWriter.newLine(); 983 for (int i = 0; i < mApiDenylistExemptions.size(); ++i) { 984 state.mZygoteOutputWriter.write(mApiDenylistExemptions.get(i)); 985 state.mZygoteOutputWriter.newLine(); 986 } 987 state.mZygoteOutputWriter.flush(); 988 int status = state.mZygoteInputStream.readInt(); 989 if (status != 0) { 990 Slog.e(LOG_TAG, "Failed to set API denylist exemptions; status " + status); 991 } 992 return true; 993 } catch (IOException ioe) { 994 Slog.e(LOG_TAG, "Failed to set API denylist exemptions", ioe); 995 mApiDenylistExemptions = Collections.emptyList(); 996 return false; 997 } 998 } 999 maybeSetHiddenApiAccessLogSampleRate(ZygoteState state)1000 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) { 1001 if (state == null || state.isClosed() || mHiddenApiAccessLogSampleRate == -1) { 1002 return; 1003 } 1004 1005 try { 1006 state.mZygoteOutputWriter.write(Integer.toString(1)); 1007 state.mZygoteOutputWriter.newLine(); 1008 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate=" 1009 + mHiddenApiAccessLogSampleRate); 1010 state.mZygoteOutputWriter.newLine(); 1011 state.mZygoteOutputWriter.flush(); 1012 int status = state.mZygoteInputStream.readInt(); 1013 if (status != 0) { 1014 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status); 1015 } 1016 } catch (IOException ioe) { 1017 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe); 1018 } 1019 } 1020 maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state)1021 private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) { 1022 if (state == null || state.isClosed() || mHiddenApiAccessStatslogSampleRate == -1) { 1023 return; 1024 } 1025 1026 try { 1027 state.mZygoteOutputWriter.write(Integer.toString(1)); 1028 state.mZygoteOutputWriter.newLine(); 1029 state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate=" 1030 + mHiddenApiAccessStatslogSampleRate); 1031 state.mZygoteOutputWriter.newLine(); 1032 state.mZygoteOutputWriter.flush(); 1033 int status = state.mZygoteInputStream.readInt(); 1034 if (status != 0) { 1035 Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate; status " 1036 + status); 1037 } 1038 } catch (IOException ioe) { 1039 Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate", ioe); 1040 } 1041 } 1042 1043 /** 1044 * Creates a ZygoteState for the primary zygote if it doesn't exist or has been disconnected. 1045 */ 1046 @GuardedBy("mLock") attemptConnectionToPrimaryZygote()1047 private void attemptConnectionToPrimaryZygote() throws IOException { 1048 if (primaryZygoteState == null || primaryZygoteState.isClosed()) { 1049 primaryZygoteState = 1050 ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress); 1051 1052 maybeSetApiDenylistExemptions(primaryZygoteState, false); 1053 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState); 1054 } 1055 } 1056 1057 /** 1058 * Creates a ZygoteState for the secondary zygote if it doesn't exist or has been disconnected. 1059 */ 1060 @GuardedBy("mLock") attemptConnectionToSecondaryZygote()1061 private void attemptConnectionToSecondaryZygote() throws IOException { 1062 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { 1063 secondaryZygoteState = 1064 ZygoteState.connect(mZygoteSecondarySocketAddress, 1065 mUsapPoolSecondarySocketAddress); 1066 1067 maybeSetApiDenylistExemptions(secondaryZygoteState, false); 1068 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState); 1069 } 1070 } 1071 1072 /** 1073 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not 1074 * already open. If a compatible session socket is already open that session socket is returned. 1075 * This function may block and may have to try connecting to multiple Zygotes to find the 1076 * appropriate one. Requires that mLock be held. 1077 */ 1078 @GuardedBy("mLock") openZygoteSocketIfNeeded(String abi)1079 private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { 1080 try { 1081 attemptConnectionToPrimaryZygote(); 1082 1083 if (primaryZygoteState.matches(abi)) { 1084 return primaryZygoteState; 1085 } 1086 1087 if (mZygoteSecondarySocketAddress != null) { 1088 // The primary zygote didn't match. Try the secondary. 1089 attemptConnectionToSecondaryZygote(); 1090 1091 if (secondaryZygoteState.matches(abi)) { 1092 return secondaryZygoteState; 1093 } 1094 } 1095 } catch (IOException ioe) { 1096 throw new ZygoteStartFailedEx("Error connecting to zygote", ioe); 1097 } 1098 1099 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); 1100 } 1101 1102 /** 1103 * Instructs the zygote to pre-load the application code for the given Application. 1104 * Only the app zygote supports this function. 1105 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead. 1106 */ preloadApp(ApplicationInfo appInfo, String abi)1107 public boolean preloadApp(ApplicationInfo appInfo, String abi) 1108 throws ZygoteStartFailedEx, IOException { 1109 synchronized (mLock) { 1110 ZygoteState state = openZygoteSocketIfNeeded(abi); 1111 state.mZygoteOutputWriter.write("2"); 1112 state.mZygoteOutputWriter.newLine(); 1113 1114 state.mZygoteOutputWriter.write("--preload-app"); 1115 state.mZygoteOutputWriter.newLine(); 1116 1117 // Zygote args needs to be strings, so in order to pass ApplicationInfo, 1118 // write it to a Parcel, and base64 the raw Parcel bytes to the other side. 1119 Parcel parcel = Parcel.obtain(); 1120 appInfo.writeToParcel(parcel, 0 /* flags */); 1121 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall()); 1122 parcel.recycle(); 1123 state.mZygoteOutputWriter.write(encodedParcelData); 1124 state.mZygoteOutputWriter.newLine(); 1125 1126 state.mZygoteOutputWriter.flush(); 1127 1128 return (state.mZygoteInputStream.readInt() == 0); 1129 } 1130 } 1131 1132 /** 1133 * Instructs the zygote to pre-load the classes and native libraries at the given paths 1134 * for the specified abi. Not all zygotes support this function. 1135 */ preloadPackageForAbi( String packagePath, String libsPath, String libFileName, String cacheKey, String abi)1136 public boolean preloadPackageForAbi( 1137 String packagePath, String libsPath, String libFileName, String cacheKey, String abi) 1138 throws ZygoteStartFailedEx, IOException { 1139 synchronized (mLock) { 1140 ZygoteState state = openZygoteSocketIfNeeded(abi); 1141 state.mZygoteOutputWriter.write("5"); 1142 state.mZygoteOutputWriter.newLine(); 1143 1144 state.mZygoteOutputWriter.write("--preload-package"); 1145 state.mZygoteOutputWriter.newLine(); 1146 1147 state.mZygoteOutputWriter.write(packagePath); 1148 state.mZygoteOutputWriter.newLine(); 1149 1150 state.mZygoteOutputWriter.write(libsPath); 1151 state.mZygoteOutputWriter.newLine(); 1152 1153 state.mZygoteOutputWriter.write(libFileName); 1154 state.mZygoteOutputWriter.newLine(); 1155 1156 state.mZygoteOutputWriter.write(cacheKey); 1157 state.mZygoteOutputWriter.newLine(); 1158 1159 state.mZygoteOutputWriter.flush(); 1160 1161 return (state.mZygoteInputStream.readInt() == 0); 1162 } 1163 } 1164 1165 /** 1166 * Instructs the zygote to preload the default set of classes and resources. Returns 1167 * {@code true} if a preload was performed as a result of this call, and {@code false} 1168 * otherwise. The latter usually means that the zygote eagerly preloaded at startup 1169 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous. 1170 */ preloadDefault(String abi)1171 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException { 1172 synchronized (mLock) { 1173 ZygoteState state = openZygoteSocketIfNeeded(abi); 1174 // Each query starts with the argument count (1 in this case) 1175 state.mZygoteOutputWriter.write("1"); 1176 state.mZygoteOutputWriter.newLine(); 1177 state.mZygoteOutputWriter.write("--preload-default"); 1178 state.mZygoteOutputWriter.newLine(); 1179 state.mZygoteOutputWriter.flush(); 1180 1181 return (state.mZygoteInputStream.readInt() == 0); 1182 } 1183 } 1184 1185 /** 1186 * Try connecting to the Zygote over and over again until we hit a time-out. 1187 * @param zygoteSocketName The name of the socket to connect to. 1188 */ waitForConnectionToZygote(String zygoteSocketName)1189 public static void waitForConnectionToZygote(String zygoteSocketName) { 1190 final LocalSocketAddress zygoteSocketAddress = 1191 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED); 1192 waitForConnectionToZygote(zygoteSocketAddress); 1193 } 1194 1195 /** 1196 * Try connecting to the Zygote over and over again until we hit a time-out. 1197 * @param zygoteSocketAddress The name of the socket to connect to. 1198 */ waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress)1199 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) { 1200 int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS; 1201 for (int n = numRetries; n >= 0; n--) { 1202 try { 1203 final ZygoteState zs = 1204 ZygoteState.connect(zygoteSocketAddress, null); 1205 zs.close(); 1206 return; 1207 } catch (IOException ioe) { 1208 Log.w(LOG_TAG, 1209 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage()); 1210 } 1211 1212 try { 1213 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS); 1214 } catch (InterruptedException ignored) { } 1215 } 1216 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " 1217 + zygoteSocketAddress.getName()); 1218 } 1219 1220 /** 1221 * Sends messages to the zygotes telling them to change the status of their USAP pools. If 1222 * this notification fails the ZygoteProcess will fall back to the previous behavior. 1223 */ informZygotesOfUsapPoolStatus()1224 private void informZygotesOfUsapPoolStatus() { 1225 final String command = "1\n--usap-pool-enabled=" + mUsapPoolEnabled + "\n"; 1226 1227 synchronized (mLock) { 1228 try { 1229 attemptConnectionToPrimaryZygote(); 1230 1231 primaryZygoteState.mZygoteOutputWriter.write(command); 1232 primaryZygoteState.mZygoteOutputWriter.flush(); 1233 } catch (IOException ioe) { 1234 mUsapPoolEnabled = !mUsapPoolEnabled; 1235 Log.w(LOG_TAG, "Failed to inform zygotes of USAP pool status: " 1236 + ioe.getMessage()); 1237 return; 1238 } 1239 1240 if (mZygoteSecondarySocketAddress != null) { 1241 try { 1242 attemptConnectionToSecondaryZygote(); 1243 1244 try { 1245 secondaryZygoteState.mZygoteOutputWriter.write(command); 1246 secondaryZygoteState.mZygoteOutputWriter.flush(); 1247 1248 // Wait for the secondary Zygote to finish its work. 1249 secondaryZygoteState.mZygoteInputStream.readInt(); 1250 } catch (IOException ioe) { 1251 throw new IllegalStateException( 1252 "USAP pool state change cause an irrecoverable error", 1253 ioe); 1254 } 1255 } catch (IOException ioe) { 1256 // No secondary zygote present. This is expected on some devices. 1257 } 1258 } 1259 1260 // Wait for the response from the primary zygote here so the primary/secondary zygotes 1261 // can work concurrently. 1262 try { 1263 // Wait for the primary zygote to finish its work. 1264 primaryZygoteState.mZygoteInputStream.readInt(); 1265 } catch (IOException ioe) { 1266 throw new IllegalStateException( 1267 "USAP pool state change cause an irrecoverable error", 1268 ioe); 1269 } 1270 } 1271 } 1272 1273 /** 1274 * Starts a new zygote process as a child of this zygote. This is used to create 1275 * secondary zygotes that inherit data from the zygote that this object 1276 * communicates with. This returns a new ZygoteProcess representing a connection 1277 * to the newly created zygote. Throws an exception if the zygote cannot be started. 1278 * 1279 * @param processClass The class to use as the child zygote's main entry 1280 * point. 1281 * @param niceName A more readable name to use for the process. 1282 * @param uid The user-id under which the child zygote will run. 1283 * @param gid The group-id under which the child zygote will run. 1284 * @param gids Additional group-ids associated with the child zygote process. 1285 * @param runtimeFlags Additional flags. 1286 * @param seInfo null-ok SELinux information for the child zygote process. 1287 * @param abi non-null the ABI of the child zygote 1288 * @param acceptedAbiList ABIs this child zygote will accept connections for; this 1289 * may be different from <code>abi</code> in case the children 1290 * spawned from this Zygote only communicate using ABI-safe methods. 1291 * @param instructionSet null-ok the instruction set to use. 1292 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to 1293 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to 1294 */ startChildZygote(final String processClass, final String niceName, int uid, int gid, int[] gids, int runtimeFlags, String seInfo, String abi, String acceptedAbiList, String instructionSet, int uidRangeStart, int uidRangeEnd)1295 public ChildZygoteProcess startChildZygote(final String processClass, 1296 final String niceName, 1297 int uid, int gid, int[] gids, 1298 int runtimeFlags, 1299 String seInfo, 1300 String abi, 1301 String acceptedAbiList, 1302 String instructionSet, 1303 int uidRangeStart, 1304 int uidRangeEnd) { 1305 // Create an unguessable address in the global abstract namespace. 1306 final LocalSocketAddress serverAddress = new LocalSocketAddress( 1307 processClass + "/" + UUID.randomUUID().toString()); 1308 1309 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(), 1310 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList, 1311 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart, 1312 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd}; 1313 1314 Process.ProcessStartResult result; 1315 try { 1316 // We will bind mount app data dirs so app zygote can't access /data/data, while 1317 // we don't need to bind mount storage dirs as /storage won't be mounted. 1318 result = startViaZygote(processClass, niceName, uid, gid, 1319 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, 1320 abi, instructionSet, null /* appDataDir */, null /* invokeWith */, 1321 true /* startChildZygote */, null /* packageName */, 1322 ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */, 1323 null /* disabledCompatChanges */, null /* pkgDataInfoMap */, 1324 null /* allowlistedDataInfoList */, true /* bindMountAppsData*/, 1325 /* bindMountAppStorageDirs */ false, /*bindMountOverrideSysprops */ false, 1326 extraArgs); 1327 1328 } catch (ZygoteStartFailedEx ex) { 1329 throw new RuntimeException("Starting child-zygote through Zygote failed", ex); 1330 } 1331 1332 return new ChildZygoteProcess(serverAddress, result.pid); 1333 } 1334 } 1335