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