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