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