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