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