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