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 import static android.system.OsConstants.S_IRWXG; 21 import static android.system.OsConstants.S_IRWXO; 22 23 import android.content.res.Resources; 24 import android.content.res.TypedArray; 25 import android.icu.impl.CacheValue; 26 import android.icu.text.DecimalFormatSymbols; 27 import android.icu.util.ULocale; 28 import android.net.LocalServerSocket; 29 import android.opengl.EGL14; 30 import android.os.Process; 31 import android.os.SystemClock; 32 import android.os.SystemProperties; 33 import android.os.Trace; 34 import android.security.keystore.AndroidKeyStoreProvider; 35 import android.system.ErrnoException; 36 import android.system.Os; 37 import android.system.OsConstants; 38 import android.system.StructPollfd; 39 import android.text.Hyphenator; 40 import android.util.EventLog; 41 import android.util.Log; 42 import android.webkit.WebViewFactory; 43 import android.widget.TextView; 44 45 import com.android.internal.os.InstallerConnection.InstallerException; 46 47 import dalvik.system.DexFile; 48 import dalvik.system.PathClassLoader; 49 import dalvik.system.VMRuntime; 50 import dalvik.system.ZygoteHooks; 51 52 import libcore.io.IoUtils; 53 54 import java.io.BufferedReader; 55 import java.io.FileDescriptor; 56 import java.io.FileInputStream; 57 import java.io.FileNotFoundException; 58 import java.io.IOException; 59 import java.io.InputStream; 60 import java.io.InputStreamReader; 61 import java.lang.reflect.InvocationTargetException; 62 import java.lang.reflect.Method; 63 import java.security.Security; 64 import java.security.Provider; 65 import java.util.ArrayList; 66 67 /** 68 * Startup class for the zygote process. 69 * 70 * Pre-initializes some classes, and then waits for commands on a UNIX domain 71 * socket. Based on these commands, forks off child processes that inherit 72 * the initial state of the VM. 73 * 74 * Please see {@link ZygoteConnection.Arguments} for documentation on the 75 * client protocol. 76 * 77 * @hide 78 */ 79 public class ZygoteInit { 80 private static final String TAG = "Zygote"; 81 82 private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload"; 83 private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; 84 private static final String PROPERTY_RUNNING_IN_CONTAINER = "ro.boot.container"; 85 86 private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"; 87 88 private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020; 89 private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030; 90 91 /** when preloading, GC after allocating this many bytes */ 92 private static final int PRELOAD_GC_THRESHOLD = 50000; 93 94 private static final String ABI_LIST_ARG = "--abi-list="; 95 96 private static final String SOCKET_NAME_ARG = "--socket-name="; 97 98 private static LocalServerSocket sServerSocket; 99 100 /** 101 * Used to pre-load resources. We hold a global reference on it so it 102 * never gets destroyed. 103 */ 104 private static Resources mResources; 105 106 /** 107 * The path of a file that contains classes to preload. 108 */ 109 private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes"; 110 111 /** Controls whether we should preload resources during zygote init. */ 112 public static final boolean PRELOAD_RESOURCES = true; 113 114 /** 115 * Registers a server socket for zygote command connections 116 * 117 * @throws RuntimeException when open fails 118 */ registerZygoteSocket(String socketName)119 private static void registerZygoteSocket(String socketName) { 120 if (sServerSocket == null) { 121 int fileDesc; 122 final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; 123 try { 124 String env = System.getenv(fullSocketName); 125 fileDesc = Integer.parseInt(env); 126 } catch (RuntimeException ex) { 127 throw new RuntimeException(fullSocketName + " unset or invalid", ex); 128 } 129 130 try { 131 FileDescriptor fd = new FileDescriptor(); 132 fd.setInt$(fileDesc); 133 sServerSocket = new LocalServerSocket(fd); 134 } catch (IOException ex) { 135 throw new RuntimeException( 136 "Error binding to local socket '" + fileDesc + "'", ex); 137 } 138 } 139 } 140 141 /** 142 * Waits for and accepts a single command connection. Throws 143 * RuntimeException on failure. 144 */ acceptCommandPeer(String abiList)145 private static ZygoteConnection acceptCommandPeer(String abiList) { 146 try { 147 return new ZygoteConnection(sServerSocket.accept(), abiList); 148 } catch (IOException ex) { 149 throw new RuntimeException( 150 "IOException during accept()", ex); 151 } 152 } 153 154 /** 155 * Close and clean up zygote sockets. Called on shutdown and on the 156 * child's exit path. 157 */ closeServerSocket()158 static void closeServerSocket() { 159 try { 160 if (sServerSocket != null) { 161 FileDescriptor fd = sServerSocket.getFileDescriptor(); 162 sServerSocket.close(); 163 if (fd != null) { 164 Os.close(fd); 165 } 166 } 167 } catch (IOException ex) { 168 Log.e(TAG, "Zygote: error closing sockets", ex); 169 } catch (ErrnoException ex) { 170 Log.e(TAG, "Zygote: error closing descriptor", ex); 171 } 172 173 sServerSocket = null; 174 } 175 176 /** 177 * Return the server socket's underlying file descriptor, so that 178 * ZygoteConnection can pass it to the native code for proper 179 * closure after a child process is forked off. 180 */ 181 getServerSocketFileDescriptor()182 static FileDescriptor getServerSocketFileDescriptor() { 183 return sServerSocket.getFileDescriptor(); 184 } 185 186 private static final int UNPRIVILEGED_UID = 9999; 187 private static final int UNPRIVILEGED_GID = 9999; 188 189 private static final int ROOT_UID = 0; 190 private static final int ROOT_GID = 0; 191 preload()192 static void preload() { 193 Log.d(TAG, "begin preload"); 194 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "BeginIcuCachePinning"); 195 beginIcuCachePinning(); 196 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 197 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses"); 198 preloadClasses(); 199 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 200 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources"); 201 preloadResources(); 202 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 203 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL"); 204 preloadOpenGL(); 205 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 206 preloadSharedLibraries(); 207 preloadTextResources(); 208 // Ask the WebViewFactory to do any initialization that must run in the zygote process, 209 // for memory sharing purposes. 210 WebViewFactory.prepareWebViewInZygote(); 211 endIcuCachePinning(); 212 warmUpJcaProviders(); 213 Log.d(TAG, "end preload"); 214 } 215 beginIcuCachePinning()216 private static void beginIcuCachePinning() { 217 // Pin ICU data in memory from this point that would normally be held by soft references. 218 // Without this, any references created immediately below or during class preloading 219 // would be collected when the Zygote GC runs in gcAndFinalize(). 220 Log.i(TAG, "Installing ICU cache reference pinning..."); 221 222 CacheValue.setStrength(CacheValue.Strength.STRONG); 223 224 Log.i(TAG, "Preloading ICU data..."); 225 // Explicitly exercise code to cache data apps are likely to need. 226 ULocale[] localesToPin = { ULocale.ROOT, ULocale.US, ULocale.getDefault() }; 227 for (ULocale uLocale : localesToPin) { 228 new DecimalFormatSymbols(uLocale); 229 } 230 } 231 endIcuCachePinning()232 private static void endIcuCachePinning() { 233 // All cache references created by ICU from this point will be soft. 234 CacheValue.setStrength(CacheValue.Strength.SOFT); 235 236 Log.i(TAG, "Uninstalled ICU cache reference pinning..."); 237 } 238 preloadSharedLibraries()239 private static void preloadSharedLibraries() { 240 Log.i(TAG, "Preloading shared libraries..."); 241 System.loadLibrary("android"); 242 System.loadLibrary("compiler_rt"); 243 System.loadLibrary("jnigraphics"); 244 } 245 preloadOpenGL()246 private static void preloadOpenGL() { 247 String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER); 248 if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false) || 249 driverPackageName == null || driverPackageName.isEmpty()) { 250 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 251 } 252 } 253 preloadTextResources()254 private static void preloadTextResources() { 255 Hyphenator.init(); 256 TextView.preloadFontCache(); 257 } 258 259 /** 260 * Register AndroidKeyStoreProvider and warm up the providers that are already registered. 261 * 262 * By doing it here we avoid that each app does it when requesting a service from the 263 * provider for the first time. 264 */ warmUpJcaProviders()265 private static void warmUpJcaProviders() { 266 long startTime = SystemClock.uptimeMillis(); 267 Trace.traceBegin( 268 Trace.TRACE_TAG_DALVIK, "Starting installation of AndroidKeyStoreProvider"); 269 // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert 270 // preferred providers. Note this is not done via security.properties as the JCA providers 271 // are not on the classpath in the case of, for example, raw dalvikvm runtimes. 272 AndroidKeyStoreProvider.install(); 273 Log.i(TAG, "Installed AndroidKeyStoreProvider in " 274 + (SystemClock.uptimeMillis() - startTime) + "ms."); 275 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 276 277 startTime = SystemClock.uptimeMillis(); 278 Trace.traceBegin( 279 Trace.TRACE_TAG_DALVIK, "Starting warm up of JCA providers"); 280 for (Provider p : Security.getProviders()) { 281 p.warmUpServiceProvision(); 282 } 283 Log.i(TAG, "Warmed up JCA providers in " 284 + (SystemClock.uptimeMillis() - startTime) + "ms."); 285 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 286 } 287 288 /** 289 * Performs Zygote process initialization. Loads and initializes 290 * commonly used classes. 291 * 292 * Most classes only cause a few hundred bytes to be allocated, but 293 * a few will allocate a dozen Kbytes (in one case, 500+K). 294 */ preloadClasses()295 private static void preloadClasses() { 296 final VMRuntime runtime = VMRuntime.getRuntime(); 297 298 InputStream is; 299 try { 300 is = new FileInputStream(PRELOADED_CLASSES); 301 } catch (FileNotFoundException e) { 302 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + "."); 303 return; 304 } 305 306 Log.i(TAG, "Preloading classes..."); 307 long startTime = SystemClock.uptimeMillis(); 308 309 // Drop root perms while running static initializers. 310 final int reuid = Os.getuid(); 311 final int regid = Os.getgid(); 312 313 // We need to drop root perms only if we're already root. In the case of "wrapped" 314 // processes (see WrapperInit), this function is called from an unprivileged uid 315 // and gid. 316 boolean droppedPriviliges = false; 317 if (reuid == ROOT_UID && regid == ROOT_GID) { 318 try { 319 Os.setregid(ROOT_GID, UNPRIVILEGED_GID); 320 Os.setreuid(ROOT_UID, UNPRIVILEGED_UID); 321 } catch (ErrnoException ex) { 322 throw new RuntimeException("Failed to drop root", ex); 323 } 324 325 droppedPriviliges = true; 326 } 327 328 // Alter the target heap utilization. With explicit GCs this 329 // is not likely to have any effect. 330 float defaultUtilization = runtime.getTargetHeapUtilization(); 331 runtime.setTargetHeapUtilization(0.8f); 332 333 try { 334 BufferedReader br 335 = new BufferedReader(new InputStreamReader(is), 256); 336 337 int count = 0; 338 String line; 339 while ((line = br.readLine()) != null) { 340 // Skip comments and blank lines. 341 line = line.trim(); 342 if (line.startsWith("#") || line.equals("")) { 343 continue; 344 } 345 346 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClass " + line); 347 try { 348 if (false) { 349 Log.v(TAG, "Preloading " + line + "..."); 350 } 351 // Load and explicitly initialize the given class. Use 352 // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups 353 // (to derive the caller's class-loader). Use true to force initialization, and 354 // null for the boot classpath class-loader (could as well cache the 355 // class-loader of this class in a variable). 356 Class.forName(line, true, null); 357 count++; 358 } catch (ClassNotFoundException e) { 359 Log.w(TAG, "Class not found for preloading: " + line); 360 } catch (UnsatisfiedLinkError e) { 361 Log.w(TAG, "Problem preloading " + line + ": " + e); 362 } catch (Throwable t) { 363 Log.e(TAG, "Error preloading " + line + ".", t); 364 if (t instanceof Error) { 365 throw (Error) t; 366 } 367 if (t instanceof RuntimeException) { 368 throw (RuntimeException) t; 369 } 370 throw new RuntimeException(t); 371 } 372 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 373 } 374 375 Log.i(TAG, "...preloaded " + count + " classes in " 376 + (SystemClock.uptimeMillis()-startTime) + "ms."); 377 } catch (IOException e) { 378 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e); 379 } finally { 380 IoUtils.closeQuietly(is); 381 // Restore default. 382 runtime.setTargetHeapUtilization(defaultUtilization); 383 384 // Fill in dex caches with classes, fields, and methods brought in by preloading. 385 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches"); 386 runtime.preloadDexCaches(); 387 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 388 389 // Bring back root. We'll need it later if we're in the zygote. 390 if (droppedPriviliges) { 391 try { 392 Os.setreuid(ROOT_UID, ROOT_UID); 393 Os.setregid(ROOT_GID, ROOT_GID); 394 } catch (ErrnoException ex) { 395 throw new RuntimeException("Failed to restore root", ex); 396 } 397 } 398 } 399 } 400 401 /** 402 * Load in commonly used resources, so they can be shared across 403 * processes. 404 * 405 * These tend to be a few Kbytes, but are frequently in the 20-40K 406 * range, and occasionally even larger. 407 */ preloadResources()408 private static void preloadResources() { 409 final VMRuntime runtime = VMRuntime.getRuntime(); 410 411 try { 412 mResources = Resources.getSystem(); 413 mResources.startPreloading(); 414 if (PRELOAD_RESOURCES) { 415 Log.i(TAG, "Preloading resources..."); 416 417 long startTime = SystemClock.uptimeMillis(); 418 TypedArray ar = mResources.obtainTypedArray( 419 com.android.internal.R.array.preloaded_drawables); 420 int N = preloadDrawables(ar); 421 ar.recycle(); 422 Log.i(TAG, "...preloaded " + N + " resources in " 423 + (SystemClock.uptimeMillis()-startTime) + "ms."); 424 425 startTime = SystemClock.uptimeMillis(); 426 ar = mResources.obtainTypedArray( 427 com.android.internal.R.array.preloaded_color_state_lists); 428 N = preloadColorStateLists(ar); 429 ar.recycle(); 430 Log.i(TAG, "...preloaded " + N + " resources in " 431 + (SystemClock.uptimeMillis()-startTime) + "ms."); 432 433 if (mResources.getBoolean( 434 com.android.internal.R.bool.config_freeformWindowManagement)) { 435 startTime = SystemClock.uptimeMillis(); 436 ar = mResources.obtainTypedArray( 437 com.android.internal.R.array.preloaded_freeform_multi_window_drawables); 438 N = preloadDrawables(ar); 439 ar.recycle(); 440 Log.i(TAG, "...preloaded " + N + " resource in " 441 + (SystemClock.uptimeMillis() - startTime) + "ms."); 442 } 443 } 444 mResources.finishPreloading(); 445 } catch (RuntimeException e) { 446 Log.w(TAG, "Failure preloading resources", e); 447 } 448 } 449 preloadColorStateLists(TypedArray ar)450 private static int preloadColorStateLists(TypedArray ar) { 451 int N = ar.length(); 452 for (int i=0; i<N; i++) { 453 int id = ar.getResourceId(i, 0); 454 if (false) { 455 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id)); 456 } 457 if (id != 0) { 458 if (mResources.getColorStateList(id, null) == null) { 459 throw new IllegalArgumentException( 460 "Unable to find preloaded color resource #0x" 461 + Integer.toHexString(id) 462 + " (" + ar.getString(i) + ")"); 463 } 464 } 465 } 466 return N; 467 } 468 469 preloadDrawables(TypedArray ar)470 private static int preloadDrawables(TypedArray ar) { 471 int N = ar.length(); 472 for (int i=0; i<N; i++) { 473 int id = ar.getResourceId(i, 0); 474 if (false) { 475 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id)); 476 } 477 if (id != 0) { 478 if (mResources.getDrawable(id, null) == null) { 479 throw new IllegalArgumentException( 480 "Unable to find preloaded drawable resource #0x" 481 + Integer.toHexString(id) 482 + " (" + ar.getString(i) + ")"); 483 } 484 } 485 } 486 return N; 487 } 488 489 /** 490 * Runs several special GCs to try to clean up a few generations of 491 * softly- and final-reachable objects, along with any other garbage. 492 * This is only useful just before a fork(). 493 */ gcAndFinalize()494 /*package*/ static void gcAndFinalize() { 495 final VMRuntime runtime = VMRuntime.getRuntime(); 496 497 /* runFinalizationSync() lets finalizers be called in Zygote, 498 * which doesn't have a HeapWorker thread. 499 */ 500 System.gc(); 501 runtime.runFinalizationSync(); 502 System.gc(); 503 } 504 505 /** 506 * Finish remaining work for the newly forked system server process. 507 */ handleSystemServerProcess( ZygoteConnection.Arguments parsedArgs)508 private static void handleSystemServerProcess( 509 ZygoteConnection.Arguments parsedArgs) 510 throws ZygoteInit.MethodAndArgsCaller { 511 512 closeServerSocket(); 513 514 // set umask to 0077 so new files and directories will default to owner-only permissions. 515 Os.umask(S_IRWXG | S_IRWXO); 516 517 if (parsedArgs.niceName != null) { 518 Process.setArgV0(parsedArgs.niceName); 519 } 520 521 final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH"); 522 if (systemServerClasspath != null) { 523 performSystemServerDexOpt(systemServerClasspath); 524 } 525 526 if (parsedArgs.invokeWith != null) { 527 String[] args = parsedArgs.remainingArgs; 528 // If we have a non-null system server class path, we'll have to duplicate the 529 // existing arguments and append the classpath to it. ART will handle the classpath 530 // correctly when we exec a new process. 531 if (systemServerClasspath != null) { 532 String[] amendedArgs = new String[args.length + 2]; 533 amendedArgs[0] = "-cp"; 534 amendedArgs[1] = systemServerClasspath; 535 System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length); 536 } 537 538 WrapperInit.execApplication(parsedArgs.invokeWith, 539 parsedArgs.niceName, parsedArgs.targetSdkVersion, 540 VMRuntime.getCurrentInstructionSet(), null, args); 541 } else { 542 ClassLoader cl = null; 543 if (systemServerClasspath != null) { 544 cl = createSystemServerClassLoader(systemServerClasspath, 545 parsedArgs.targetSdkVersion); 546 547 Thread.currentThread().setContextClassLoader(cl); 548 } 549 550 /* 551 * Pass the remaining arguments to SystemServer. 552 */ 553 RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl); 554 } 555 556 /* should never reach here */ 557 } 558 559 /** 560 * Creates a PathClassLoader for the system server. It also creates 561 * a shared namespace associated with the classloader to let it access 562 * platform-private native libraries. 563 */ createSystemServerClassLoader(String systemServerClasspath, int targetSdkVersion)564 private static PathClassLoader createSystemServerClassLoader(String systemServerClasspath, 565 int targetSdkVersion) { 566 String librarySearchPath = System.getProperty("java.library.path"); 567 568 return PathClassLoaderFactory.createClassLoader(systemServerClasspath, 569 librarySearchPath, 570 null /* libraryPermittedPath */, 571 ClassLoader.getSystemClassLoader(), 572 targetSdkVersion, 573 true /* isNamespaceShared */); 574 } 575 576 /** 577 * Performs dex-opt on the elements of {@code classPath}, if needed. We 578 * choose the instruction set of the current runtime. 579 */ performSystemServerDexOpt(String classPath)580 private static void performSystemServerDexOpt(String classPath) { 581 final String[] classPathElements = classPath.split(":"); 582 final InstallerConnection installer = new InstallerConnection(); 583 installer.waitForConnection(); 584 final String instructionSet = VMRuntime.getRuntime().vmInstructionSet(); 585 586 try { 587 String sharedLibraries = ""; 588 for (String classPathElement : classPathElements) { 589 // System server is fully AOTed and never profiled 590 // for profile guided compilation. 591 // TODO: Make this configurable between INTERPRET_ONLY, SPEED, SPACE and EVERYTHING? 592 593 int dexoptNeeded; 594 try { 595 dexoptNeeded = DexFile.getDexOptNeeded( 596 classPathElement, instructionSet, "speed", 597 false /* newProfile */); 598 } catch (FileNotFoundException ignored) { 599 // Do not add to the classpath. 600 Log.w(TAG, "Missing classpath element for system server: " + classPathElement); 601 continue; 602 } catch (IOException e) { 603 // Not fully clear what to do here as we don't know the cause of the 604 // IO exception. Add to the classpath to be conservative, but don't 605 // attempt to compile it. 606 Log.w(TAG, "Error checking classpath element for system server: " 607 + classPathElement, e); 608 dexoptNeeded = DexFile.NO_DEXOPT_NEEDED; 609 } 610 611 if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { 612 try { 613 installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet, 614 dexoptNeeded, 0 /*dexFlags*/, "speed", null /*volumeUuid*/, 615 sharedLibraries); 616 } catch (InstallerException e) { 617 // Ignore (but log), we need this on the classpath for fallback mode. 618 Log.w(TAG, "Failed compiling classpath element for system server: " 619 + classPathElement, e); 620 } 621 } 622 623 if (!sharedLibraries.isEmpty()) { 624 sharedLibraries += ":"; 625 } 626 sharedLibraries += classPathElement; 627 } 628 } finally { 629 installer.disconnect(); 630 } 631 } 632 633 /** 634 * Prepare the arguments and fork for the system server process. 635 */ startSystemServer(String abiList, String socketName)636 private static boolean startSystemServer(String abiList, String socketName) 637 throws MethodAndArgsCaller, RuntimeException { 638 long capabilities = posixCapabilitiesAsBits( 639 OsConstants.CAP_IPC_LOCK, 640 OsConstants.CAP_KILL, 641 OsConstants.CAP_NET_ADMIN, 642 OsConstants.CAP_NET_BIND_SERVICE, 643 OsConstants.CAP_NET_BROADCAST, 644 OsConstants.CAP_NET_RAW, 645 OsConstants.CAP_SYS_MODULE, 646 OsConstants.CAP_SYS_NICE, 647 OsConstants.CAP_SYS_PTRACE, 648 OsConstants.CAP_SYS_TIME, 649 OsConstants.CAP_SYS_TTY_CONFIG 650 ); 651 /* Containers run without this capability, so avoid setting it in that case */ 652 if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) { 653 capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND); 654 } 655 /* Hardcoded command line to start the system server */ 656 String args[] = { 657 "--setuid=1000", 658 "--setgid=1000", 659 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010", 660 "--capabilities=" + capabilities + "," + capabilities, 661 "--nice-name=system_server", 662 "--runtime-args", 663 "com.android.server.SystemServer", 664 }; 665 ZygoteConnection.Arguments parsedArgs = null; 666 667 int pid; 668 669 try { 670 parsedArgs = new ZygoteConnection.Arguments(args); 671 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); 672 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); 673 674 /* Request to fork the system server process */ 675 pid = Zygote.forkSystemServer( 676 parsedArgs.uid, parsedArgs.gid, 677 parsedArgs.gids, 678 parsedArgs.debugFlags, 679 null, 680 parsedArgs.permittedCapabilities, 681 parsedArgs.effectiveCapabilities); 682 } catch (IllegalArgumentException ex) { 683 throw new RuntimeException(ex); 684 } 685 686 /* For child process */ 687 if (pid == 0) { 688 if (hasSecondZygote(abiList)) { 689 waitForSecondaryZygote(socketName); 690 } 691 692 handleSystemServerProcess(parsedArgs); 693 } 694 695 return true; 696 } 697 698 /** 699 * Gets the bit array representation of the provided list of POSIX capabilities. 700 */ posixCapabilitiesAsBits(int... capabilities)701 private static long posixCapabilitiesAsBits(int... capabilities) { 702 long result = 0; 703 for (int capability : capabilities) { 704 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) { 705 throw new IllegalArgumentException(String.valueOf(capability)); 706 } 707 result |= (1L << capability); 708 } 709 return result; 710 } 711 main(String argv[])712 public static void main(String argv[]) { 713 // Mark zygote start. This ensures that thread creation will throw 714 // an error. 715 ZygoteHooks.startZygoteNoThreadCreation(); 716 717 try { 718 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit"); 719 RuntimeInit.enableDdms(); 720 // Start profiling the zygote initialization. 721 SamplingProfilerIntegration.start(); 722 723 boolean startSystemServer = false; 724 String socketName = "zygote"; 725 String abiList = null; 726 for (int i = 1; i < argv.length; i++) { 727 if ("start-system-server".equals(argv[i])) { 728 startSystemServer = true; 729 } else if (argv[i].startsWith(ABI_LIST_ARG)) { 730 abiList = argv[i].substring(ABI_LIST_ARG.length()); 731 } else if (argv[i].startsWith(SOCKET_NAME_ARG)) { 732 socketName = argv[i].substring(SOCKET_NAME_ARG.length()); 733 } else { 734 throw new RuntimeException("Unknown command line argument: " + argv[i]); 735 } 736 } 737 738 if (abiList == null) { 739 throw new RuntimeException("No ABI list supplied."); 740 } 741 742 registerZygoteSocket(socketName); 743 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload"); 744 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, 745 SystemClock.uptimeMillis()); 746 preload(); 747 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, 748 SystemClock.uptimeMillis()); 749 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 750 751 // Finish profiling the zygote initialization. 752 SamplingProfilerIntegration.writeZygoteSnapshot(); 753 754 // Do an initial gc to clean up after startup 755 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC"); 756 gcAndFinalize(); 757 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 758 759 Trace.traceEnd(Trace.TRACE_TAG_DALVIK); 760 761 // Disable tracing so that forked processes do not inherit stale tracing tags from 762 // Zygote. 763 Trace.setTracingEnabled(false); 764 765 // Zygote process unmounts root storage spaces. 766 Zygote.nativeUnmountStorageOnInit(); 767 768 ZygoteHooks.stopZygoteNoThreadCreation(); 769 770 if (startSystemServer) { 771 startSystemServer(abiList, socketName); 772 } 773 774 Log.i(TAG, "Accepting command socket connections"); 775 runSelectLoop(abiList); 776 777 closeServerSocket(); 778 } catch (MethodAndArgsCaller caller) { 779 caller.run(); 780 } catch (Throwable ex) { 781 Log.e(TAG, "Zygote died with exception", ex); 782 closeServerSocket(); 783 throw ex; 784 } 785 } 786 787 /** 788 * Return {@code true} if this device configuration has another zygote. 789 * 790 * We determine this by comparing the device ABI list with this zygotes 791 * list. If this zygote supports all ABIs this device supports, there won't 792 * be another zygote. 793 */ hasSecondZygote(String abiList)794 private static boolean hasSecondZygote(String abiList) { 795 return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList); 796 } 797 waitForSecondaryZygote(String socketName)798 private static void waitForSecondaryZygote(String socketName) { 799 String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ? 800 Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET; 801 while (true) { 802 try { 803 final Process.ZygoteState zs = Process.ZygoteState.connect(otherZygoteName); 804 zs.close(); 805 break; 806 } catch (IOException ioe) { 807 Log.w(TAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage()); 808 } 809 810 try { 811 Thread.sleep(1000); 812 } catch (InterruptedException ie) { 813 } 814 } 815 } 816 817 /** 818 * Runs the zygote process's select loop. Accepts new connections as 819 * they happen, and reads commands from connections one spawn-request's 820 * worth at a time. 821 * 822 * @throws MethodAndArgsCaller in a child process when a main() should 823 * be executed. 824 */ runSelectLoop(String abiList)825 private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { 826 ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); 827 ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); 828 829 fds.add(sServerSocket.getFileDescriptor()); 830 peers.add(null); 831 832 while (true) { 833 StructPollfd[] pollFds = new StructPollfd[fds.size()]; 834 for (int i = 0; i < pollFds.length; ++i) { 835 pollFds[i] = new StructPollfd(); 836 pollFds[i].fd = fds.get(i); 837 pollFds[i].events = (short) POLLIN; 838 } 839 try { 840 Os.poll(pollFds, -1); 841 } catch (ErrnoException ex) { 842 throw new RuntimeException("poll failed", ex); 843 } 844 for (int i = pollFds.length - 1; i >= 0; --i) { 845 if ((pollFds[i].revents & POLLIN) == 0) { 846 continue; 847 } 848 if (i == 0) { 849 ZygoteConnection newPeer = acceptCommandPeer(abiList); 850 peers.add(newPeer); 851 fds.add(newPeer.getFileDesciptor()); 852 } else { 853 boolean done = peers.get(i).runOnce(); 854 if (done) { 855 peers.remove(i); 856 fds.remove(i); 857 } 858 } 859 } 860 } 861 } 862 863 /** 864 * Class not instantiable. 865 */ ZygoteInit()866 private ZygoteInit() { 867 } 868 869 /** 870 * Helper exception class which holds a method and arguments and 871 * can call them. This is used as part of a trampoline to get rid of 872 * the initial process setup stack frames. 873 */ 874 public static class MethodAndArgsCaller extends Exception 875 implements Runnable { 876 /** method to call */ 877 private final Method mMethod; 878 879 /** argument array */ 880 private final String[] mArgs; 881 MethodAndArgsCaller(Method method, String[] args)882 public MethodAndArgsCaller(Method method, String[] args) { 883 mMethod = method; 884 mArgs = args; 885 } 886 run()887 public void run() { 888 try { 889 mMethod.invoke(null, new Object[] { mArgs }); 890 } catch (IllegalAccessException ex) { 891 throw new RuntimeException(ex); 892 } catch (InvocationTargetException ex) { 893 Throwable cause = ex.getCause(); 894 if (cause instanceof RuntimeException) { 895 throw (RuntimeException) cause; 896 } else if (cause instanceof Error) { 897 throw (Error) cause; 898 } 899 throw new RuntimeException(ex); 900 } 901 } 902 } 903 } 904