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.Build;
30import android.os.IInstalld;
31import android.os.Environment;
32import android.os.Process;
33import android.os.RemoteException;
34import android.os.Seccomp;
35import android.os.ServiceManager;
36import android.os.ServiceSpecificException;
37import android.os.SystemClock;
38import android.os.SystemProperties;
39import android.os.Trace;
40import android.os.ZygoteProcess;
41import android.os.storage.StorageManager;
42import android.security.keystore.AndroidKeyStoreProvider;
43import android.system.ErrnoException;
44import android.system.Os;
45import android.system.OsConstants;
46import android.text.Hyphenator;
47import android.util.BootTimingsTraceLog;
48import android.util.EventLog;
49import android.util.Log;
50import android.util.Slog;
51import android.webkit.WebViewFactory;
52import android.widget.TextView;
53
54import com.android.internal.logging.MetricsLogger;
55
56import com.android.internal.util.Preconditions;
57import dalvik.system.DexFile;
58import dalvik.system.PathClassLoader;
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    private static final String PROPERTY_RUNNING_IN_CONTAINER = "ro.boot.container";
92
93    private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
94    private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
95
96    /** when preloading, GC after allocating this many bytes */
97    private static final int PRELOAD_GC_THRESHOLD = 50000;
98
99    private static final String ABI_LIST_ARG = "--abi-list=";
100
101    private static final String SOCKET_NAME_ARG = "--socket-name=";
102
103    /**
104     * Used to pre-load resources.
105     */
106    private static Resources mResources;
107
108    /**
109     * The path of a file that contains classes to preload.
110     */
111    private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
112
113    /** Controls whether we should preload resources during zygote init. */
114    public static final boolean PRELOAD_RESOURCES = true;
115
116    private static final int UNPRIVILEGED_UID = 9999;
117    private static final int UNPRIVILEGED_GID = 9999;
118
119    private static final int ROOT_UID = 0;
120    private static final int ROOT_GID = 0;
121
122    private static boolean sPreloadComplete;
123
124    static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
125        Log.d(TAG, "begin preload");
126        bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
127        beginIcuCachePinning();
128        bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
129        bootTimingsTraceLog.traceBegin("PreloadClasses");
130        preloadClasses();
131        bootTimingsTraceLog.traceEnd(); // PreloadClasses
132        bootTimingsTraceLog.traceBegin("PreloadResources");
133        preloadResources();
134        bootTimingsTraceLog.traceEnd(); // PreloadResources
135        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
136        preloadOpenGL();
137        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
138        preloadSharedLibraries();
139        preloadTextResources();
140        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
141        // for memory sharing purposes.
142        WebViewFactory.prepareWebViewInZygote();
143        endIcuCachePinning();
144        warmUpJcaProviders();
145        Log.d(TAG, "end preload");
146
147        sPreloadComplete = true;
148    }
149
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            // Capturing profiles is only supported for debug or eng builds since selinux normally
464            // prevents it.
465            boolean profileSystemServer = SystemProperties.getBoolean(
466                    "dalvik.vm.profilesystemserver", false);
467            if (profileSystemServer && (Build.IS_USERDEBUG || Build.IS_ENG)) {
468                try {
469                    File profileDir = Environment.getDataProfilesDePackageDirectory(
470                            Process.SYSTEM_UID, "system_server");
471                    File profile = new File(profileDir, "primary.prof");
472                    profile.getParentFile().mkdirs();
473                    profile.createNewFile();
474                    String[] codePaths = systemServerClasspath.split(":");
475                    VMRuntime.registerAppInfo(profile.getPath(), codePaths);
476                } catch (Exception e) {
477                    Log.wtf(TAG, "Failed to set up system server profile", e);
478                }
479            }
480        }
481
482        if (parsedArgs.invokeWith != null) {
483            String[] args = parsedArgs.remainingArgs;
484            // If we have a non-null system server class path, we'll have to duplicate the
485            // existing arguments and append the classpath to it. ART will handle the classpath
486            // correctly when we exec a new process.
487            if (systemServerClasspath != null) {
488                String[] amendedArgs = new String[args.length + 2];
489                amendedArgs[0] = "-cp";
490                amendedArgs[1] = systemServerClasspath;
491                System.arraycopy(args, 0, amendedArgs, 2, args.length);
492                args = amendedArgs;
493            }
494
495            WrapperInit.execApplication(parsedArgs.invokeWith,
496                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
497                    VMRuntime.getCurrentInstructionSet(), null, args);
498        } else {
499            ClassLoader cl = null;
500            if (systemServerClasspath != null) {
501                cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
502
503                Thread.currentThread().setContextClassLoader(cl);
504            }
505
506            /*
507             * Pass the remaining arguments to SystemServer.
508             */
509            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
510        }
511
512        /* should never reach here */
513    }
514
515    /**
516     * Creates a PathClassLoader for the given class path that is associated with a shared
517     * namespace, i.e., this classloader can access platform-private native libraries. The
518     * classloader will use java.library.path as the native library path.
519     */
520    static PathClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
521      String libraryPath = System.getProperty("java.library.path");
522
523      return PathClassLoaderFactory.createClassLoader(classPath,
524                                                      libraryPath,
525                                                      libraryPath,
526                                                      ClassLoader.getSystemClassLoader(),
527                                                      targetSdkVersion,
528                                                      true /* isNamespaceShared */);
529    }
530
531    /**
532     * Performs dex-opt on the elements of {@code classPath}, if needed. We
533     * choose the instruction set of the current runtime.
534     */
535    private static void performSystemServerDexOpt(String classPath) {
536        final String[] classPathElements = classPath.split(":");
537        final IInstalld installd = IInstalld.Stub
538                .asInterface(ServiceManager.getService("installd"));
539        final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
540
541        String sharedLibraries = "";
542        for (String classPathElement : classPathElements) {
543            // System server is fully AOTed and never profiled
544            // for profile guided compilation.
545            // TODO: Make this configurable between INTERPRET_ONLY, SPEED, SPACE and EVERYTHING?
546
547            int dexoptNeeded;
548            try {
549                dexoptNeeded = DexFile.getDexOptNeeded(
550                    classPathElement, instructionSet, "speed",
551                    false /* newProfile */);
552            } catch (FileNotFoundException ignored) {
553                // Do not add to the classpath.
554                Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
555                continue;
556            } catch (IOException e) {
557                // Not fully clear what to do here as we don't know the cause of the
558                // IO exception. Add to the classpath to be conservative, but don't
559                // attempt to compile it.
560                Log.w(TAG, "Error checking classpath element for system server: "
561                        + classPathElement, e);
562                dexoptNeeded = DexFile.NO_DEXOPT_NEEDED;
563            }
564
565            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
566                final String packageName = "*";
567                final String outputPath = null;
568                final int dexFlags = 0;
569                final String compilerFilter = "speed";
570                final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
571                final String seInfo = null;
572                try {
573                    installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
574                            instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
575                            uuid, sharedLibraries, seInfo);
576                } catch (RemoteException | ServiceSpecificException e) {
577                    // Ignore (but log), we need this on the classpath for fallback mode.
578                    Log.w(TAG, "Failed compiling classpath element for system server: "
579                            + classPathElement, e);
580                }
581            }
582
583            if (!sharedLibraries.isEmpty()) {
584                sharedLibraries += ":";
585            }
586            sharedLibraries += classPathElement;
587        }
588    }
589
590    /**
591     * Prepare the arguments and fork for the system server process.
592     */
593    private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
594            throws Zygote.MethodAndArgsCaller, RuntimeException {
595        long capabilities = posixCapabilitiesAsBits(
596            OsConstants.CAP_IPC_LOCK,
597            OsConstants.CAP_KILL,
598            OsConstants.CAP_NET_ADMIN,
599            OsConstants.CAP_NET_BIND_SERVICE,
600            OsConstants.CAP_NET_BROADCAST,
601            OsConstants.CAP_NET_RAW,
602            OsConstants.CAP_SYS_MODULE,
603            OsConstants.CAP_SYS_NICE,
604            OsConstants.CAP_SYS_PTRACE,
605            OsConstants.CAP_SYS_TIME,
606            OsConstants.CAP_SYS_TTY_CONFIG,
607            OsConstants.CAP_WAKE_ALARM
608        );
609        /* Containers run without this capability, so avoid setting it in that case */
610        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
611            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
612        }
613        /* Hardcoded command line to start the system server */
614        String args[] = {
615            "--setuid=1000",
616            "--setgid=1000",
617            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
618            "--capabilities=" + capabilities + "," + capabilities,
619            "--nice-name=system_server",
620            "--runtime-args",
621            "com.android.server.SystemServer",
622        };
623        ZygoteConnection.Arguments parsedArgs = null;
624
625        int pid;
626
627        try {
628            parsedArgs = new ZygoteConnection.Arguments(args);
629            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
630            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
631
632            /* Request to fork the system server process */
633            pid = Zygote.forkSystemServer(
634                    parsedArgs.uid, parsedArgs.gid,
635                    parsedArgs.gids,
636                    parsedArgs.debugFlags,
637                    null,
638                    parsedArgs.permittedCapabilities,
639                    parsedArgs.effectiveCapabilities);
640        } catch (IllegalArgumentException ex) {
641            throw new RuntimeException(ex);
642        }
643
644        /* For child process */
645        if (pid == 0) {
646            if (hasSecondZygote(abiList)) {
647                waitForSecondaryZygote(socketName);
648            }
649
650            zygoteServer.closeServerSocket();
651            handleSystemServerProcess(parsedArgs);
652        }
653
654        return true;
655    }
656
657    /**
658     * Gets the bit array representation of the provided list of POSIX capabilities.
659     */
660    private static long posixCapabilitiesAsBits(int... capabilities) {
661        long result = 0;
662        for (int capability : capabilities) {
663            if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
664                throw new IllegalArgumentException(String.valueOf(capability));
665            }
666            result |= (1L << capability);
667        }
668        return result;
669    }
670
671    public static void main(String argv[]) {
672        ZygoteServer zygoteServer = new ZygoteServer();
673
674        // Mark zygote start. This ensures that thread creation will throw
675        // an error.
676        ZygoteHooks.startZygoteNoThreadCreation();
677
678        // Zygote goes into its own process group.
679        try {
680            Os.setpgid(0, 0);
681        } catch (ErrnoException ex) {
682            throw new RuntimeException("Failed to setpgid(0,0)", ex);
683        }
684
685        try {
686            // Report Zygote start time to tron unless it is a runtime restart
687            if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
688                MetricsLogger.histogram(null, "boot_zygote_init",
689                        (int) SystemClock.elapsedRealtime());
690            }
691
692            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
693            BootTimingsTraceLog bootTimingsTraceLog = new BootTimingsTraceLog(bootTimeTag,
694                    Trace.TRACE_TAG_DALVIK);
695            bootTimingsTraceLog.traceBegin("ZygoteInit");
696            RuntimeInit.enableDdms();
697            // Start profiling the zygote initialization.
698            SamplingProfilerIntegration.start();
699
700            boolean startSystemServer = false;
701            String socketName = "zygote";
702            String abiList = null;
703            boolean enableLazyPreload = false;
704            for (int i = 1; i < argv.length; i++) {
705                if ("start-system-server".equals(argv[i])) {
706                    startSystemServer = true;
707                } else if ("--enable-lazy-preload".equals(argv[i])) {
708                    enableLazyPreload = true;
709                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
710                    abiList = argv[i].substring(ABI_LIST_ARG.length());
711                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
712                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
713                } else {
714                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
715                }
716            }
717
718            if (abiList == null) {
719                throw new RuntimeException("No ABI list supplied.");
720            }
721
722            zygoteServer.registerServerSocket(socketName);
723            // In some configurations, we avoid preloading resources and classes eagerly.
724            // In such cases, we will preload things prior to our first fork.
725            if (!enableLazyPreload) {
726                bootTimingsTraceLog.traceBegin("ZygotePreload");
727                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
728                    SystemClock.uptimeMillis());
729                preload(bootTimingsTraceLog);
730                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
731                    SystemClock.uptimeMillis());
732                bootTimingsTraceLog.traceEnd(); // ZygotePreload
733            } else {
734                Zygote.resetNicePriority();
735            }
736
737            // Finish profiling the zygote initialization.
738            SamplingProfilerIntegration.writeZygoteSnapshot();
739
740            // Do an initial gc to clean up after startup
741            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
742            gcAndFinalize();
743            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
744
745            bootTimingsTraceLog.traceEnd(); // ZygoteInit
746            // Disable tracing so that forked processes do not inherit stale tracing tags from
747            // Zygote.
748            Trace.setTracingEnabled(false);
749
750            // Zygote process unmounts root storage spaces.
751            Zygote.nativeUnmountStorageOnInit();
752
753            // Set seccomp policy
754            Seccomp.setPolicy();
755
756            ZygoteHooks.stopZygoteNoThreadCreation();
757
758            if (startSystemServer) {
759                startSystemServer(abiList, socketName, zygoteServer);
760            }
761
762            Log.i(TAG, "Accepting command socket connections");
763            zygoteServer.runSelectLoop(abiList);
764
765            zygoteServer.closeServerSocket();
766        } catch (Zygote.MethodAndArgsCaller caller) {
767            caller.run();
768        } catch (Throwable ex) {
769            Log.e(TAG, "System zygote died with exception", ex);
770            zygoteServer.closeServerSocket();
771            throw ex;
772        }
773    }
774
775    /**
776     * Return {@code true} if this device configuration has another zygote.
777     *
778     * We determine this by comparing the device ABI list with this zygotes
779     * list. If this zygote supports all ABIs this device supports, there won't
780     * be another zygote.
781     */
782    private static boolean hasSecondZygote(String abiList) {
783        return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
784    }
785
786    private static void waitForSecondaryZygote(String socketName) {
787        String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
788                Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
789        while (true) {
790            try {
791                final ZygoteProcess.ZygoteState zs =
792                        ZygoteProcess.ZygoteState.connect(otherZygoteName);
793                zs.close();
794                break;
795            } catch (IOException ioe) {
796                Log.w(TAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
797            }
798
799            try {
800                Thread.sleep(1000);
801            } catch (InterruptedException ie) {
802            }
803        }
804    }
805
806    static boolean isPreloadComplete() {
807        return sPreloadComplete;
808    }
809
810    /**
811     * Class not instantiable.
812     */
813    private ZygoteInit() {
814    }
815
816    /**
817     * The main function called when started through the zygote process. This
818     * could be unified with main(), if the native code in nativeFinishInit()
819     * were rationalized with Zygote startup.<p>
820     *
821     * Current recognized args:
822     * <ul>
823     *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
824     * </ul>
825     *
826     * @param targetSdkVersion target SDK version
827     * @param argv arg strings
828     */
829    public static final void zygoteInit(int targetSdkVersion, String[] argv,
830            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
831        if (RuntimeInit.DEBUG) {
832            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
833        }
834
835        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
836        RuntimeInit.redirectLogStreams();
837
838        RuntimeInit.commonInit();
839        ZygoteInit.nativeZygoteInit();
840        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
841    }
842
843    private static final native void nativeZygoteInit();
844}
845