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