blob: 2be6212b9f1ee77e97a01b62f0ee4eb0f848c530 [file] [log] [blame]
Justin Klaassen10d07c82017-09-15 17:58:39 -04001/*
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
17package com.android.internal.os;
18
19import static android.system.OsConstants.S_IRWXG;
20import static android.system.OsConstants.S_IRWXO;
21
22import android.content.res.Resources;
23import android.content.res.TypedArray;
24import android.icu.impl.CacheValue;
25import android.icu.text.DecimalFormatSymbols;
26import android.icu.util.ULocale;
27import android.opengl.EGL14;
28import android.os.Build;
29import android.os.IInstalld;
30import android.os.Environment;
31import android.os.Process;
32import android.os.RemoteException;
33import android.os.Seccomp;
34import android.os.ServiceManager;
35import android.os.ServiceSpecificException;
36import android.os.SystemClock;
37import android.os.SystemProperties;
38import android.os.Trace;
39import android.os.ZygoteProcess;
40import android.os.storage.StorageManager;
41import android.security.keystore.AndroidKeyStoreProvider;
42import android.system.ErrnoException;
43import android.system.Os;
44import android.system.OsConstants;
45import android.system.StructCapUserData;
46import android.system.StructCapUserHeader;
47import android.text.Hyphenator;
48import android.util.TimingsTraceLog;
49import android.util.EventLog;
50import android.util.Log;
51import android.util.Slog;
52import android.webkit.WebViewFactory;
53import android.widget.TextView;
54
55import com.android.internal.logging.MetricsLogger;
56
57import com.android.internal.util.Preconditions;
58import dalvik.system.DexFile;
59import dalvik.system.VMRuntime;
60import dalvik.system.ZygoteHooks;
61
62import libcore.io.IoUtils;
63
64import java.io.BufferedReader;
65import java.io.File;
66import java.io.FileInputStream;
67import java.io.FileNotFoundException;
68import java.io.IOException;
69import java.io.InputStream;
70import java.io.InputStreamReader;
71import java.security.Security;
72import java.security.Provider;
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 */
86public 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
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
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
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
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
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
189 native private static void nativePreloadAppProcessHALs();
190
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
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 */
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 */
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 */
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
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
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 */
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 */
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 File profileDir = Environment.getDataProfilesDePackageDirectory(
471 Process.SYSTEM_UID, "system_server");
472 File profile = new File(profileDir, "primary.prof");
473 profile.getParentFile().mkdirs();
474 profile.createNewFile();
475 String[] codePaths = systemServerClasspath.split(":");
476 VMRuntime.registerAppInfo(profile.getPath(), codePaths);
477 } catch (Exception e) {
478 Log.wtf(TAG, "Failed to set up system server profile", e);
479 }
480 }
481 }
482
483 if (parsedArgs.invokeWith != null) {
484 String[] args = parsedArgs.remainingArgs;
485 // If we have a non-null system server class path, we'll have to duplicate the
486 // existing arguments and append the classpath to it. ART will handle the classpath
487 // correctly when we exec a new process.
488 if (systemServerClasspath != null) {
489 String[] amendedArgs = new String[args.length + 2];
490 amendedArgs[0] = "-cp";
491 amendedArgs[1] = systemServerClasspath;
492 System.arraycopy(args, 0, amendedArgs, 2, args.length);
493 args = amendedArgs;
494 }
495
496 WrapperInit.execApplication(parsedArgs.invokeWith,
497 parsedArgs.niceName, parsedArgs.targetSdkVersion,
498 VMRuntime.getCurrentInstructionSet(), null, args);
499
500 throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
501 } else {
502 ClassLoader cl = null;
503 if (systemServerClasspath != null) {
504 cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
505
506 Thread.currentThread().setContextClassLoader(cl);
507 }
508
509 /*
510 * Pass the remaining arguments to SystemServer.
511 */
512 return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
513 }
514
515 /* should never reach here */
516 }
517
518 /**
519 * Creates a PathClassLoader for the given class path that is associated with a shared
520 * namespace, i.e., this classloader can access platform-private native libraries. The
521 * classloader will use java.library.path as the native library path.
522 */
523 static ClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
524 String libraryPath = System.getProperty("java.library.path");
525
526 return ClassLoaderFactory.createClassLoader(classPath, libraryPath, libraryPath,
527 ClassLoader.getSystemClassLoader(), targetSdkVersion, true /* isNamespaceShared */,
528 null /* classLoaderName */);
529 }
530
531 /**
532 * Performs dex-opt on the elements of {@code classPath}, if needed. We
533 * choose the instruction set of the current runtime.
534 */
535 private static void performSystemServerDexOpt(String classPath) {
536 final String[] classPathElements = classPath.split(":");
537 final IInstalld installd = IInstalld.Stub
538 .asInterface(ServiceManager.getService("installd"));
539 final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
540
541 String classPathForElement = "";
542 for (String classPathElement : classPathElements) {
543 // System server is fully AOTed and never profiled
544 // for profile guided compilation.
545 String systemServerFilter = SystemProperties.get(
546 "dalvik.vm.systemservercompilerfilter", "speed");
547
548 int dexoptNeeded;
549 try {
550 dexoptNeeded = DexFile.getDexOptNeeded(
551 classPathElement, instructionSet, systemServerFilter,
Justin Klaassen47ed54e2017-10-24 19:50:40 -0400552 null /* classLoaderContext */, false /* newProfile */, false /* downgrade */);
Justin Klaassen10d07c82017-09-15 17:58:39 -0400553 } catch (FileNotFoundException ignored) {
554 // Do not add to the classpath.
555 Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
556 continue;
557 } catch (IOException e) {
558 // Not fully clear what to do here as we don't know the cause of the
559 // IO exception. Add to the classpath to be conservative, but don't
560 // attempt to compile it.
561 Log.w(TAG, "Error checking classpath element for system server: "
562 + classPathElement, e);
563 dexoptNeeded = DexFile.NO_DEXOPT_NEEDED;
564 }
565
566 if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
567 final String packageName = "*";
568 final String outputPath = null;
569 final int dexFlags = 0;
570 final String compilerFilter = systemServerFilter;
571 final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
572 final String seInfo = null;
573 final String classLoaderContext =
574 getSystemServerClassLoaderContext(classPathForElement);
575 try {
576 installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
577 instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
578 uuid, classLoaderContext, seInfo, false /* downgrade */);
579 } catch (RemoteException | ServiceSpecificException e) {
580 // Ignore (but log), we need this on the classpath for fallback mode.
581 Log.w(TAG, "Failed compiling classpath element for system server: "
582 + classPathElement, e);
583 }
584 }
585
586 classPathForElement = encodeSystemServerClassPath(
587 classPathForElement, classPathElement);
588 }
589 }
590
591 /**
592 * Encodes the system server class loader context in a format that is accepted by dexopt.
593 * This assumes the system server is always loaded with a {@link dalvik.system.PathClassLoader}.
594 *
595 * Note that ideally we would use the {@code DexoptUtils} to compute this. However we have no
596 * dependency here on the server so we hard code the logic again.
597 */
598 private static String getSystemServerClassLoaderContext(String classPath) {
599 return classPath == null ? "PCL[]" : "PCL[" + classPath + "]";
600 }
601
602 /**
603 * Encodes the class path in a format accepted by dexopt.
604 * @param classPath the old class path (may be empty).
605 * @param newElement the new class path elements
606 * @return the class path encoding resulted from appending {@code newElement} to
607 * {@code classPath}.
608 */
609 private static String encodeSystemServerClassPath(String classPath, String newElement) {
610 return (classPath == null || classPath.isEmpty())
611 ? newElement
612 : classPath + ":" + newElement;
613 }
614
615 /**
616 * Prepare the arguments and forks for the system server process.
617 *
618 * Returns an {@code Runnable} that provides an entrypoint into system_server code in the
619 * child process, and {@code null} in the parent.
620 */
621 private static Runnable forkSystemServer(String abiList, String socketName,
622 ZygoteServer zygoteServer) {
623 long capabilities = posixCapabilitiesAsBits(
624 OsConstants.CAP_IPC_LOCK,
625 OsConstants.CAP_KILL,
626 OsConstants.CAP_NET_ADMIN,
627 OsConstants.CAP_NET_BIND_SERVICE,
628 OsConstants.CAP_NET_BROADCAST,
629 OsConstants.CAP_NET_RAW,
630 OsConstants.CAP_SYS_MODULE,
631 OsConstants.CAP_SYS_NICE,
632 OsConstants.CAP_SYS_PTRACE,
633 OsConstants.CAP_SYS_TIME,
634 OsConstants.CAP_SYS_TTY_CONFIG,
635 OsConstants.CAP_WAKE_ALARM,
636 OsConstants.CAP_BLOCK_SUSPEND
637 );
638 /* Containers run without some capabilities, so drop any caps that are not available. */
639 StructCapUserHeader header = new StructCapUserHeader(
640 OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
641 StructCapUserData[] data;
642 try {
643 data = Os.capget(header);
644 } catch (ErrnoException ex) {
645 throw new RuntimeException("Failed to capget()", ex);
646 }
647 capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
648
649 /* Hardcoded command line to start the system server */
650 String args[] = {
651 "--setuid=1000",
652 "--setgid=1000",
653 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
654 "--capabilities=" + capabilities + "," + capabilities,
655 "--nice-name=system_server",
656 "--runtime-args",
657 "com.android.server.SystemServer",
658 };
659 ZygoteConnection.Arguments parsedArgs = null;
660
661 int pid;
662
663 try {
664 parsedArgs = new ZygoteConnection.Arguments(args);
665 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
666 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
667
668 /* Request to fork the system server process */
669 pid = Zygote.forkSystemServer(
670 parsedArgs.uid, parsedArgs.gid,
671 parsedArgs.gids,
Justin Klaassenbc81c7a2017-09-18 17:38:50 -0400672 parsedArgs.runtimeFlags,
Justin Klaassen10d07c82017-09-15 17:58:39 -0400673 null,
674 parsedArgs.permittedCapabilities,
675 parsedArgs.effectiveCapabilities);
676 } catch (IllegalArgumentException ex) {
677 throw new RuntimeException(ex);
678 }
679
680 /* For child process */
681 if (pid == 0) {
682 if (hasSecondZygote(abiList)) {
683 waitForSecondaryZygote(socketName);
684 }
685
686 zygoteServer.closeServerSocket();
687 return handleSystemServerProcess(parsedArgs);
688 }
689
690 return null;
691 }
692
693 /**
694 * Gets the bit array representation of the provided list of POSIX capabilities.
695 */
696 private static long posixCapabilitiesAsBits(int... capabilities) {
697 long result = 0;
698 for (int capability : capabilities) {
699 if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
700 throw new IllegalArgumentException(String.valueOf(capability));
701 }
702 result |= (1L << capability);
703 }
704 return result;
705 }
706
707 public static void main(String argv[]) {
708 ZygoteServer zygoteServer = new ZygoteServer();
709
710 // Mark zygote start. This ensures that thread creation will throw
711 // an error.
712 ZygoteHooks.startZygoteNoThreadCreation();
713
714 // Zygote goes into its own process group.
715 try {
716 Os.setpgid(0, 0);
717 } catch (ErrnoException ex) {
718 throw new RuntimeException("Failed to setpgid(0,0)", ex);
719 }
720
721 final Runnable caller;
722 try {
723 // Report Zygote start time to tron unless it is a runtime restart
724 if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
725 MetricsLogger.histogram(null, "boot_zygote_init",
726 (int) SystemClock.elapsedRealtime());
727 }
728
729 String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
730 TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
731 Trace.TRACE_TAG_DALVIK);
732 bootTimingsTraceLog.traceBegin("ZygoteInit");
733 RuntimeInit.enableDdms();
734
735 boolean startSystemServer = false;
736 String socketName = "zygote";
737 String abiList = null;
738 boolean enableLazyPreload = false;
739 for (int i = 1; i < argv.length; i++) {
740 if ("start-system-server".equals(argv[i])) {
741 startSystemServer = true;
742 } else if ("--enable-lazy-preload".equals(argv[i])) {
743 enableLazyPreload = true;
744 } else if (argv[i].startsWith(ABI_LIST_ARG)) {
745 abiList = argv[i].substring(ABI_LIST_ARG.length());
746 } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
747 socketName = argv[i].substring(SOCKET_NAME_ARG.length());
748 } else {
749 throw new RuntimeException("Unknown command line argument: " + argv[i]);
750 }
751 }
752
753 if (abiList == null) {
754 throw new RuntimeException("No ABI list supplied.");
755 }
756
757 zygoteServer.registerServerSocket(socketName);
758 // In some configurations, we avoid preloading resources and classes eagerly.
759 // In such cases, we will preload things prior to our first fork.
760 if (!enableLazyPreload) {
761 bootTimingsTraceLog.traceBegin("ZygotePreload");
762 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
763 SystemClock.uptimeMillis());
764 preload(bootTimingsTraceLog);
765 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
766 SystemClock.uptimeMillis());
767 bootTimingsTraceLog.traceEnd(); // ZygotePreload
768 } else {
769 Zygote.resetNicePriority();
770 }
771
772 // Do an initial gc to clean up after startup
773 bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
774 gcAndFinalize();
775 bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
776
777 bootTimingsTraceLog.traceEnd(); // ZygoteInit
778 // Disable tracing so that forked processes do not inherit stale tracing tags from
779 // Zygote.
780 Trace.setTracingEnabled(false, 0);
781
782 // Zygote process unmounts root storage spaces.
783 Zygote.nativeUnmountStorageOnInit();
784
785 // Set seccomp policy
786 Seccomp.setPolicy();
787
788 ZygoteHooks.stopZygoteNoThreadCreation();
789
790 if (startSystemServer) {
791 Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
792
793 // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
794 // child (system_server) process.
795 if (r != null) {
796 r.run();
797 return;
798 }
799 }
800
801 Log.i(TAG, "Accepting command socket connections");
802
803 // The select loop returns early in the child process after a fork and
804 // loops forever in the zygote.
805 caller = zygoteServer.runSelectLoop(abiList);
806 } catch (Throwable ex) {
807 Log.e(TAG, "System zygote died with exception", ex);
808 throw ex;
809 } finally {
810 zygoteServer.closeServerSocket();
811 }
812
813 // We're in the child process and have exited the select loop. Proceed to execute the
814 // command.
815 if (caller != null) {
816 caller.run();
817 }
818 }
819
820 /**
821 * Return {@code true} if this device configuration has another zygote.
822 *
823 * We determine this by comparing the device ABI list with this zygotes
824 * list. If this zygote supports all ABIs this device supports, there won't
825 * be another zygote.
826 */
827 private static boolean hasSecondZygote(String abiList) {
828 return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
829 }
830
831 private static void waitForSecondaryZygote(String socketName) {
832 String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
833 Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
834 ZygoteProcess.waitForConnectionToZygote(otherZygoteName);
835 }
836
837 static boolean isPreloadComplete() {
838 return sPreloadComplete;
839 }
840
841 /**
842 * Class not instantiable.
843 */
844 private ZygoteInit() {
845 }
846
847 /**
848 * The main function called when started through the zygote process. This
849 * could be unified with main(), if the native code in nativeFinishInit()
850 * were rationalized with Zygote startup.<p>
851 *
852 * Current recognized args:
853 * <ul>
854 * <li> <code> [--] &lt;start class name&gt; &lt;args&gt;
855 * </ul>
856 *
857 * @param targetSdkVersion target SDK version
858 * @param argv arg strings
859 */
860 public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
861 if (RuntimeInit.DEBUG) {
862 Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
863 }
864
865 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
866 RuntimeInit.redirectLogStreams();
867
868 RuntimeInit.commonInit();
869 ZygoteInit.nativeZygoteInit();
870 return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
871 }
872
873 private static final native void nativeZygoteInit();
874}