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 = 20000; 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, @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 @Nullable String[] zygoteArgs) { 359 // TODO (chriswailes): Is there a better place to check this value? 360 if (fetchUsapPoolEnabledPropWithMinInterval()) { 361 informZygotesOfUsapPoolStatus(); 362 } 363 364 try { 365 return startViaZygote(processClass, niceName, uid, gid, gids, 366 runtimeFlags, mountExternal, targetSdkVersion, seInfo, 367 abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, 368 packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, 369 pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData, 370 bindMountAppStorageDirs, zygoteArgs); 371 } catch (ZygoteStartFailedEx ex) { 372 Log.e(LOG_TAG, 373 "Starting VM process through Zygote failed"); 374 throw new RuntimeException( 375 "Starting VM process through Zygote failed", ex); 376 } 377 } 378 379 /** retry interval for opening a zygote socket */ 380 static final int ZYGOTE_RETRY_MILLIS = 500; 381 382 /** 383 * Queries the zygote for the list of ABIS it supports. 384 */ 385 @GuardedBy("mLock") getAbiList(BufferedWriter writer, DataInputStream inputStream)386 private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream) 387 throws IOException { 388 // Each query starts with the argument count (1 in this case) 389 writer.write("1"); 390 // ... followed by a new-line. 391 writer.newLine(); 392 // ... followed by our only argument. 393 writer.write("--query-abi-list"); 394 writer.newLine(); 395 writer.flush(); 396 397 // The response is a length prefixed stream of ASCII bytes. 398 int numBytes = inputStream.readInt(); 399 byte[] bytes = new byte[numBytes]; 400 inputStream.readFully(bytes); 401 402 final String rawList = new String(bytes, StandardCharsets.US_ASCII); 403 404 return Arrays.asList(rawList.split(",")); 405 } 406 407 /** 408 * Sends an argument list to the zygote process, which starts a new child 409 * and returns the child's pid. Please note: the present implementation 410 * replaces newlines in the argument list with spaces. 411 * 412 * @throws ZygoteStartFailedEx if process start failed for any reason 413 */ 414 @GuardedBy("mLock") zygoteSendArgsAndGetResult( ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)415 private Process.ProcessStartResult zygoteSendArgsAndGetResult( 416 ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args) 417 throws ZygoteStartFailedEx { 418 // Throw early if any of the arguments are malformed. This means we can 419 // avoid writing a partial response to the zygote. 420 for (String arg : args) { 421 // Making two indexOf calls here is faster than running a manually fused loop due 422 // to the fact that indexOf is an optimized intrinsic. 423 if (arg.indexOf('\n') >= 0) { 424 throw new ZygoteStartFailedEx("Embedded newlines not allowed"); 425 } else if (arg.indexOf('\r') >= 0) { 426 throw new ZygoteStartFailedEx("Embedded carriage returns not allowed"); 427 } 428 } 429 430 /* 431 * See com.android.internal.os.ZygoteArguments.parseArgs() 432 * Presently the wire format to the zygote process is: 433 * a) a count of arguments (argc, in essence) 434 * b) a number of newline-separated argument strings equal to count 435 * 436 * After the zygote process reads these it will write the pid of 437 * the child or -1 on failure, followed by boolean to 438 * indicate whether a wrapper process was used. 439 */ 440 String msgStr = args.size() + "\n" + String.join("\n", args) + "\n"; 441 442 if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) { 443 try { 444 return attemptUsapSendArgsAndGetResult(zygoteState, msgStr); 445 } catch (IOException ex) { 446 // If there was an IOException using the USAP pool we will log the error and 447 // attempt to start the process through the Zygote. 448 Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - " 449 + ex.getMessage()); 450 } 451 } 452 453 return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr); 454 } 455 attemptZygoteSendArgsAndGetResult( ZygoteState zygoteState, String msgStr)456 private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult( 457 ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx { 458 try { 459 final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter; 460 final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream; 461 462 zygoteWriter.write(msgStr); 463 zygoteWriter.flush(); 464 465 // Always read the entire result from the input stream to avoid leaving 466 // bytes in the stream for future process starts to accidentally stumble 467 // upon. 468 Process.ProcessStartResult result = new Process.ProcessStartResult(); 469 result.pid = zygoteInputStream.readInt(); 470 result.usingWrapper = zygoteInputStream.readBoolean(); 471 472 if (result.pid < 0) { 473 throw new ZygoteStartFailedEx("fork() failed"); 474 } 475 476 return result; 477 } catch (IOException ex) { 478 zygoteState.close(); 479 Log.e(LOG_TAG, "IO Exception while communicating with Zygote - " 480 + ex.toString()); 481 throw new ZygoteStartFailedEx(ex); 482 } 483 } 484 attemptUsapSendArgsAndGetResult( ZygoteState zygoteState, String msgStr)485 private Process.ProcessStartResult attemptUsapSendArgsAndGetResult( 486 ZygoteState zygoteState, String msgStr) 487 throws ZygoteStartFailedEx, IOException { 488 try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) { 489 final BufferedWriter usapWriter = 490 new BufferedWriter( 491 new OutputStreamWriter(usapSessionSocket.getOutputStream()), 492 Zygote.SOCKET_BUFFER_SIZE); 493 final DataInputStream usapReader = 494 new DataInputStream(usapSessionSocket.getInputStream()); 495 496 usapWriter.write(msgStr); 497 usapWriter.flush(); 498 499 Process.ProcessStartResult result = new Process.ProcessStartResult(); 500 result.pid = usapReader.readInt(); 501 // USAPs can't be used to spawn processes that need wrappers. 502 result.usingWrapper = false; 503 504 if (result.pid >= 0) { 505 return result; 506 } else { 507 throw new ZygoteStartFailedEx("USAP specialization failed"); 508 } 509 } 510 } 511 512 /** 513 * Test various member properties and parameters to determine if a launch event should be 514 * handled using an Unspecialized App Process Pool or not. 515 * 516 * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the 517 * Zygote command 518 * @param args Arguments that will be passed to the Zygote 519 * @return If the command should be sent to a USAP Pool member or an actual Zygote 520 */ shouldAttemptUsapLaunch(int zygotePolicyFlags, ArrayList<String> args)521 private boolean shouldAttemptUsapLaunch(int zygotePolicyFlags, ArrayList<String> args) { 522 return mUsapPoolSupported 523 && mUsapPoolEnabled 524 && policySpecifiesUsapPoolLaunch(zygotePolicyFlags) 525 && commandSupportedByUsap(args); 526 } 527 528 /** 529 * Tests a Zygote policy flag set for various properties that determine if it is eligible for 530 * being handled by an Unspecialized App Process Pool. 531 * 532 * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the 533 * Zygote command 534 * @return If the policy allows for use of a USAP pool 535 */ policySpecifiesUsapPoolLaunch(int zygotePolicyFlags)536 private static boolean policySpecifiesUsapPoolLaunch(int zygotePolicyFlags) { 537 /* 538 * Zygote USAP Pool Policy: Launch the new process from the USAP Pool iff the launch event 539 * is latency sensitive but *NOT* a system process. All system processes are equally 540 * important so we don't want to prioritize one over another. 541 */ 542 return (zygotePolicyFlags 543 & (ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS | ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE)) 544 == ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE; 545 } 546 547 /** 548 * Flags that may not be passed to a USAP. These may appear as prefixes to individual Zygote 549 * arguments. 550 */ 551 private static final String[] INVALID_USAP_FLAGS = { 552 "--query-abi-list", 553 "--get-pid", 554 "--preload-default", 555 "--preload-package", 556 "--preload-app", 557 "--start-child-zygote", 558 "--set-api-denylist-exemptions", 559 "--hidden-api-log-sampling-rate", 560 "--hidden-api-statslog-sampling-rate", 561 "--invoke-with" 562 }; 563 564 /** 565 * Tests a command list to see if it is valid to send to a USAP. 566 * 567 * @param args Zygote/USAP command arguments 568 * @return True if the command can be passed to a USAP; false otherwise 569 */ commandSupportedByUsap(ArrayList<String> args)570 private static boolean commandSupportedByUsap(ArrayList<String> args) { 571 for (String flag : args) { 572 for (String badFlag : INVALID_USAP_FLAGS) { 573 if (flag.startsWith(badFlag)) { 574 return false; 575 } 576 } 577 if (flag.startsWith("--nice-name=")) { 578 // Check if the wrap property is set, usap would ignore it. 579 if (Zygote.getWrapProperty(flag.substring(12)) != null) { 580 return false; 581 } 582 } 583 } 584 585 return true; 586 } 587 588 /** 589 * Starts a new process via the zygote mechanism. 590 * 591 * @param processClass Class name whose static main() to run 592 * @param niceName 'nice' process name to appear in ps 593 * @param uid a POSIX uid that the new process should setuid() to 594 * @param gid a POSIX gid that the new process shuold setgid() to 595 * @param gids null-ok; a list of supplementary group IDs that the 596 * new process should setgroup() to. 597 * @param runtimeFlags Additional flags for the runtime. 598 * @param targetSdkVersion The target SDK version for the app. 599 * @param seInfo null-ok SELinux information for the new process. 600 * @param abi the ABI the process should use. 601 * @param instructionSet null-ok the instruction set to use. 602 * @param appDataDir null-ok the data directory of the app. 603 * @param startChildZygote Start a sub-zygote. This creates a new zygote process 604 * that has its state cloned from this zygote process. 605 * @param packageName null-ok the name of the package this process belongs to. 606 * @param zygotePolicyFlags Flags used to determine how to launch the application. 607 * @param isTopApp Whether the process starts for high priority application. 608 * @param disabledCompatChanges a list of disabled compat changes for the process being started. 609 * @param pkgDataInfoMap Map from related package names to private data directory volume UUID 610 * and inode number. 611 * @param allowlistedDataInfoList Map from allowlisted package names to private data directory 612 * volume UUID and inode number. 613 * @param bindMountAppsData whether zygote needs to mount CE and DE data. 614 * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. 615 * @param extraArgs Additional arguments to supply to the zygote process. 616 * @return An object that describes the result of the attempt to start the process. 617 * @throws ZygoteStartFailedEx if process start failed for any reason 618 */ 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, @Nullable String[] extraArgs)619 private Process.ProcessStartResult startViaZygote(@NonNull final String processClass, 620 @Nullable final String niceName, 621 final int uid, final int gid, 622 @Nullable final int[] gids, 623 int runtimeFlags, int mountExternal, 624 int targetSdkVersion, 625 @Nullable String seInfo, 626 @NonNull String abi, 627 @Nullable String instructionSet, 628 @Nullable String appDataDir, 629 @Nullable String invokeWith, 630 boolean startChildZygote, 631 @Nullable String packageName, 632 int zygotePolicyFlags, 633 boolean isTopApp, 634 @Nullable long[] disabledCompatChanges, 635 @Nullable Map<String, Pair<String, Long>> 636 pkgDataInfoMap, 637 @Nullable Map<String, Pair<String, Long>> 638 allowlistedDataInfoList, 639 boolean bindMountAppsData, 640 boolean bindMountAppStorageDirs, 641 @Nullable String[] extraArgs) 642 throws ZygoteStartFailedEx { 643 ArrayList<String> argsForZygote = new ArrayList<>(); 644 645 // --runtime-args, --setuid=, --setgid=, 646 // and --setgroups= must go first 647 argsForZygote.add("--runtime-args"); 648 argsForZygote.add("--setuid=" + uid); 649 argsForZygote.add("--setgid=" + gid); 650 argsForZygote.add("--runtime-flags=" + runtimeFlags); 651 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) { 652 argsForZygote.add("--mount-external-default"); 653 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) { 654 argsForZygote.add("--mount-external-installer"); 655 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) { 656 argsForZygote.add("--mount-external-pass-through"); 657 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) { 658 argsForZygote.add("--mount-external-android-writable"); 659 } 660 661 argsForZygote.add("--target-sdk-version=" + targetSdkVersion); 662 663 // --setgroups is a comma-separated list 664 if (gids != null && gids.length > 0) { 665 final StringBuilder sb = new StringBuilder(); 666 sb.append("--setgroups="); 667 668 final int sz = gids.length; 669 for (int i = 0; i < sz; i++) { 670 if (i != 0) { 671 sb.append(','); 672 } 673 sb.append(gids[i]); 674 } 675 676 argsForZygote.add(sb.toString()); 677 } 678 679 if (niceName != null) { 680 argsForZygote.add("--nice-name=" + niceName); 681 } 682 683 if (seInfo != null) { 684 argsForZygote.add("--seinfo=" + seInfo); 685 } 686 687 if (instructionSet != null) { 688 argsForZygote.add("--instruction-set=" + instructionSet); 689 } 690 691 if (appDataDir != null) { 692 argsForZygote.add("--app-data-dir=" + appDataDir); 693 } 694 695 if (invokeWith != null) { 696 argsForZygote.add("--invoke-with"); 697 argsForZygote.add(invokeWith); 698 } 699 700 if (startChildZygote) { 701 argsForZygote.add("--start-child-zygote"); 702 } 703 704 if (packageName != null) { 705 argsForZygote.add("--package-name=" + packageName); 706 } 707 708 if (isTopApp) { 709 argsForZygote.add(Zygote.START_AS_TOP_APP_ARG); 710 } 711 if (pkgDataInfoMap != null && pkgDataInfoMap.size() > 0) { 712 StringBuilder sb = new StringBuilder(); 713 sb.append(Zygote.PKG_DATA_INFO_MAP); 714 sb.append("="); 715 boolean started = false; 716 for (Map.Entry<String, Pair<String, Long>> entry : pkgDataInfoMap.entrySet()) { 717 if (started) { 718 sb.append(','); 719 } 720 started = true; 721 sb.append(entry.getKey()); 722 sb.append(','); 723 sb.append(entry.getValue().first); 724 sb.append(','); 725 sb.append(entry.getValue().second); 726 } 727 argsForZygote.add(sb.toString()); 728 } 729 if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) { 730 StringBuilder sb = new StringBuilder(); 731 sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP); 732 sb.append("="); 733 boolean started = false; 734 for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) { 735 if (started) { 736 sb.append(','); 737 } 738 started = true; 739 sb.append(entry.getKey()); 740 sb.append(','); 741 sb.append(entry.getValue().first); 742 sb.append(','); 743 sb.append(entry.getValue().second); 744 } 745 argsForZygote.add(sb.toString()); 746 } 747 748 if (bindMountAppStorageDirs) { 749 argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS); 750 } 751 752 if (bindMountAppsData) { 753 argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS); 754 } 755 756 if (disabledCompatChanges != null && disabledCompatChanges.length > 0) { 757 StringBuilder sb = new StringBuilder(); 758 sb.append("--disabled-compat-changes="); 759 760 int sz = disabledCompatChanges.length; 761 for (int i = 0; i < sz; i++) { 762 if (i != 0) { 763 sb.append(','); 764 } 765 sb.append(disabledCompatChanges[i]); 766 } 767 768 argsForZygote.add(sb.toString()); 769 } 770 771 argsForZygote.add(processClass); 772 773 if (extraArgs != null) { 774 Collections.addAll(argsForZygote, extraArgs); 775 } 776 777 synchronized(mLock) { 778 // The USAP pool can not be used if the application will not use the systems graphics 779 // driver. If that driver is requested use the Zygote application start path. 780 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), 781 zygotePolicyFlags, 782 argsForZygote); 783 } 784 } 785 fetchUsapPoolEnabledProp()786 private boolean fetchUsapPoolEnabledProp() { 787 boolean origVal = mUsapPoolEnabled; 788 789 mUsapPoolEnabled = ZygoteConfig.getBool( 790 ZygoteConfig.USAP_POOL_ENABLED, ZygoteConfig.USAP_POOL_ENABLED_DEFAULT); 791 792 boolean valueChanged = origVal != mUsapPoolEnabled; 793 794 if (valueChanged) { 795 Log.i(LOG_TAG, "usapPoolEnabled = " + mUsapPoolEnabled); 796 } 797 798 return valueChanged; 799 } 800 801 private boolean mIsFirstPropCheck = true; 802 private long mLastPropCheckTimestamp = 0; 803 fetchUsapPoolEnabledPropWithMinInterval()804 private boolean fetchUsapPoolEnabledPropWithMinInterval() { 805 // If this Zygote doesn't support USAPs there is no need to fetch any 806 // properties. 807 if (!mUsapPoolSupported) return false; 808 809 final long currentTimestamp = SystemClock.elapsedRealtime(); 810 811 if (mIsFirstPropCheck 812 || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) { 813 mIsFirstPropCheck = false; 814 mLastPropCheckTimestamp = currentTimestamp; 815 return fetchUsapPoolEnabledProp(); 816 } 817 818 return false; 819 } 820 821 /** 822 * Closes the connections to the zygote, if they exist. 823 */ close()824 public void close() { 825 if (primaryZygoteState != null) { 826 primaryZygoteState.close(); 827 } 828 if (secondaryZygoteState != null) { 829 secondaryZygoteState.close(); 830 } 831 } 832 833 /** 834 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block 835 * and retry if the zygote is unresponsive. This method is a no-op if a connection is 836 * already open. 837 */ establishZygoteConnectionForAbi(String abi)838 public void establishZygoteConnectionForAbi(String abi) { 839 try { 840 synchronized(mLock) { 841 openZygoteSocketIfNeeded(abi); 842 } 843 } catch (ZygoteStartFailedEx ex) { 844 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex); 845 } 846 } 847 848 /** 849 * Attempt to retrieve the PID of the zygote serving the given abi. 850 */ getZygotePid(String abi)851 public int getZygotePid(String abi) { 852 try { 853 synchronized (mLock) { 854 ZygoteState state = openZygoteSocketIfNeeded(abi); 855 856 // Each query starts with the argument count (1 in this case) 857 state.mZygoteOutputWriter.write("1"); 858 // ... followed by a new-line. 859 state.mZygoteOutputWriter.newLine(); 860 // ... followed by our only argument. 861 state.mZygoteOutputWriter.write("--get-pid"); 862 state.mZygoteOutputWriter.newLine(); 863 state.mZygoteOutputWriter.flush(); 864 865 // The response is a length prefixed stream of ASCII bytes. 866 int numBytes = state.mZygoteInputStream.readInt(); 867 byte[] bytes = new byte[numBytes]; 868 state.mZygoteInputStream.readFully(bytes); 869 870 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII)); 871 } 872 } catch (Exception ex) { 873 throw new RuntimeException("Failure retrieving pid", ex); 874 } 875 } 876 877 /** 878 * Notify the Zygote processes that boot completed. 879 */ bootCompleted()880 public void bootCompleted() { 881 // Notify both the 32-bit and 64-bit zygote. 882 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 883 bootCompleted(Build.SUPPORTED_32_BIT_ABIS[0]); 884 } 885 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { 886 bootCompleted(Build.SUPPORTED_64_BIT_ABIS[0]); 887 } 888 } 889 bootCompleted(String abi)890 private void bootCompleted(String abi) { 891 try { 892 synchronized (mLock) { 893 ZygoteState state = openZygoteSocketIfNeeded(abi); 894 state.mZygoteOutputWriter.write("1\n--boot-completed\n"); 895 state.mZygoteOutputWriter.flush(); 896 state.mZygoteInputStream.readInt(); 897 } 898 } catch (Exception ex) { 899 throw new RuntimeException("Failed to inform zygote of boot_completed", ex); 900 } 901 } 902 903 /** 904 * Push hidden API deny-listing exemptions into the zygote process(es). 905 * 906 * <p>The list of exemptions will take affect for all new processes forked from the zygote after 907 * this call. 908 * 909 * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as 910 * allowed/public APIs (i.e. allowed, no logging of usage). 911 */ setApiDenylistExemptions(List<String> exemptions)912 public boolean setApiDenylistExemptions(List<String> exemptions) { 913 synchronized (mLock) { 914 mApiDenylistExemptions = exemptions; 915 boolean ok = maybeSetApiDenylistExemptions(primaryZygoteState, true); 916 if (ok) { 917 ok = maybeSetApiDenylistExemptions(secondaryZygoteState, true); 918 } 919 return ok; 920 } 921 } 922 923 /** 924 * Set the precentage of detected hidden API accesses that are logged to the event log. 925 * 926 * <p>This rate will take affect for all new processes forked from the zygote after this call. 927 * 928 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging. 929 */ setHiddenApiAccessLogSampleRate(int rate)930 public void setHiddenApiAccessLogSampleRate(int rate) { 931 synchronized (mLock) { 932 mHiddenApiAccessLogSampleRate = rate; 933 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState); 934 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState); 935 } 936 } 937 938 /** 939 * Set the precentage of detected hidden API accesses that are logged to the new event log. 940 * 941 * <p>This rate will take affect for all new processes forked from the zygote after this call. 942 * 943 * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging. 944 */ setHiddenApiAccessStatslogSampleRate(int rate)945 public void setHiddenApiAccessStatslogSampleRate(int rate) { 946 synchronized (mLock) { 947 mHiddenApiAccessStatslogSampleRate = rate; 948 maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState); 949 maybeSetHiddenApiAccessStatslogSampleRate(secondaryZygoteState); 950 } 951 } 952 953 @GuardedBy("mLock") maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty)954 private boolean maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty) { 955 if (state == null || state.isClosed()) { 956 Slog.e(LOG_TAG, "Can't set API denylist exemptions: no zygote connection"); 957 return false; 958 } else if (!sendIfEmpty && mApiDenylistExemptions.isEmpty()) { 959 return true; 960 } 961 962 try { 963 state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1)); 964 state.mZygoteOutputWriter.newLine(); 965 state.mZygoteOutputWriter.write("--set-api-denylist-exemptions"); 966 state.mZygoteOutputWriter.newLine(); 967 for (int i = 0; i < mApiDenylistExemptions.size(); ++i) { 968 state.mZygoteOutputWriter.write(mApiDenylistExemptions.get(i)); 969 state.mZygoteOutputWriter.newLine(); 970 } 971 state.mZygoteOutputWriter.flush(); 972 int status = state.mZygoteInputStream.readInt(); 973 if (status != 0) { 974 Slog.e(LOG_TAG, "Failed to set API denylist exemptions; status " + status); 975 } 976 return true; 977 } catch (IOException ioe) { 978 Slog.e(LOG_TAG, "Failed to set API denylist exemptions", ioe); 979 mApiDenylistExemptions = Collections.emptyList(); 980 return false; 981 } 982 } 983 maybeSetHiddenApiAccessLogSampleRate(ZygoteState state)984 private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) { 985 if (state == null || state.isClosed() || mHiddenApiAccessLogSampleRate == -1) { 986 return; 987 } 988 989 try { 990 state.mZygoteOutputWriter.write(Integer.toString(1)); 991 state.mZygoteOutputWriter.newLine(); 992 state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate=" 993 + mHiddenApiAccessLogSampleRate); 994 state.mZygoteOutputWriter.newLine(); 995 state.mZygoteOutputWriter.flush(); 996 int status = state.mZygoteInputStream.readInt(); 997 if (status != 0) { 998 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status); 999 } 1000 } catch (IOException ioe) { 1001 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe); 1002 } 1003 } 1004 maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state)1005 private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) { 1006 if (state == null || state.isClosed() || mHiddenApiAccessStatslogSampleRate == -1) { 1007 return; 1008 } 1009 1010 try { 1011 state.mZygoteOutputWriter.write(Integer.toString(1)); 1012 state.mZygoteOutputWriter.newLine(); 1013 state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate=" 1014 + mHiddenApiAccessStatslogSampleRate); 1015 state.mZygoteOutputWriter.newLine(); 1016 state.mZygoteOutputWriter.flush(); 1017 int status = state.mZygoteInputStream.readInt(); 1018 if (status != 0) { 1019 Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate; status " 1020 + status); 1021 } 1022 } catch (IOException ioe) { 1023 Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate", ioe); 1024 } 1025 } 1026 1027 /** 1028 * Creates a ZygoteState for the primary zygote if it doesn't exist or has been disconnected. 1029 */ 1030 @GuardedBy("mLock") attemptConnectionToPrimaryZygote()1031 private void attemptConnectionToPrimaryZygote() throws IOException { 1032 if (primaryZygoteState == null || primaryZygoteState.isClosed()) { 1033 primaryZygoteState = 1034 ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress); 1035 1036 maybeSetApiDenylistExemptions(primaryZygoteState, false); 1037 maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState); 1038 } 1039 } 1040 1041 /** 1042 * Creates a ZygoteState for the secondary zygote if it doesn't exist or has been disconnected. 1043 */ 1044 @GuardedBy("mLock") attemptConnectionToSecondaryZygote()1045 private void attemptConnectionToSecondaryZygote() throws IOException { 1046 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { 1047 secondaryZygoteState = 1048 ZygoteState.connect(mZygoteSecondarySocketAddress, 1049 mUsapPoolSecondarySocketAddress); 1050 1051 maybeSetApiDenylistExemptions(secondaryZygoteState, false); 1052 maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState); 1053 } 1054 } 1055 1056 /** 1057 * Tries to open a session socket to a Zygote process with a compatible ABI if one is not 1058 * already open. If a compatible session socket is already open that session socket is returned. 1059 * This function may block and may have to try connecting to multiple Zygotes to find the 1060 * appropriate one. Requires that mLock be held. 1061 */ 1062 @GuardedBy("mLock") openZygoteSocketIfNeeded(String abi)1063 private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { 1064 try { 1065 attemptConnectionToPrimaryZygote(); 1066 1067 if (primaryZygoteState.matches(abi)) { 1068 return primaryZygoteState; 1069 } 1070 1071 if (mZygoteSecondarySocketAddress != null) { 1072 // The primary zygote didn't match. Try the secondary. 1073 attemptConnectionToSecondaryZygote(); 1074 1075 if (secondaryZygoteState.matches(abi)) { 1076 return secondaryZygoteState; 1077 } 1078 } 1079 } catch (IOException ioe) { 1080 throw new ZygoteStartFailedEx("Error connecting to zygote", ioe); 1081 } 1082 1083 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); 1084 } 1085 1086 /** 1087 * Instructs the zygote to pre-load the application code for the given Application. 1088 * Only the app zygote supports this function. 1089 * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead. 1090 */ preloadApp(ApplicationInfo appInfo, String abi)1091 public boolean preloadApp(ApplicationInfo appInfo, String abi) 1092 throws ZygoteStartFailedEx, IOException { 1093 synchronized (mLock) { 1094 ZygoteState state = openZygoteSocketIfNeeded(abi); 1095 state.mZygoteOutputWriter.write("2"); 1096 state.mZygoteOutputWriter.newLine(); 1097 1098 state.mZygoteOutputWriter.write("--preload-app"); 1099 state.mZygoteOutputWriter.newLine(); 1100 1101 // Zygote args needs to be strings, so in order to pass ApplicationInfo, 1102 // write it to a Parcel, and base64 the raw Parcel bytes to the other side. 1103 Parcel parcel = Parcel.obtain(); 1104 appInfo.writeToParcel(parcel, 0 /* flags */); 1105 String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall()); 1106 parcel.recycle(); 1107 state.mZygoteOutputWriter.write(encodedParcelData); 1108 state.mZygoteOutputWriter.newLine(); 1109 1110 state.mZygoteOutputWriter.flush(); 1111 1112 return (state.mZygoteInputStream.readInt() == 0); 1113 } 1114 } 1115 1116 /** 1117 * Instructs the zygote to pre-load the classes and native libraries at the given paths 1118 * for the specified abi. Not all zygotes support this function. 1119 */ preloadPackageForAbi( String packagePath, String libsPath, String libFileName, String cacheKey, String abi)1120 public boolean preloadPackageForAbi( 1121 String packagePath, String libsPath, String libFileName, String cacheKey, String abi) 1122 throws ZygoteStartFailedEx, IOException { 1123 synchronized (mLock) { 1124 ZygoteState state = openZygoteSocketIfNeeded(abi); 1125 state.mZygoteOutputWriter.write("5"); 1126 state.mZygoteOutputWriter.newLine(); 1127 1128 state.mZygoteOutputWriter.write("--preload-package"); 1129 state.mZygoteOutputWriter.newLine(); 1130 1131 state.mZygoteOutputWriter.write(packagePath); 1132 state.mZygoteOutputWriter.newLine(); 1133 1134 state.mZygoteOutputWriter.write(libsPath); 1135 state.mZygoteOutputWriter.newLine(); 1136 1137 state.mZygoteOutputWriter.write(libFileName); 1138 state.mZygoteOutputWriter.newLine(); 1139 1140 state.mZygoteOutputWriter.write(cacheKey); 1141 state.mZygoteOutputWriter.newLine(); 1142 1143 state.mZygoteOutputWriter.flush(); 1144 1145 return (state.mZygoteInputStream.readInt() == 0); 1146 } 1147 } 1148 1149 /** 1150 * Instructs the zygote to preload the default set of classes and resources. Returns 1151 * {@code true} if a preload was performed as a result of this call, and {@code false} 1152 * otherwise. The latter usually means that the zygote eagerly preloaded at startup 1153 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous. 1154 */ preloadDefault(String abi)1155 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException { 1156 synchronized (mLock) { 1157 ZygoteState state = openZygoteSocketIfNeeded(abi); 1158 // Each query starts with the argument count (1 in this case) 1159 state.mZygoteOutputWriter.write("1"); 1160 state.mZygoteOutputWriter.newLine(); 1161 state.mZygoteOutputWriter.write("--preload-default"); 1162 state.mZygoteOutputWriter.newLine(); 1163 state.mZygoteOutputWriter.flush(); 1164 1165 return (state.mZygoteInputStream.readInt() == 0); 1166 } 1167 } 1168 1169 /** 1170 * Try connecting to the Zygote over and over again until we hit a time-out. 1171 * @param zygoteSocketName The name of the socket to connect to. 1172 */ waitForConnectionToZygote(String zygoteSocketName)1173 public static void waitForConnectionToZygote(String zygoteSocketName) { 1174 final LocalSocketAddress zygoteSocketAddress = 1175 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED); 1176 waitForConnectionToZygote(zygoteSocketAddress); 1177 } 1178 1179 /** 1180 * Try connecting to the Zygote over and over again until we hit a time-out. 1181 * @param zygoteSocketAddress The name of the socket to connect to. 1182 */ waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress)1183 public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) { 1184 int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS; 1185 for (int n = numRetries; n >= 0; n--) { 1186 try { 1187 final ZygoteState zs = 1188 ZygoteState.connect(zygoteSocketAddress, null); 1189 zs.close(); 1190 return; 1191 } catch (IOException ioe) { 1192 Log.w(LOG_TAG, 1193 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage()); 1194 } 1195 1196 try { 1197 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS); 1198 } catch (InterruptedException ignored) { } 1199 } 1200 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " 1201 + zygoteSocketAddress.getName()); 1202 } 1203 1204 /** 1205 * Sends messages to the zygotes telling them to change the status of their USAP pools. If 1206 * this notification fails the ZygoteProcess will fall back to the previous behavior. 1207 */ informZygotesOfUsapPoolStatus()1208 private void informZygotesOfUsapPoolStatus() { 1209 final String command = "1\n--usap-pool-enabled=" + mUsapPoolEnabled + "\n"; 1210 1211 synchronized (mLock) { 1212 try { 1213 attemptConnectionToPrimaryZygote(); 1214 1215 primaryZygoteState.mZygoteOutputWriter.write(command); 1216 primaryZygoteState.mZygoteOutputWriter.flush(); 1217 } catch (IOException ioe) { 1218 mUsapPoolEnabled = !mUsapPoolEnabled; 1219 Log.w(LOG_TAG, "Failed to inform zygotes of USAP pool status: " 1220 + ioe.getMessage()); 1221 return; 1222 } 1223 1224 if (mZygoteSecondarySocketAddress != null) { 1225 try { 1226 attemptConnectionToSecondaryZygote(); 1227 1228 try { 1229 secondaryZygoteState.mZygoteOutputWriter.write(command); 1230 secondaryZygoteState.mZygoteOutputWriter.flush(); 1231 1232 // Wait for the secondary Zygote to finish its work. 1233 secondaryZygoteState.mZygoteInputStream.readInt(); 1234 } catch (IOException ioe) { 1235 throw new IllegalStateException( 1236 "USAP pool state change cause an irrecoverable error", 1237 ioe); 1238 } 1239 } catch (IOException ioe) { 1240 // No secondary zygote present. This is expected on some devices. 1241 } 1242 } 1243 1244 // Wait for the response from the primary zygote here so the primary/secondary zygotes 1245 // can work concurrently. 1246 try { 1247 // Wait for the primary zygote to finish its work. 1248 primaryZygoteState.mZygoteInputStream.readInt(); 1249 } catch (IOException ioe) { 1250 throw new IllegalStateException( 1251 "USAP pool state change cause an irrecoverable error", 1252 ioe); 1253 } 1254 } 1255 } 1256 1257 /** 1258 * Starts a new zygote process as a child of this zygote. This is used to create 1259 * secondary zygotes that inherit data from the zygote that this object 1260 * communicates with. This returns a new ZygoteProcess representing a connection 1261 * to the newly created zygote. Throws an exception if the zygote cannot be started. 1262 * 1263 * @param processClass The class to use as the child zygote's main entry 1264 * point. 1265 * @param niceName A more readable name to use for the process. 1266 * @param uid The user-id under which the child zygote will run. 1267 * @param gid The group-id under which the child zygote will run. 1268 * @param gids Additional group-ids associated with the child zygote process. 1269 * @param runtimeFlags Additional flags. 1270 * @param seInfo null-ok SELinux information for the child zygote process. 1271 * @param abi non-null the ABI of the child zygote 1272 * @param acceptedAbiList ABIs this child zygote will accept connections for; this 1273 * may be different from <code>abi</code> in case the children 1274 * spawned from this Zygote only communicate using ABI-safe methods. 1275 * @param instructionSet null-ok the instruction set to use. 1276 * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to 1277 * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to 1278 */ 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)1279 public ChildZygoteProcess startChildZygote(final String processClass, 1280 final String niceName, 1281 int uid, int gid, int[] gids, 1282 int runtimeFlags, 1283 String seInfo, 1284 String abi, 1285 String acceptedAbiList, 1286 String instructionSet, 1287 int uidRangeStart, 1288 int uidRangeEnd) { 1289 // Create an unguessable address in the global abstract namespace. 1290 final LocalSocketAddress serverAddress = new LocalSocketAddress( 1291 processClass + "/" + UUID.randomUUID().toString()); 1292 1293 final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(), 1294 Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList, 1295 Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart, 1296 Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd}; 1297 1298 Process.ProcessStartResult result; 1299 try { 1300 // We will bind mount app data dirs so app zygote can't access /data/data, while 1301 // we don't need to bind mount storage dirs as /storage won't be mounted. 1302 result = startViaZygote(processClass, niceName, uid, gid, 1303 gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, 1304 abi, instructionSet, null /* appDataDir */, null /* invokeWith */, 1305 true /* startChildZygote */, null /* packageName */, 1306 ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */, 1307 null /* disabledCompatChanges */, null /* pkgDataInfoMap */, 1308 null /* allowlistedDataInfoList */, true /* bindMountAppsData*/, 1309 /* bindMountAppStorageDirs */ false, extraArgs); 1310 1311 } catch (ZygoteStartFailedEx ex) { 1312 throw new RuntimeException("Starting child-zygote through Zygote failed", ex); 1313 } 1314 1315 return new ChildZygoteProcess(serverAddress, result.pid); 1316 } 1317 } 1318