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