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