Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.os;
     18 
     19 import static android.system.OsConstants.S_IRWXG;
     20 import static android.system.OsConstants.S_IRWXO;
     21 
     22 import android.content.res.Resources;
     23 import android.content.res.TypedArray;
     24 import android.icu.impl.CacheValue;
     25 import android.icu.text.DecimalFormatSymbols;
     26 import android.icu.util.ULocale;
     27 import android.net.LocalServerSocket;
     28 import android.opengl.EGL14;
     29 import android.os.Build;
     30 import android.os.IInstalld;
     31 import android.os.Environment;
     32 import android.os.Process;
     33 import android.os.RemoteException;
     34 import android.os.Seccomp;
     35 import android.os.ServiceManager;
     36 import android.os.ServiceSpecificException;
     37 import android.os.SystemClock;
     38 import android.os.SystemProperties;
     39 import android.os.Trace;
     40 import android.os.ZygoteProcess;
     41 import android.os.storage.StorageManager;
     42 import android.security.keystore.AndroidKeyStoreProvider;
     43 import android.system.ErrnoException;
     44 import android.system.Os;
     45 import android.system.OsConstants;
     46 import android.text.Hyphenator;
     47 import android.util.BootTimingsTraceLog;
     48 import android.util.EventLog;
     49 import android.util.Log;
     50 import android.util.Slog;
     51 import android.webkit.WebViewFactory;
     52 import android.widget.TextView;
     53 
     54 import com.android.internal.logging.MetricsLogger;
     55 
     56 import com.android.internal.util.Preconditions;
     57 import dalvik.system.DexFile;
     58 import dalvik.system.PathClassLoader;
     59 import dalvik.system.VMRuntime;
     60 import dalvik.system.ZygoteHooks;
     61 
     62 import libcore.io.IoUtils;
     63 
     64 import java.io.BufferedReader;
     65 import java.io.File;
     66 import java.io.FileInputStream;
     67 import java.io.FileNotFoundException;
     68 import java.io.IOException;
     69 import java.io.InputStream;
     70 import java.io.InputStreamReader;
     71 import java.security.Security;
     72 import 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  */
     86 public class ZygoteInit {
     87     private static final String TAG = "Zygote";
     88 
     89     private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
     90     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
     91     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