1 /* 2 * Copyright (C) 2014 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.O_CLOEXEC; 20 21 import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC; 22 23 import android.content.pm.ApplicationInfo; 24 import android.net.Credentials; 25 import android.net.LocalServerSocket; 26 import android.net.LocalSocket; 27 import android.os.Build; 28 import android.os.FactoryTest; 29 import android.os.IVold; 30 import android.os.Process; 31 import android.os.SystemProperties; 32 import android.os.Trace; 33 import android.provider.DeviceConfig; 34 import android.system.ErrnoException; 35 import android.system.Os; 36 import android.util.Log; 37 38 import dalvik.system.ZygoteHooks; 39 40 import libcore.io.IoUtils; 41 42 import java.io.BufferedReader; 43 import java.io.ByteArrayOutputStream; 44 import java.io.DataOutputStream; 45 import java.io.FileDescriptor; 46 import java.io.IOException; 47 import java.io.InputStreamReader; 48 49 /** @hide */ 50 public final class Zygote { 51 /* 52 * Bit values for "runtimeFlags" argument. The definitions are duplicated 53 * in the native code. 54 */ 55 56 /** enable debugging over JDWP */ 57 public static final int DEBUG_ENABLE_JDWP = 1; 58 /** enable JNI checks */ 59 public static final int DEBUG_ENABLE_CHECKJNI = 1 << 1; 60 /** enable Java programming language "assert" statements */ 61 public static final int DEBUG_ENABLE_ASSERT = 1 << 2; 62 /** disable the AOT compiler and JIT */ 63 public static final int DEBUG_ENABLE_SAFEMODE = 1 << 3; 64 /** Enable logging of third-party JNI activity. */ 65 public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4; 66 /** Force generation of native debugging information. */ 67 public static final int DEBUG_GENERATE_DEBUG_INFO = 1 << 5; 68 /** Always use JIT-ed code. */ 69 public static final int DEBUG_ALWAYS_JIT = 1 << 6; 70 /** Make the code native debuggable by turning off some optimizations. */ 71 public static final int DEBUG_NATIVE_DEBUGGABLE = 1 << 7; 72 /** Make the code Java debuggable by turning off some optimizations. */ 73 public static final int DEBUG_JAVA_DEBUGGABLE = 1 << 8; 74 75 /** Turn off the verifier. */ 76 public static final int DISABLE_VERIFIER = 1 << 9; 77 /** Only use oat files located in /system. Otherwise use dex/jar/apk . */ 78 public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10; 79 /** Force generation of native debugging information for backtraces. */ 80 public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11; 81 /** 82 * Hidden API access restrictions. This is a mask for bits representing the API enforcement 83 * policy, defined by {@code @ApplicationInfo.HiddenApiEnforcementPolicy}. 84 */ 85 public static final int API_ENFORCEMENT_POLICY_MASK = (1 << 12) | (1 << 13); 86 /** 87 * Bit shift for use with {@link #API_ENFORCEMENT_POLICY_MASK}. 88 * 89 * (flags & API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT gives 90 * @ApplicationInfo.ApiEnforcementPolicy values. 91 */ 92 public static final int API_ENFORCEMENT_POLICY_SHIFT = 93 Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK); 94 /** 95 * Enable system server ART profiling. 96 */ 97 public static final int PROFILE_SYSTEM_SERVER = 1 << 14; 98 99 /** 100 * Enable profiling from shell. 101 */ 102 public static final int PROFILE_FROM_SHELL = 1 << 15; 103 104 /* 105 * Enable using the ART app image startup cache 106 */ 107 public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16; 108 109 /** No external storage should be mounted. */ 110 public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE; 111 /** Default external storage should be mounted. */ 112 public static final int MOUNT_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT; 113 /** Read-only external storage should be mounted. */ 114 public static final int MOUNT_EXTERNAL_READ = IVold.REMOUNT_MODE_READ; 115 /** Read-write external storage should be mounted. */ 116 public static final int MOUNT_EXTERNAL_WRITE = IVold.REMOUNT_MODE_WRITE; 117 /** 118 * Mount mode for apps that are already installed on the device before the isolated_storage 119 * feature is enabled. 120 */ 121 public static final int MOUNT_EXTERNAL_LEGACY = IVold.REMOUNT_MODE_LEGACY; 122 /** 123 * Mount mode for package installers which should give them access to 124 * all obb dirs in addition to their package sandboxes 125 */ 126 public static final int MOUNT_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER; 127 /** Read-write external storage should be mounted instead of package sandbox */ 128 public static final int MOUNT_EXTERNAL_FULL = IVold.REMOUNT_MODE_FULL; 129 130 /** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */ 131 public static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8; 132 133 /** 134 * An extraArg passed when a zygote process is forking a child-zygote, specifying a name 135 * in the abstract socket namespace. This socket name is what the new child zygote 136 * should listen for connections on. 137 */ 138 public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket="; 139 140 /** 141 * An extraArg passed when a zygote process is forking a child-zygote, specifying the 142 * requested ABI for the child Zygote. 143 */ 144 public static final String CHILD_ZYGOTE_ABI_LIST_ARG = "--abi-list="; 145 146 /** 147 * An extraArg passed when a zygote process is forking a child-zygote, specifying the 148 * start of the UID range the children of the Zygote may setuid()/setgid() to. This 149 * will be enforced with a seccomp filter. 150 */ 151 public static final String CHILD_ZYGOTE_UID_RANGE_START = "--uid-range-start="; 152 153 /** 154 * An extraArg passed when a zygote process is forking a child-zygote, specifying the 155 * end of the UID range the children of the Zygote may setuid()/setgid() to. This 156 * will be enforced with a seccomp filter. 157 */ 158 public static final String CHILD_ZYGOTE_UID_RANGE_END = "--uid-range-end="; 159 160 /** Prefix prepended to socket names created by init */ 161 private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"; 162 163 /** 164 * The duration to wait before re-checking Zygote related system properties. 165 * 166 * One minute in milliseconds. 167 */ 168 public static final long PROPERTY_CHECK_INTERVAL = 60000; 169 170 /** 171 * @hide for internal use only 172 */ 173 public static final int SOCKET_BUFFER_SIZE = 256; 174 175 /** a prototype instance for a future List.toArray() */ 176 protected static final int[][] INT_ARRAY_2D = new int[0][0]; 177 178 /** 179 * @hide for internal use only. 180 */ 181 public static final String PRIMARY_SOCKET_NAME = "zygote"; 182 183 /** 184 * @hide for internal use only. 185 */ 186 public static final String SECONDARY_SOCKET_NAME = "zygote_secondary"; 187 188 /** 189 * @hide for internal use only 190 */ 191 public static final String USAP_POOL_PRIMARY_SOCKET_NAME = "usap_pool_primary"; 192 193 /** 194 * @hide for internal use only 195 */ 196 public static final String USAP_POOL_SECONDARY_SOCKET_NAME = "usap_pool_secondary"; 197 Zygote()198 private Zygote() {} 199 200 /** 201 * Forks a new VM instance. The current VM must have been started 202 * with the -Xzygote flag. <b>NOTE: new instance keeps all 203 * root capabilities. The new process is expected to call capset()</b>. 204 * 205 * @param uid the UNIX uid that the new process should setuid() to after 206 * fork()ing and and before spawning any threads. 207 * @param gid the UNIX gid that the new process should setgid() to after 208 * fork()ing and and before spawning any threads. 209 * @param gids null-ok; a list of UNIX gids that the new process should 210 * setgroups() to after fork and before spawning any threads. 211 * @param runtimeFlags bit flags that enable ART features. 212 * @param rlimits null-ok an array of rlimit tuples, with the second 213 * dimension having a length of 3 and representing 214 * (resource, rlim_cur, rlim_max). These are set via the posix 215 * setrlimit(2) call. 216 * @param seInfo null-ok a string specifying SELinux information for 217 * the new process. 218 * @param niceName null-ok a string specifying the process name. 219 * @param fdsToClose an array of ints, holding one or more POSIX 220 * file descriptor numbers that are to be closed by the child 221 * (and replaced by /dev/null) after forking. An integer value 222 * of -1 in any entry in the array means "ignore this one". 223 * @param fdsToIgnore null-ok an array of ints, either null or holding 224 * one or more POSIX file descriptor numbers that are to be ignored 225 * in the file descriptor table check. 226 * @param startChildZygote if true, the new child process will itself be a 227 * new zygote process. 228 * @param instructionSet null-ok the instruction set to use. 229 * @param appDataDir null-ok the data directory of the app. 230 * 231 * @return 0 if this is the child, pid of the child 232 * if this is the parent, or -1 on error. 233 */ forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, int targetSdkVersion)234 public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, 235 int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, 236 int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, 237 int targetSdkVersion) { 238 ZygoteHooks.preFork(); 239 // Resets nice priority for zygote process. 240 resetNicePriority(); 241 int pid = nativeForkAndSpecialize( 242 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, 243 fdsToIgnore, startChildZygote, instructionSet, appDataDir); 244 // Enable tracing as soon as possible for the child process. 245 if (pid == 0) { 246 Zygote.disableExecuteOnly(targetSdkVersion); 247 Trace.setTracingEnabled(true, runtimeFlags); 248 249 // Note that this event ends at the end of handleChildProc, 250 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); 251 } 252 ZygoteHooks.postForkCommon(); 253 return pid; 254 } 255 nativeForkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir)256 private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids, 257 int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, 258 int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, 259 String appDataDir); 260 261 /** 262 * Specialize an unspecialized app process. The current VM must have been started 263 * with the -Xzygote flag. 264 * 265 * @param uid The UNIX uid that the new process should setuid() to before spawning any threads 266 * @param gid The UNIX gid that the new process should setgid() to before spawning any threads 267 * @param gids null-ok; A list of UNIX gids that the new process should 268 * setgroups() to before spawning any threads 269 * @param runtimeFlags Bit flags that enable ART features 270 * @param rlimits null-ok An array of rlimit tuples, with the second 271 * dimension having a length of 3 and representing 272 * (resource, rlim_cur, rlim_max). These are set via the posix 273 * setrlimit(2) call. 274 * @param seInfo null-ok A string specifying SELinux information for 275 * the new process. 276 * @param niceName null-ok A string specifying the process name. 277 * @param startChildZygote If true, the new child process will itself be a 278 * new zygote process. 279 * @param instructionSet null-ok The instruction set to use. 280 * @param appDataDir null-ok The data directory of the app. 281 */ specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir)282 public static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, 283 int[][] rlimits, int mountExternal, String seInfo, String niceName, 284 boolean startChildZygote, String instructionSet, String appDataDir) { 285 nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, 286 niceName, startChildZygote, instructionSet, appDataDir); 287 288 // Enable tracing as soon as possible for the child process. 289 Trace.setTracingEnabled(true, runtimeFlags); 290 291 // Note that this event ends at the end of handleChildProc. 292 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); 293 294 /* 295 * This is called here (instead of after the fork but before the specialize) to maintain 296 * consistancy with the code paths for forkAndSpecialize. 297 * 298 * TODO (chriswailes): Look into moving this to immediately after the fork. 299 */ 300 ZygoteHooks.postForkCommon(); 301 } 302 nativeSpecializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir)303 private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids, 304 int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, 305 boolean startChildZygote, String instructionSet, String appDataDir); 306 307 /** 308 * Called to do any initialization before starting an application. 309 */ nativePreApplicationInit()310 static native void nativePreApplicationInit(); 311 312 /** 313 * Special method to start the system server process. In addition to the 314 * common actions performed in forkAndSpecialize, the pid of the child 315 * process is recorded such that the death of the child process will cause 316 * zygote to exit. 317 * 318 * @param uid the UNIX uid that the new process should setuid() to after 319 * fork()ing and and before spawning any threads. 320 * @param gid the UNIX gid that the new process should setgid() to after 321 * fork()ing and and before spawning any threads. 322 * @param gids null-ok; a list of UNIX gids that the new process should 323 * setgroups() to after fork and before spawning any threads. 324 * @param runtimeFlags bit flags that enable ART features. 325 * @param rlimits null-ok an array of rlimit tuples, with the second 326 * dimension having a length of 3 and representing 327 * (resource, rlim_cur, rlim_max). These are set via the posix 328 * setrlimit(2) call. 329 * @param permittedCapabilities argument for setcap() 330 * @param effectiveCapabilities argument for setcap() 331 * 332 * @return 0 if this is the child, pid of the child 333 * if this is the parent, or -1 on error. 334 */ forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)335 public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, 336 int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { 337 ZygoteHooks.preFork(); 338 // Resets nice priority for zygote process. 339 resetNicePriority(); 340 int pid = nativeForkSystemServer( 341 uid, gid, gids, runtimeFlags, rlimits, 342 permittedCapabilities, effectiveCapabilities); 343 // Enable tracing as soon as we enter the system_server. 344 if (pid == 0) { 345 Trace.setTracingEnabled(true, runtimeFlags); 346 } 347 ZygoteHooks.postForkCommon(); 348 return pid; 349 } 350 nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)351 private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, 352 int[][] rlimits, long permittedCapabilities, long effectiveCapabilities); 353 354 /** 355 * Lets children of the zygote inherit open file descriptors to this path. 356 */ nativeAllowFileAcrossFork(String path)357 protected static native void nativeAllowFileAcrossFork(String path); 358 359 /** 360 * Lets children of the zygote inherit open file descriptors that belong to the 361 * ApplicationInfo that is passed in. 362 * 363 * @param appInfo ApplicationInfo of the application 364 */ allowAppFilesAcrossFork(ApplicationInfo appInfo)365 protected static void allowAppFilesAcrossFork(ApplicationInfo appInfo) { 366 for (String path : appInfo.getAllApkPaths()) { 367 Zygote.nativeAllowFileAcrossFork(path); 368 } 369 } 370 371 /** 372 * Installs a seccomp filter that limits setresuid()/setresgid() to the passed-in range 373 * @param uidGidMin The smallest allowed uid/gid 374 * @param uidGidMax The largest allowed uid/gid 375 */ nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax)376 native protected static void nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax); 377 378 /** 379 * Initialize the native state of the Zygote. This inclues 380 * - Fetching socket FDs from the environment 381 * - Initializing security properties 382 * - Unmounting storage as appropriate 383 * - Loading necessary performance profile information 384 * 385 * @param isPrimary True if this is the zygote process, false if it is zygote_secondary 386 */ initNativeState(boolean isPrimary)387 static void initNativeState(boolean isPrimary) { 388 nativeInitNativeState(isPrimary); 389 } 390 nativeInitNativeState(boolean isPrimary)391 protected static native void nativeInitNativeState(boolean isPrimary); 392 393 /** 394 * Returns the raw string value of a system property. 395 * 396 * Note that Device Config is not available without an application so SystemProperties is used 397 * instead. 398 * 399 * TODO (chriswailes): Cache the system property location in native code and then write a JNI 400 * function to fetch it. 401 */ getConfigurationProperty(String propertyName, String defaultValue)402 public static String getConfigurationProperty(String propertyName, String defaultValue) { 403 return SystemProperties.get( 404 String.join(".", 405 "persist.device_config", 406 DeviceConfig.NAMESPACE_RUNTIME_NATIVE, 407 propertyName), 408 defaultValue); 409 } 410 emptyUsapPool()411 protected static void emptyUsapPool() { 412 nativeEmptyUsapPool(); 413 } 414 nativeEmptyUsapPool()415 private static native void nativeEmptyUsapPool(); 416 417 /** 418 * Returns the value of a system property converted to a boolean using specific logic. 419 * 420 * Note that Device Config is not available without an application so SystemProperties is used 421 * instead. 422 * 423 * @see SystemProperties.getBoolean 424 * 425 * TODO (chriswailes): Cache the system property location in native code and then write a JNI 426 * function to fetch it. 427 * TODO (chriswailes): Move into ZygoteConfig.java once the necessary CL lands (go/ag/6580627) 428 */ getConfigurationPropertyBoolean( String propertyName, Boolean defaultValue)429 public static boolean getConfigurationPropertyBoolean( 430 String propertyName, Boolean defaultValue) { 431 return SystemProperties.getBoolean( 432 String.join(".", 433 "persist.device_config", 434 DeviceConfig.NAMESPACE_RUNTIME_NATIVE, 435 propertyName), 436 defaultValue); 437 } 438 439 /** 440 * @return Number of unspecialized app processes currently in the pool 441 */ getUsapPoolCount()442 static int getUsapPoolCount() { 443 return nativeGetUsapPoolCount(); 444 } 445 nativeGetUsapPoolCount()446 private static native int nativeGetUsapPoolCount(); 447 448 /** 449 * @return The event FD used for communication between the signal handler and the ZygoteServer 450 * poll loop 451 */ getUsapPoolEventFD()452 static FileDescriptor getUsapPoolEventFD() { 453 FileDescriptor fd = new FileDescriptor(); 454 fd.setInt$(nativeGetUsapPoolEventFD()); 455 456 return fd; 457 } 458 nativeGetUsapPoolEventFD()459 private static native int nativeGetUsapPoolEventFD(); 460 461 /** 462 * Fork a new unspecialized app process from the zygote 463 * 464 * @param sessionSocketRawFDs Anonymous session sockets that are currently open 465 * @return In the Zygote process this function will always return null; in unspecialized app 466 * processes this function will return a Runnable object representing the new 467 * application that is passed up from usapMain. 468 */ forkUsap(LocalServerSocket usapPoolSocket, int[] sessionSocketRawFDs)469 static Runnable forkUsap(LocalServerSocket usapPoolSocket, 470 int[] sessionSocketRawFDs) { 471 FileDescriptor[] pipeFDs = null; 472 473 try { 474 pipeFDs = Os.pipe2(O_CLOEXEC); 475 } catch (ErrnoException errnoEx) { 476 throw new IllegalStateException("Unable to create USAP pipe.", errnoEx); 477 } 478 479 int pid = 480 nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs); 481 482 if (pid == 0) { 483 IoUtils.closeQuietly(pipeFDs[0]); 484 return usapMain(usapPoolSocket, pipeFDs[1]); 485 } else { 486 // The read-end of the pipe will be closed by the native code. 487 // See removeUsapTableEntry(); 488 IoUtils.closeQuietly(pipeFDs[1]); 489 return null; 490 } 491 } 492 nativeForkUsap(int readPipeFD, int writePipeFD, int[] sessionSocketRawFDs)493 private static native int nativeForkUsap(int readPipeFD, 494 int writePipeFD, 495 int[] sessionSocketRawFDs); 496 497 /** 498 * This function is used by unspecialized app processes to wait for specialization requests from 499 * the system server. 500 * 501 * @param writePipe The write end of the reporting pipe used to communicate with the poll loop 502 * of the ZygoteServer. 503 * @return A runnable oject representing the new application. 504 */ usapMain(LocalServerSocket usapPoolSocket, FileDescriptor writePipe)505 private static Runnable usapMain(LocalServerSocket usapPoolSocket, 506 FileDescriptor writePipe) { 507 final int pid = Process.myPid(); 508 Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32"); 509 510 LocalSocket sessionSocket = null; 511 DataOutputStream usapOutputStream = null; 512 Credentials peerCredentials = null; 513 ZygoteArguments args = null; 514 515 while (true) { 516 try { 517 sessionSocket = usapPoolSocket.accept(); 518 519 // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool. 520 blockSigTerm(); 521 522 BufferedReader usapReader = 523 new BufferedReader(new InputStreamReader(sessionSocket.getInputStream())); 524 usapOutputStream = 525 new DataOutputStream(sessionSocket.getOutputStream()); 526 527 peerCredentials = sessionSocket.getPeerCredentials(); 528 529 String[] argStrings = readArgumentList(usapReader); 530 531 if (argStrings != null) { 532 args = new ZygoteArguments(argStrings); 533 534 // TODO (chriswailes): Should this only be run for debug builds? 535 validateUsapCommand(args); 536 break; 537 } else { 538 Log.e("USAP", "Truncated command received."); 539 IoUtils.closeQuietly(sessionSocket); 540 541 // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary. 542 unblockSigTerm(); 543 } 544 } catch (Exception ex) { 545 Log.e("USAP", ex.getMessage()); 546 IoUtils.closeQuietly(sessionSocket); 547 548 // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary. 549 unblockSigTerm(); 550 } 551 } 552 553 try { 554 // SIGTERM is blocked on loop exit. This prevents a USAP that is specializing from 555 // being killed during a pool flush. 556 557 applyUidSecurityPolicy(args, peerCredentials); 558 applyDebuggerSystemProperty(args); 559 560 int[][] rlimits = null; 561 562 if (args.mRLimits != null) { 563 rlimits = args.mRLimits.toArray(INT_ARRAY_2D); 564 } 565 566 // This must happen before the SELinux policy for this process is 567 // changed when specializing. 568 try { 569 // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a 570 // Process.ProcessStartResult object. 571 usapOutputStream.writeInt(pid); 572 } catch (IOException ioEx) { 573 Log.e("USAP", "Failed to write response to session socket: " 574 + ioEx.getMessage()); 575 throw new RuntimeException(ioEx); 576 } finally { 577 IoUtils.closeQuietly(sessionSocket); 578 579 try { 580 // This socket is closed using Os.close due to an issue with the implementation 581 // of LocalSocketImp.close(). Because the raw FD is created by init and then 582 // loaded from an environment variable (as opposed to being created by the 583 // LocalSocketImpl itself) the current implementation will not actually close 584 // the underlying FD. 585 // 586 // See b/130309968 for discussion of this issue. 587 Os.close(usapPoolSocket.getFileDescriptor()); 588 } catch (ErrnoException ex) { 589 Log.e("USAP", "Failed to close USAP pool socket"); 590 throw new RuntimeException(ex); 591 } 592 } 593 594 try { 595 ByteArrayOutputStream buffer = 596 new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES); 597 DataOutputStream outputStream = new DataOutputStream(buffer); 598 599 // This is written as a long so that the USAP reporting pipe and USAP pool event FD 600 // handlers in ZygoteServer.runSelectLoop can be unified. These two cases should 601 // both send/receive 8 bytes. 602 outputStream.writeLong(pid); 603 outputStream.flush(); 604 605 Os.write(writePipe, buffer.toByteArray(), 0, buffer.size()); 606 } catch (Exception ex) { 607 Log.e("USAP", 608 String.format("Failed to write PID (%d) to pipe (%d): %s", 609 pid, writePipe.getInt$(), ex.getMessage())); 610 throw new RuntimeException(ex); 611 } finally { 612 IoUtils.closeQuietly(writePipe); 613 } 614 615 specializeAppProcess(args.mUid, args.mGid, args.mGids, 616 args.mRuntimeFlags, rlimits, args.mMountExternal, 617 args.mSeInfo, args.mNiceName, args.mStartChildZygote, 618 args.mInstructionSet, args.mAppDataDir); 619 620 disableExecuteOnly(args.mTargetSdkVersion); 621 622 if (args.mNiceName != null) { 623 Process.setArgV0(args.mNiceName); 624 } 625 626 // End of the postFork event. 627 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 628 629 return ZygoteInit.zygoteInit(args.mTargetSdkVersion, 630 args.mRemainingArgs, 631 null /* classLoader */); 632 } finally { 633 // Unblock SIGTERM to restore the process to default behavior. 634 unblockSigTerm(); 635 } 636 } 637 blockSigTerm()638 private static void blockSigTerm() { 639 nativeBlockSigTerm(); 640 } 641 nativeBlockSigTerm()642 private static native void nativeBlockSigTerm(); 643 unblockSigTerm()644 private static void unblockSigTerm() { 645 nativeUnblockSigTerm(); 646 } 647 nativeUnblockSigTerm()648 private static native void nativeUnblockSigTerm(); 649 650 private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: "; 651 652 /** 653 * Checks a set of zygote arguments to see if they can be handled by a USAP. Throws an 654 * exception if an invalid arugment is encountered. 655 * @param args The arguments to test 656 */ validateUsapCommand(ZygoteArguments args)657 private static void validateUsapCommand(ZygoteArguments args) { 658 if (args.mAbiListQuery) { 659 throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--query-abi-list"); 660 } else if (args.mPidQuery) { 661 throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--get-pid"); 662 } else if (args.mPreloadDefault) { 663 throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-default"); 664 } else if (args.mPreloadPackage != null) { 665 throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-package"); 666 } else if (args.mPreloadApp != null) { 667 throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-app"); 668 } else if (args.mStartChildZygote) { 669 throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote"); 670 } else if (args.mApiBlacklistExemptions != null) { 671 throw new IllegalArgumentException( 672 USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions"); 673 } else if (args.mHiddenApiAccessLogSampleRate != -1) { 674 throw new IllegalArgumentException( 675 USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate="); 676 } else if (args.mHiddenApiAccessStatslogSampleRate != -1) { 677 throw new IllegalArgumentException( 678 USAP_ERROR_PREFIX + "--hidden-api-statslog-sampling-rate="); 679 } else if (args.mInvokeWith != null) { 680 throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--invoke-with"); 681 } else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) { 682 throw new ZygoteSecurityException("Client may not specify capabilities: " 683 + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities) 684 + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities)); 685 } 686 } 687 688 /** 689 * Mark execute-only segments of libraries read+execute for apps with targetSdkVersion<Q. 690 */ disableExecuteOnly(int targetSdkVersion)691 protected static void disableExecuteOnly(int targetSdkVersion) { 692 if ((targetSdkVersion < Build.VERSION_CODES.Q) && !nativeDisableExecuteOnly()) { 693 Log.e("Zygote", "Failed to set libraries to read+execute."); 694 } 695 } 696 nativeDisableExecuteOnly()697 private static native boolean nativeDisableExecuteOnly(); 698 699 /** 700 * @return Raw file descriptors for the read-end of USAP reporting pipes. 701 */ getUsapPipeFDs()702 protected static int[] getUsapPipeFDs() { 703 return nativeGetUsapPipeFDs(); 704 } 705 nativeGetUsapPipeFDs()706 private static native int[] nativeGetUsapPipeFDs(); 707 708 /** 709 * Remove the USAP table entry for the provided process ID. 710 * 711 * @param usapPID Process ID of the entry to remove 712 * @return True if the entry was removed; false if it doesn't exist 713 */ removeUsapTableEntry(int usapPID)714 protected static boolean removeUsapTableEntry(int usapPID) { 715 return nativeRemoveUsapTableEntry(usapPID); 716 } 717 nativeRemoveUsapTableEntry(int usapPID)718 private static native boolean nativeRemoveUsapTableEntry(int usapPID); 719 720 /** 721 * uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal 722 * operation. It may also specify any gid and setgroups() list it chooses. 723 * In factory test mode, it may specify any UID. 724 * 725 * @param args non-null; zygote spawner arguments 726 * @param peer non-null; peer credentials 727 * @throws ZygoteSecurityException 728 */ applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)729 protected static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer) 730 throws ZygoteSecurityException { 731 732 if (peer.getUid() == Process.SYSTEM_UID) { 733 /* In normal operation, SYSTEM_UID can only specify a restricted 734 * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid. 735 */ 736 boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF; 737 738 if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) { 739 throw new ZygoteSecurityException( 740 "System UID may not launch process with UID < " 741 + Process.SYSTEM_UID); 742 } 743 } 744 745 // If not otherwise specified, uid and gid are inherited from peer 746 if (!args.mUidSpecified) { 747 args.mUid = peer.getUid(); 748 args.mUidSpecified = true; 749 } 750 if (!args.mGidSpecified) { 751 args.mGid = peer.getGid(); 752 args.mGidSpecified = true; 753 } 754 } 755 756 /** 757 * Applies debugger system properties to the zygote arguments. 758 * 759 * If "ro.debuggable" is "1", all apps are debuggable. Otherwise, 760 * the debugger state is specified via the "--enable-jdwp" flag 761 * in the spawn request. 762 * 763 * @param args non-null; zygote spawner args 764 */ applyDebuggerSystemProperty(ZygoteArguments args)765 protected static void applyDebuggerSystemProperty(ZygoteArguments args) { 766 if (RoSystemProperties.DEBUGGABLE) { 767 args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP; 768 } 769 } 770 771 /** 772 * Applies zygote security policy. 773 * Based on the credentials of the process issuing a zygote command: 774 * <ol> 775 * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a 776 * wrapper command. 777 * <li> Any other uid may not specify any invoke-with argument. 778 * </ul> 779 * 780 * @param args non-null; zygote spawner arguments 781 * @param peer non-null; peer credentials 782 * @throws ZygoteSecurityException 783 */ applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer)784 protected static void applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer) 785 throws ZygoteSecurityException { 786 int peerUid = peer.getUid(); 787 788 if (args.mInvokeWith != null && peerUid != 0 789 && (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) { 790 throw new ZygoteSecurityException("Peer is permitted to specify an " 791 + "explicit invoke-with wrapper command only for debuggable " 792 + "applications."); 793 } 794 } 795 796 /** 797 * Applies invoke-with system properties to the zygote arguments. 798 * 799 * @param args non-null; zygote args 800 */ applyInvokeWithSystemProperty(ZygoteArguments args)801 protected static void applyInvokeWithSystemProperty(ZygoteArguments args) { 802 if (args.mInvokeWith == null && args.mNiceName != null) { 803 String property = "wrap." + args.mNiceName; 804 args.mInvokeWith = SystemProperties.get(property); 805 if (args.mInvokeWith != null && args.mInvokeWith.length() == 0) { 806 args.mInvokeWith = null; 807 } 808 } 809 } 810 811 /** 812 * Reads an argument list from the provided socket 813 * @return Argument list or null if EOF is reached 814 * @throws IOException passed straight through 815 */ readArgumentList(BufferedReader socketReader)816 static String[] readArgumentList(BufferedReader socketReader) throws IOException { 817 int argc; 818 819 try { 820 String argc_string = socketReader.readLine(); 821 822 if (argc_string == null) { 823 // EOF reached. 824 return null; 825 } 826 argc = Integer.parseInt(argc_string); 827 828 } catch (NumberFormatException ex) { 829 Log.e("Zygote", "Invalid Zygote wire format: non-int at argc"); 830 throw new IOException("Invalid wire format"); 831 } 832 833 // See bug 1092107: large argc can be used for a DOS attack 834 if (argc > MAX_ZYGOTE_ARGC) { 835 throw new IOException("Max arg count exceeded"); 836 } 837 838 String[] args = new String[argc]; 839 for (int arg_index = 0; arg_index < argc; arg_index++) { 840 args[arg_index] = socketReader.readLine(); 841 if (args[arg_index] == null) { 842 // We got an unexpected EOF. 843 throw new IOException("Truncated request"); 844 } 845 } 846 847 return args; 848 } 849 850 /** 851 * Creates a managed LocalServerSocket object using a file descriptor 852 * created by an init.rc script. The init scripts that specify the 853 * sockets name can be found in system/core/rootdir. The socket is bound 854 * to the file system in the /dev/sockets/ directory, and the file 855 * descriptor is shared via the ANDROID_SOCKET_<socketName> environment 856 * variable. 857 */ createManagedSocketFromInitSocket(String socketName)858 static LocalServerSocket createManagedSocketFromInitSocket(String socketName) { 859 int fileDesc; 860 final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; 861 862 try { 863 String env = System.getenv(fullSocketName); 864 fileDesc = Integer.parseInt(env); 865 } catch (RuntimeException ex) { 866 throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex); 867 } 868 869 try { 870 FileDescriptor fd = new FileDescriptor(); 871 fd.setInt$(fileDesc); 872 return new LocalServerSocket(fd); 873 } catch (IOException ex) { 874 throw new RuntimeException( 875 "Error building socket from file descriptor: " + fileDesc, ex); 876 } 877 } 878 callPostForkSystemServerHooks()879 private static void callPostForkSystemServerHooks() { 880 // SystemServer specific post fork hooks run before child post fork hooks. 881 ZygoteHooks.postForkSystemServer(); 882 } 883 callPostForkChildHooks(int runtimeFlags, boolean isSystemServer, boolean isZygote, String instructionSet)884 private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer, 885 boolean isZygote, String instructionSet) { 886 ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet); 887 } 888 889 /** 890 * Resets the calling thread priority to the default value (Thread.NORM_PRIORITY 891 * or nice value 0). This updates both the priority value in java.lang.Thread and 892 * the nice value (setpriority). 893 */ resetNicePriority()894 static void resetNicePriority() { 895 Thread.currentThread().setPriority(Thread.NORM_PRIORITY); 896 } 897 898 /** 899 * Executes "/system/bin/sh -c <command>" using the exec() system call. 900 * This method throws a runtime exception if exec() failed, otherwise, this 901 * method never returns. 902 * 903 * @param command The shell command to execute. 904 */ execShell(String command)905 public static void execShell(String command) { 906 String[] args = { "/system/bin/sh", "-c", command }; 907 try { 908 Os.execv(args[0], args); 909 } catch (ErrnoException e) { 910 throw new RuntimeException(e); 911 } 912 } 913 914 /** 915 * Appends quotes shell arguments to the specified string builder. 916 * The arguments are quoted using single-quotes, escaped if necessary, 917 * prefixed with a space, and appended to the command. 918 * 919 * @param command A string builder for the shell command being constructed. 920 * @param args An array of argument strings to be quoted and appended to the command. 921 * @see #execShell(String) 922 */ appendQuotedShellArgs(StringBuilder command, String[] args)923 public static void appendQuotedShellArgs(StringBuilder command, String[] args) { 924 for (String arg : args) { 925 command.append(" '").append(arg.replace("'", "'\\''")).append("'"); 926 } 927 } 928 } 929