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