1 /* 2 * Copyright (C) 2007 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 com.android.internal.os; 18 19 import static android.system.OsConstants.POLLIN; 20 21 import android.net.LocalServerSocket; 22 import android.net.LocalSocket; 23 import android.os.SystemClock; 24 import android.os.Trace; 25 import android.system.ErrnoException; 26 import android.system.Os; 27 import android.system.StructPollfd; 28 import android.util.Log; 29 import android.util.Slog; 30 31 import dalvik.system.ZygoteHooks; 32 33 import java.io.ByteArrayInputStream; 34 import java.io.DataInputStream; 35 import java.io.FileDescriptor; 36 import java.io.IOException; 37 import java.util.ArrayList; 38 39 /** 40 * Server socket class for zygote processes. 41 * 42 * Provides functions to wait for commands on a UNIX domain socket, and fork 43 * off child processes that inherit the initial state of the VM.% 44 * 45 * Please see {@link ZygoteArguments} for documentation on the 46 * client protocol. 47 */ 48 class ZygoteServer { 49 // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate 50 public static final String TAG = "ZygoteServer"; 51 52 /** 53 * The maximim value that will be accepted from the USAP_POOL_SIZE_MAX device property. 54 * is a mirror of USAP_POOL_MAX_LIMIT found in com_android_internal_os_Zygote.cpp. 55 */ 56 private static final int USAP_POOL_SIZE_MAX_LIMIT = 100; 57 58 /** 59 * The minimum value that will be accepted from the USAP_POOL_SIZE_MIN device property. 60 */ 61 private static final int USAP_POOL_SIZE_MIN_LIMIT = 1; 62 63 /** The default value used for the USAP_POOL_SIZE_MAX device property */ 64 private static final String USAP_POOL_SIZE_MAX_DEFAULT = "10"; 65 66 /** The default value used for the USAP_POOL_SIZE_MIN device property */ 67 private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1"; 68 69 /** The default value used for the USAP_REFILL_DELAY_MS device property */ 70 private static final String USAP_POOL_REFILL_DELAY_MS_DEFAULT = "3000"; 71 72 /** The "not a timestamp" value for the refill delay timestamp mechanism. */ 73 private static final int INVALID_TIMESTAMP = -1; 74 75 /** 76 * Indicates if this Zygote server can support a unspecialized app process pool. Currently this 77 * should only be true for the primary and secondary Zygotes, and not the App Zygotes or the 78 * WebView Zygote. 79 * 80 * TODO (chriswailes): Make this an explicit argument to the constructor 81 */ 82 83 private final boolean mUsapPoolSupported; 84 85 /** 86 * If the unspecialized app process pool should be created and used to start applications. 87 * 88 * Setting this value to false will disable the creation, maintenance, and use of the USAP 89 * pool. When the USAP pool is disabled the application lifecycle will be identical to 90 * previous versions of Android. 91 */ 92 private boolean mUsapPoolEnabled = false; 93 94 /** 95 * Listening socket that accepts new server connections. 96 */ 97 private LocalServerSocket mZygoteSocket; 98 99 /** 100 * The name of the unspecialized app process pool socket to use if the USAP pool is enabled. 101 */ 102 private final LocalServerSocket mUsapPoolSocket; 103 104 /** 105 * File descriptor used for communication between the signal handler and the ZygoteServer poll 106 * loop. 107 * */ 108 private final FileDescriptor mUsapPoolEventFD; 109 110 /** 111 * Whether or not mZygoteSocket's underlying FD should be closed directly. 112 * If mZygoteSocket is created with an existing FD, closing the socket does 113 * not close the FD and it must be closed explicitly. If the socket is created 114 * with a name instead, then closing the socket will close the underlying FD 115 * and it should not be double-closed. 116 */ 117 private boolean mCloseSocketFd; 118 119 /** 120 * Set by the child process, immediately after a call to {@code Zygote.forkAndSpecialize}. 121 */ 122 private boolean mIsForkChild; 123 124 /** 125 * The runtime-adjustable maximum USAP pool size. 126 */ 127 private int mUsapPoolSizeMax = 0; 128 129 /** 130 * The runtime-adjustable minimum USAP pool size. 131 */ 132 private int mUsapPoolSizeMin = 0; 133 134 /** 135 * The runtime-adjustable value used to determine when to re-fill the USAP pool. The pool will 136 * be re-filled when (mUsapPoolMax - gUsapPoolCount) >= sUsapPoolRefillThreshold. 137 */ 138 private int mUsapPoolRefillThreshold = 0; 139 140 /** 141 * Number of milliseconds to delay before refilling the pool if it hasn't reached its 142 * minimum value. 143 */ 144 private int mUsapPoolRefillDelayMs = -1; 145 146 /** 147 * If and when we should refill the USAP pool. 148 */ 149 private UsapPoolRefillAction mUsapPoolRefillAction; 150 private long mUsapPoolRefillTriggerTimestamp; 151 152 private enum UsapPoolRefillAction { 153 DELAYED, 154 IMMEDIATE, 155 NONE 156 } 157 ZygoteServer()158 ZygoteServer() { 159 mUsapPoolEventFD = null; 160 mZygoteSocket = null; 161 mUsapPoolSocket = null; 162 163 mUsapPoolSupported = false; 164 } 165 166 /** 167 * Initialize the Zygote server with the Zygote server socket, USAP pool server socket, and USAP 168 * pool event FD. 169 * 170 * @param isPrimaryZygote If this is the primary Zygote or not. 171 */ ZygoteServer(boolean isPrimaryZygote)172 ZygoteServer(boolean isPrimaryZygote) { 173 mUsapPoolEventFD = Zygote.getUsapPoolEventFD(); 174 175 if (isPrimaryZygote) { 176 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME); 177 mUsapPoolSocket = 178 Zygote.createManagedSocketFromInitSocket( 179 Zygote.USAP_POOL_PRIMARY_SOCKET_NAME); 180 } else { 181 mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME); 182 mUsapPoolSocket = 183 Zygote.createManagedSocketFromInitSocket( 184 Zygote.USAP_POOL_SECONDARY_SOCKET_NAME); 185 } 186 187 mUsapPoolSupported = true; 188 fetchUsapPoolPolicyProps(); 189 } 190 setForkChild()191 void setForkChild() { 192 mIsForkChild = true; 193 } 194 isUsapPoolEnabled()195 public boolean isUsapPoolEnabled() { 196 return mUsapPoolEnabled; 197 } 198 199 /** 200 * Registers a server socket for zygote command connections. This opens the server socket 201 * at the specified name in the abstract socket namespace. 202 */ registerServerSocketAtAbstractName(String socketName)203 void registerServerSocketAtAbstractName(String socketName) { 204 if (mZygoteSocket == null) { 205 try { 206 mZygoteSocket = new LocalServerSocket(socketName); 207 mCloseSocketFd = false; 208 } catch (IOException ex) { 209 throw new RuntimeException( 210 "Error binding to abstract socket '" + socketName + "'", ex); 211 } 212 } 213 } 214 215 /** 216 * Waits for and accepts a single command connection. Throws 217 * RuntimeException on failure. 218 */ acceptCommandPeer(String abiList)219 private ZygoteConnection acceptCommandPeer(String abiList) { 220 try { 221 return createNewConnection(mZygoteSocket.accept(), abiList); 222 } catch (IOException ex) { 223 throw new RuntimeException( 224 "IOException during accept()", ex); 225 } 226 } 227 createNewConnection(LocalSocket socket, String abiList)228 protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList) 229 throws IOException { 230 return new ZygoteConnection(socket, abiList); 231 } 232 233 /** 234 * Close and clean up zygote sockets. Called on shutdown and on the 235 * child's exit path. 236 */ closeServerSocket()237 void closeServerSocket() { 238 try { 239 if (mZygoteSocket != null) { 240 FileDescriptor fd = mZygoteSocket.getFileDescriptor(); 241 mZygoteSocket.close(); 242 if (fd != null && mCloseSocketFd) { 243 Os.close(fd); 244 } 245 } 246 } catch (IOException ex) { 247 Log.e(TAG, "Zygote: error closing sockets", ex); 248 } catch (ErrnoException ex) { 249 Log.e(TAG, "Zygote: error closing descriptor", ex); 250 } 251 252 mZygoteSocket = null; 253 } 254 255 /** 256 * Return the server socket's underlying file descriptor, so that 257 * ZygoteConnection can pass it to the native code for proper 258 * closure after a child process is forked off. 259 */ 260 getZygoteSocketFileDescriptor()261 FileDescriptor getZygoteSocketFileDescriptor() { 262 return mZygoteSocket.getFileDescriptor(); 263 } 264 fetchUsapPoolPolicyProps()265 private void fetchUsapPoolPolicyProps() { 266 if (mUsapPoolSupported) { 267 final String usapPoolSizeMaxPropString = Zygote.getConfigurationProperty( 268 ZygoteConfig.USAP_POOL_SIZE_MAX, USAP_POOL_SIZE_MAX_DEFAULT); 269 270 if (!usapPoolSizeMaxPropString.isEmpty()) { 271 mUsapPoolSizeMax = Integer.min(Integer.parseInt( 272 usapPoolSizeMaxPropString), USAP_POOL_SIZE_MAX_LIMIT); 273 } 274 275 final String usapPoolSizeMinPropString = Zygote.getConfigurationProperty( 276 ZygoteConfig.USAP_POOL_SIZE_MIN, USAP_POOL_SIZE_MIN_DEFAULT); 277 278 if (!usapPoolSizeMinPropString.isEmpty()) { 279 mUsapPoolSizeMin = Integer.max( 280 Integer.parseInt(usapPoolSizeMinPropString), USAP_POOL_SIZE_MIN_LIMIT); 281 } 282 283 final String usapPoolRefillThresholdPropString = Zygote.getConfigurationProperty( 284 ZygoteConfig.USAP_POOL_REFILL_THRESHOLD, 285 Integer.toString(mUsapPoolSizeMax / 2)); 286 287 if (!usapPoolRefillThresholdPropString.isEmpty()) { 288 mUsapPoolRefillThreshold = Integer.min( 289 Integer.parseInt(usapPoolRefillThresholdPropString), 290 mUsapPoolSizeMax); 291 } 292 293 final String usapPoolRefillDelayMsPropString = Zygote.getConfigurationProperty( 294 ZygoteConfig.USAP_POOL_REFILL_DELAY_MS, USAP_POOL_REFILL_DELAY_MS_DEFAULT); 295 296 if (!usapPoolRefillDelayMsPropString.isEmpty()) { 297 mUsapPoolRefillDelayMs = Integer.parseInt(usapPoolRefillDelayMsPropString); 298 } 299 300 // Validity check 301 if (mUsapPoolSizeMin >= mUsapPoolSizeMax) { 302 Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size." 303 + " Restoring default values."); 304 305 mUsapPoolSizeMax = Integer.parseInt(USAP_POOL_SIZE_MAX_DEFAULT); 306 mUsapPoolSizeMin = Integer.parseInt(USAP_POOL_SIZE_MIN_DEFAULT); 307 mUsapPoolRefillThreshold = mUsapPoolSizeMax / 2; 308 } 309 } 310 } 311 312 private boolean mIsFirstPropertyCheck = true; 313 private long mLastPropCheckTimestamp = 0; 314 fetchUsapPoolPolicyPropsWithMinInterval()315 private void fetchUsapPoolPolicyPropsWithMinInterval() { 316 final long currentTimestamp = SystemClock.elapsedRealtime(); 317 318 if (mIsFirstPropertyCheck 319 || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) { 320 mIsFirstPropertyCheck = false; 321 mLastPropCheckTimestamp = currentTimestamp; 322 fetchUsapPoolPolicyProps(); 323 } 324 } 325 fetchUsapPoolPolicyPropsIfUnfetched()326 private void fetchUsapPoolPolicyPropsIfUnfetched() { 327 if (mIsFirstPropertyCheck) { 328 mIsFirstPropertyCheck = false; 329 fetchUsapPoolPolicyProps(); 330 } 331 } 332 333 /** 334 * Refill the USAP Pool to the appropriate level, determined by whether this is a priority 335 * refill event or not. 336 * 337 * @param sessionSocketRawFDs Anonymous session sockets that are currently open 338 * @return In the Zygote process this function will always return null; in unspecialized app 339 * processes this function will return a Runnable object representing the new 340 * application that is passed up from childMain (the usap's main wait loop). 341 */ 342 fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill)343 Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) { 344 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool"); 345 346 // Ensure that the pool properties have been fetched. 347 fetchUsapPoolPolicyPropsIfUnfetched(); 348 349 int usapPoolCount = Zygote.getUsapPoolCount(); 350 int numUsapsToSpawn; 351 352 if (isPriorityRefill) { 353 // Refill to min 354 numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount; 355 356 Log.i("zygote", 357 "Priority USAP Pool refill. New USAPs: " + numUsapsToSpawn); 358 } else { 359 // Refill up to max 360 numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; 361 362 Log.i("zygote", 363 "Delayed USAP Pool refill. New USAPs: " + numUsapsToSpawn); 364 } 365 366 // Disable some VM functionality and reset some system values 367 // before forking. 368 ZygoteHooks.preFork(); 369 370 while (--numUsapsToSpawn >= 0) { 371 Runnable caller = 372 Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs, isPriorityRefill); 373 374 if (caller != null) { 375 return caller; 376 } 377 } 378 379 // Re-enable runtime services for the Zygote. Services for unspecialized app process 380 // are re-enabled in specializeAppProcess. 381 ZygoteHooks.postForkCommon(); 382 383 resetUsapRefillState(); 384 385 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 386 387 return null; 388 } 389 390 /** 391 * Empty or fill the USAP pool as dictated by the current and new USAP pool statuses. 392 */ setUsapPoolStatus(boolean newStatus, LocalSocket sessionSocket)393 Runnable setUsapPoolStatus(boolean newStatus, LocalSocket sessionSocket) { 394 if (!mUsapPoolSupported) { 395 Log.w(TAG, 396 "Attempting to enable a USAP pool for a Zygote that doesn't support it."); 397 return null; 398 } else if (mUsapPoolEnabled == newStatus) { 399 return null; 400 } 401 402 Log.i(TAG, "USAP Pool status change: " + (newStatus ? "ENABLED" : "DISABLED")); 403 404 mUsapPoolEnabled = newStatus; 405 406 if (newStatus) { 407 return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false); 408 } else { 409 Zygote.emptyUsapPool(); 410 return null; 411 } 412 } 413 resetUsapRefillState()414 private void resetUsapRefillState() { 415 mUsapPoolRefillAction = UsapPoolRefillAction.NONE; 416 mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; 417 } 418 419 /** 420 * Runs the zygote process's select loop. Accepts new connections as 421 * they happen, and reads commands from connections one spawn-request's 422 * worth at a time. 423 * @param abiList list of ABIs supported by this zygote. 424 */ runSelectLoop(String abiList)425 Runnable runSelectLoop(String abiList) { 426 ArrayList<FileDescriptor> socketFDs = new ArrayList<>(); 427 ArrayList<ZygoteConnection> peers = new ArrayList<>(); 428 429 socketFDs.add(mZygoteSocket.getFileDescriptor()); 430 peers.add(null); 431 432 mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; 433 434 while (true) { 435 fetchUsapPoolPolicyPropsWithMinInterval(); 436 mUsapPoolRefillAction = UsapPoolRefillAction.NONE; 437 438 int[] usapPipeFDs = null; 439 StructPollfd[] pollFDs; 440 441 // Allocate enough space for the poll structs, taking into account 442 // the state of the USAP pool for this Zygote (could be a 443 // regular Zygote, a WebView Zygote, or an AppZygote). 444 if (mUsapPoolEnabled) { 445 usapPipeFDs = Zygote.getUsapPipeFDs(); 446 pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length]; 447 } else { 448 pollFDs = new StructPollfd[socketFDs.size()]; 449 } 450 451 /* 452 * For reasons of correctness the USAP pool pipe and event FDs 453 * must be processed before the session and server sockets. This 454 * is to ensure that the USAP pool accounting information is 455 * accurate when handling other requests like API deny list 456 * exemptions. 457 */ 458 459 int pollIndex = 0; 460 for (FileDescriptor socketFD : socketFDs) { 461 pollFDs[pollIndex] = new StructPollfd(); 462 pollFDs[pollIndex].fd = socketFD; 463 pollFDs[pollIndex].events = (short) POLLIN; 464 ++pollIndex; 465 } 466 467 final int usapPoolEventFDIndex = pollIndex; 468 469 if (mUsapPoolEnabled) { 470 pollFDs[pollIndex] = new StructPollfd(); 471 pollFDs[pollIndex].fd = mUsapPoolEventFD; 472 pollFDs[pollIndex].events = (short) POLLIN; 473 ++pollIndex; 474 475 // The usapPipeFDs array will always be filled in if the USAP Pool is enabled. 476 assert usapPipeFDs != null; 477 for (int usapPipeFD : usapPipeFDs) { 478 FileDescriptor managedFd = new FileDescriptor(); 479 managedFd.setInt$(usapPipeFD); 480 481 pollFDs[pollIndex] = new StructPollfd(); 482 pollFDs[pollIndex].fd = managedFd; 483 pollFDs[pollIndex].events = (short) POLLIN; 484 ++pollIndex; 485 } 486 } 487 488 int pollTimeoutMs; 489 490 if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) { 491 pollTimeoutMs = -1; 492 } else { 493 long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp; 494 495 if (elapsedTimeMs >= mUsapPoolRefillDelayMs) { 496 // The refill delay has elapsed during the period between poll invocations. 497 // We will now check for any currently ready file descriptors before refilling 498 // the USAP pool. 499 pollTimeoutMs = 0; 500 mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; 501 mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED; 502 503 } else if (elapsedTimeMs <= 0) { 504 // This can occur if the clock used by currentTimeMillis is reset, which is 505 // possible because it is not guaranteed to be monotonic. Because we can't tell 506 // how far back the clock was set the best way to recover is to simply re-start 507 // the respawn delay countdown. 508 pollTimeoutMs = mUsapPoolRefillDelayMs; 509 510 } else { 511 pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs); 512 } 513 } 514 515 int pollReturnValue; 516 try { 517 pollReturnValue = Os.poll(pollFDs, pollTimeoutMs); 518 } catch (ErrnoException ex) { 519 throw new RuntimeException("poll failed", ex); 520 } 521 522 if (pollReturnValue == 0) { 523 // The poll returned zero results either when the timeout value has been exceeded 524 // or when a non-blocking poll is issued and no FDs are ready. In either case it 525 // is time to refill the pool. This will result in a duplicate assignment when 526 // the non-blocking poll returns zero results, but it avoids an additional 527 // conditional in the else branch. 528 mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; 529 mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED; 530 531 } else { 532 boolean usapPoolFDRead = false; 533 534 while (--pollIndex >= 0) { 535 if ((pollFDs[pollIndex].revents & POLLIN) == 0) { 536 continue; 537 } 538 539 if (pollIndex == 0) { 540 // Zygote server socket 541 ZygoteConnection newPeer = acceptCommandPeer(abiList); 542 peers.add(newPeer); 543 socketFDs.add(newPeer.getFileDescriptor()); 544 } else if (pollIndex < usapPoolEventFDIndex) { 545 // Session socket accepted from the Zygote server socket 546 547 try { 548 ZygoteConnection connection = peers.get(pollIndex); 549 boolean multipleForksOK = !isUsapPoolEnabled() 550 && ZygoteHooks.isIndefiniteThreadSuspensionSafe(); 551 final Runnable command = 552 connection.processCommand(this, multipleForksOK); 553 554 // TODO (chriswailes): Is this extra check necessary? 555 if (mIsForkChild) { 556 // We're in the child. We should always have a command to run at 557 // this stage if processCommand hasn't called "exec". 558 if (command == null) { 559 throw new IllegalStateException("command == null"); 560 } 561 562 return command; 563 } else { 564 // We're in the server - we should never have any commands to run. 565 if (command != null) { 566 throw new IllegalStateException("command != null"); 567 } 568 569 // We don't know whether the remote side of the socket was closed or 570 // not until we attempt to read from it from processCommand. This 571 // shows up as a regular POLLIN event in our regular processing 572 // loop. 573 if (connection.isClosedByPeer()) { 574 connection.closeSocket(); 575 peers.remove(pollIndex); 576 socketFDs.remove(pollIndex); 577 } 578 } 579 } catch (Exception e) { 580 if (!mIsForkChild) { 581 // We're in the server so any exception here is one that has taken 582 // place pre-fork while processing commands or reading / writing 583 // from the control socket. Make a loud noise about any such 584 // exceptions so that we know exactly what failed and why. 585 586 Slog.e(TAG, "Exception executing zygote command: ", e); 587 588 // Make sure the socket is closed so that the other end knows 589 // immediately that something has gone wrong and doesn't time out 590 // waiting for a response. 591 ZygoteConnection conn = peers.remove(pollIndex); 592 conn.closeSocket(); 593 594 socketFDs.remove(pollIndex); 595 } else { 596 // We're in the child so any exception caught here has happened post 597 // fork and before we execute ActivityThread.main (or any other 598 // main() method). Log the details of the exception and bring down 599 // the process. 600 Log.e(TAG, "Caught post-fork exception in child process.", e); 601 throw e; 602 } 603 } finally { 604 // Reset the child flag, in the event that the child process is a child- 605 // zygote. The flag will not be consulted this loop pass after the 606 // Runnable is returned. 607 mIsForkChild = false; 608 } 609 610 } else { 611 // Either the USAP pool event FD or a USAP reporting pipe. 612 613 // If this is the event FD the payload will be the number of USAPs removed. 614 // If this is a reporting pipe FD the payload will be the PID of the USAP 615 // that was just specialized. The `continue` statements below ensure that 616 // the messagePayload will always be valid if we complete the try block 617 // without an exception. 618 long messagePayload; 619 620 try { 621 byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; 622 int readBytes = 623 Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); 624 625 if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { 626 DataInputStream inputStream = 627 new DataInputStream(new ByteArrayInputStream(buffer)); 628 629 messagePayload = inputStream.readLong(); 630 } else { 631 Log.e(TAG, "Incomplete read from USAP management FD of size " 632 + readBytes); 633 continue; 634 } 635 } catch (Exception ex) { 636 if (pollIndex == usapPoolEventFDIndex) { 637 Log.e(TAG, "Failed to read from USAP pool event FD: " 638 + ex.getMessage()); 639 } else { 640 Log.e(TAG, "Failed to read from USAP reporting pipe: " 641 + ex.getMessage()); 642 } 643 644 continue; 645 } 646 647 if (pollIndex > usapPoolEventFDIndex) { 648 Zygote.removeUsapTableEntry((int) messagePayload); 649 } 650 651 usapPoolFDRead = true; 652 } 653 } 654 655 if (usapPoolFDRead) { 656 int usapPoolCount = Zygote.getUsapPoolCount(); 657 658 if (usapPoolCount < mUsapPoolSizeMin) { 659 // Immediate refill 660 mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE; 661 } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) { 662 // Delayed refill 663 mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis(); 664 } 665 } 666 } 667 668 if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) { 669 int[] sessionSocketRawFDs = 670 socketFDs.subList(1, socketFDs.size()) 671 .stream() 672 .mapToInt(FileDescriptor::getInt$) 673 .toArray(); 674 675 final boolean isPriorityRefill = 676 mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE; 677 678 final Runnable command = 679 fillUsapPool(sessionSocketRawFDs, isPriorityRefill); 680 681 if (command != null) { 682 return command; 683 } else if (isPriorityRefill) { 684 // Schedule a delayed refill to finish refilling the pool. 685 mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis(); 686 } 687 } 688 } 689 } 690 } 691