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