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.app.ApplicationLoaders;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.content.pm.SharedLibraryInfo;
25 import android.content.res.Resources;
26 import android.content.res.TypedArray;
27 import android.os.Build;
28 import android.os.Environment;
29 import android.os.IInstalld;
30 import android.os.Process;
31 import android.os.RemoteException;
32 import android.os.ServiceManager;
33 import android.os.ServiceSpecificException;
34 import android.os.SystemClock;
35 import android.os.SystemProperties;
36 import android.os.Trace;
37 import android.os.UserHandle;
38 import android.os.ZygoteProcess;
39 import android.os.storage.StorageManager;
40 import android.provider.DeviceConfig;
41 import android.security.keystore.AndroidKeyStoreProvider;
42 import android.system.ErrnoException;
43 import android.system.Os;
44 import android.system.OsConstants;
45 import android.system.StructCapUserData;
46 import android.system.StructCapUserHeader;
47 import android.text.Hyphenator;
48 import android.util.EventLog;
49 import android.util.Log;
50 import android.util.Slog;
51 import android.util.TimingsTraceLog;
52 import android.webkit.WebViewFactory;
53 import android.widget.TextView;
54 
55 import com.android.internal.logging.MetricsLogger;
56 import com.android.internal.util.Preconditions;
57 
58 import dalvik.system.DexFile;
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.Provider;
72 import java.security.Security;
73 
74 /**
75  * Startup class for the zygote process.
76  *
77  * Pre-initializes some classes, and then waits for commands on a UNIX domain socket. Based on these
78  * commands, forks off child processes that inherit the initial state of the VM.
79  *
80  * Please see {@link ZygoteArguments} for documentation on the client protocol.
81  *
82  * @hide
83  */
84 public class ZygoteInit {
85 
86     // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
87     private static final String TAG = "Zygote";
88 
89     private static final String PROPERTY_DISABLE_GRAPHICS_DRIVER_PRELOADING =
90             "ro.zygote.disable_gl_preload";
91 
92     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
93     private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
94 
95     private static final String ABI_LIST_ARG = "--abi-list=";
96 
97     // TODO (chriswailes): Re-name this --zygote-socket-name= and then add a
98     // --usap-socket-name parameter.
99     private static final String SOCKET_NAME_ARG = "--socket-name=";
100 
101     /**
102      * Used to pre-load resources.
103      */
104     @UnsupportedAppUsage
105     private static Resources mResources;
106 
107     /**
108      * The path of a file that contains classes to preload.
109      */
110     private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
111 
112     /**
113      * Controls whether we should preload resources during zygote init.
114      */
115     public static final boolean PRELOAD_RESOURCES = true;
116 
117     private static final int UNPRIVILEGED_UID = 9999;
118     private static final int UNPRIVILEGED_GID = 9999;
119 
120     private static final int ROOT_UID = 0;
121     private static final int ROOT_GID = 0;
122 
123     private static boolean sPreloadComplete;
124 
preload(TimingsTraceLog bootTimingsTraceLog)125     static void preload(TimingsTraceLog bootTimingsTraceLog) {
126         Log.d(TAG, "begin preload");
127         bootTimingsTraceLog.traceBegin("BeginPreload");
128         beginPreload();
129         bootTimingsTraceLog.traceEnd(); // BeginPreload
130         bootTimingsTraceLog.traceBegin("PreloadClasses");
131         preloadClasses();
132         bootTimingsTraceLog.traceEnd(); // PreloadClasses
133         bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
134         cacheNonBootClasspathClassLoaders();
135         bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
136         bootTimingsTraceLog.traceBegin("PreloadResources");
137         preloadResources();
138         bootTimingsTraceLog.traceEnd(); // PreloadResources
139         Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
140         nativePreloadAppProcessHALs();
141         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
142         Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
143         maybePreloadGraphicsDriver();
144         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
145         preloadSharedLibraries();
146         preloadTextResources();
147         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
148         // for memory sharing purposes.
149         WebViewFactory.prepareWebViewInZygote();
150         endPreload();
151         warmUpJcaProviders();
152         Log.d(TAG, "end preload");
153 
154         sPreloadComplete = true;
155     }
156 
lazyPreload()157     public static void lazyPreload() {
158         Preconditions.checkState(!sPreloadComplete);
159         Log.i(TAG, "Lazily preloading resources.");
160 
161         preload(new TimingsTraceLog("ZygoteInitTiming_lazy", Trace.TRACE_TAG_DALVIK));
162     }
163 
beginPreload()164     private static void beginPreload() {
165         Log.i(TAG, "Calling ZygoteHooks.beginPreload()");
166 
167         ZygoteHooks.onBeginPreload();
168     }
169 
endPreload()170     private static void endPreload() {
171         ZygoteHooks.onEndPreload();
172 
173         Log.i(TAG, "Called ZygoteHooks.endPreload()");
174     }
175 
preloadSharedLibraries()176     private static void preloadSharedLibraries() {
177         Log.i(TAG, "Preloading shared libraries...");
178         System.loadLibrary("android");
179         System.loadLibrary("compiler_rt");
180         System.loadLibrary("jnigraphics");
181     }
182 
nativePreloadAppProcessHALs()183     native private static void nativePreloadAppProcessHALs();
184 
185     /**
186      * This call loads the graphics driver by making an OpenGL or Vulkan call.  If the driver is
187      * not currently in memory it will load and initialize it.  The OpenGL call itself is relatively
188      * cheap and pure.  This means that it is a low overhead on the initial call, and is safe and
189      * cheap to call later.  Calls after the initial invocation will effectively be no-ops for the
190      * system.
191      */
nativePreloadGraphicsDriver()192     static native void nativePreloadGraphicsDriver();
193 
maybePreloadGraphicsDriver()194     private static void maybePreloadGraphicsDriver() {
195         if (!SystemProperties.getBoolean(PROPERTY_DISABLE_GRAPHICS_DRIVER_PRELOADING, false)) {
196             nativePreloadGraphicsDriver();
197         }
198     }
199 
preloadTextResources()200     private static void preloadTextResources() {
201         Hyphenator.init();
202         TextView.preloadFontCache();
203     }
204 
205     /**
206      * Register AndroidKeyStoreProvider and warm up the providers that are already registered.
207      *
208      * By doing it here we avoid that each app does it when requesting a service from the provider
209      * for the first time.
210      */
warmUpJcaProviders()211     private static void warmUpJcaProviders() {
212         long startTime = SystemClock.uptimeMillis();
213         Trace.traceBegin(
214                 Trace.TRACE_TAG_DALVIK, "Starting installation of AndroidKeyStoreProvider");
215         // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert
216         // preferred providers. Note this is not done via security.properties as the JCA providers
217         // are not on the classpath in the case of, for example, raw dalvikvm runtimes.
218         AndroidKeyStoreProvider.install();
219         Log.i(TAG, "Installed AndroidKeyStoreProvider in "
220                 + (SystemClock.uptimeMillis() - startTime) + "ms.");
221         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
222 
223         startTime = SystemClock.uptimeMillis();
224         Trace.traceBegin(
225                 Trace.TRACE_TAG_DALVIK, "Starting warm up of JCA providers");
226         for (Provider p : Security.getProviders()) {
227             p.warmUpServiceProvision();
228         }
229         Log.i(TAG, "Warmed up JCA providers in "
230                 + (SystemClock.uptimeMillis() - startTime) + "ms.");
231         Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
232     }
233 
234     /**
235      * Performs Zygote process initialization. Loads and initializes commonly used classes.
236      *
237      * Most classes only cause a few hundred bytes to be allocated, but a few will allocate a dozen
238      * Kbytes (in one case, 500+K).
239      */
preloadClasses()240     private static void preloadClasses() {
241         final VMRuntime runtime = VMRuntime.getRuntime();
242 
243         InputStream is;
244         try {
245             is = new FileInputStream(PRELOADED_CLASSES);
246         } catch (FileNotFoundException e) {
247             Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
248             return;
249         }
250 
251         Log.i(TAG, "Preloading classes...");
252         long startTime = SystemClock.uptimeMillis();
253 
254         // Drop root perms while running static initializers.
255         final int reuid = Os.getuid();
256         final int regid = Os.getgid();
257 
258         // We need to drop root perms only if we're already root. In the case of "wrapped"
259         // processes (see WrapperInit), this function is called from an unprivileged uid
260         // and gid.
261         boolean droppedPriviliges = false;
262         if (reuid == ROOT_UID && regid == ROOT_GID) {
263             try {
264                 Os.setregid(ROOT_GID, UNPRIVILEGED_GID);
265                 Os.setreuid(ROOT_UID, UNPRIVILEGED_UID);
266             } catch (ErrnoException ex) {
267                 throw new RuntimeException("Failed to drop root", ex);
268             }
269 
270             droppedPriviliges = true;
271         }
272 
273         try {
274             BufferedReader br =
275                     new BufferedReader(new InputStreamReader(is), Zygote.SOCKET_BUFFER_SIZE);
276 
277             int count = 0;
278             String line;
279             while ((line = br.readLine()) != null) {
280                 // Skip comments and blank lines.
281                 line = line.trim();
282                 if (line.startsWith("#") || line.equals("")) {
283                     continue;
284                 }
285 
286                 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
287                 try {
288                     // Load and explicitly initialize the given class. Use
289                     // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
290                     // (to derive the caller's class-loader). Use true to force initialization, and
291                     // null for the boot classpath class-loader (could as well cache the
292                     // class-loader of this class in a variable).
293                     Class.forName(line, true, null);
294                     count++;
295                 } catch (ClassNotFoundException e) {
296                     Log.w(TAG, "Class not found for preloading: " + line);
297                 } catch (UnsatisfiedLinkError e) {
298                     Log.w(TAG, "Problem preloading " + line + ": " + e);
299                 } catch (Throwable t) {
300                     Log.e(TAG, "Error preloading " + line + ".", t);
301                     if (t instanceof Error) {
302                         throw (Error) t;
303                     }
304                     if (t instanceof RuntimeException) {
305                         throw (RuntimeException) t;
306                     }
307                     throw new RuntimeException(t);
308                 }
309                 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
310             }
311 
312             Log.i(TAG, "...preloaded " + count + " classes in "
313                     + (SystemClock.uptimeMillis() - startTime) + "ms.");
314         } catch (IOException e) {
315             Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
316         } finally {
317             IoUtils.closeQuietly(is);
318 
319             // Fill in dex caches with classes, fields, and methods brought in by preloading.
320             Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
321             runtime.preloadDexCaches();
322             Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
323 
324             // If we are profiling the boot image, reset the Jit counters after preloading the
325             // classes. We want to preload for performance, and we can use method counters to
326             // infer what clases are used after calling resetJitCounters, for profile purposes.
327             // Can't use device_config since we are the zygote.
328             String prop = SystemProperties.get(
329                     "persist.device_config.runtime_native_boot.profilebootclasspath", "");
330             // Might be empty if the property is unset since the default is "".
331             if (prop.length() == 0) {
332                 prop = SystemProperties.get("dalvik.vm.profilebootclasspath", "");
333             }
334             if ("true".equals(prop)) {
335                 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ResetJitCounters");
336                 runtime.resetJitCounters();
337                 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
338             }
339 
340             // Bring back root. We'll need it later if we're in the zygote.
341             if (droppedPriviliges) {
342                 try {
343                     Os.setreuid(ROOT_UID, ROOT_UID);
344                     Os.setregid(ROOT_GID, ROOT_GID);
345                 } catch (ErrnoException ex) {
346                     throw new RuntimeException("Failed to restore root", ex);
347                 }
348             }
349         }
350     }
351 
352     /**
353      * Load in things which are used by many apps but which cannot be put in the boot
354      * classpath.
355      */
cacheNonBootClasspathClassLoaders()356     private static void cacheNonBootClasspathClassLoaders() {
357         // These libraries used to be part of the bootclasspath, but had to be removed.
358         // Old system applications still get them for backwards compatibility reasons,
359         // so they are cached here in order to preserve performance characteristics.
360         SharedLibraryInfo hidlBase = new SharedLibraryInfo(
361                 "/system/framework/android.hidl.base-V1.0-java.jar", null /*packageName*/,
362                 null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
363                 null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
364         SharedLibraryInfo hidlManager = new SharedLibraryInfo(
365                 "/system/framework/android.hidl.manager-V1.0-java.jar", null /*packageName*/,
366                 null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
367                 null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
368         hidlManager.addDependency(hidlBase);
369 
370         SharedLibraryInfo androidTestBase = new SharedLibraryInfo(
371                 "/system/framework/android.test.base.jar", null /*packageName*/,
372                 null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
373                 null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
374 
375         ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders(
376                 new SharedLibraryInfo[]{
377                     // ordered dependencies first
378                     hidlBase,
379                     hidlManager,
380                     androidTestBase,
381                 });
382     }
383 
384     /**
385      * Load in commonly used resources, so they can be shared across processes.
386      *
387      * These tend to be a few Kbytes, but are frequently in the 20-40K range, and occasionally even
388      * larger.
389      */
preloadResources()390     private static void preloadResources() {
391         final VMRuntime runtime = VMRuntime.getRuntime();
392 
393         try {
394             mResources = Resources.getSystem();
395             mResources.startPreloading();
396             if (PRELOAD_RESOURCES) {
397                 Log.i(TAG, "Preloading resources...");
398 
399                 long startTime = SystemClock.uptimeMillis();
400                 TypedArray ar = mResources.obtainTypedArray(
401                         com.android.internal.R.array.preloaded_drawables);
402                 int N = preloadDrawables(ar);
403                 ar.recycle();
404                 Log.i(TAG, "...preloaded " + N + " resources in "
405                         + (SystemClock.uptimeMillis() - startTime) + "ms.");
406 
407                 startTime = SystemClock.uptimeMillis();
408                 ar = mResources.obtainTypedArray(
409                         com.android.internal.R.array.preloaded_color_state_lists);
410                 N = preloadColorStateLists(ar);
411                 ar.recycle();
412                 Log.i(TAG, "...preloaded " + N + " resources in "
413                         + (SystemClock.uptimeMillis() - startTime) + "ms.");
414 
415                 if (mResources.getBoolean(
416                         com.android.internal.R.bool.config_freeformWindowManagement)) {
417                     startTime = SystemClock.uptimeMillis();
418                     ar = mResources.obtainTypedArray(
419                             com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
420                     N = preloadDrawables(ar);
421                     ar.recycle();
422                     Log.i(TAG, "...preloaded " + N + " resource in "
423                             + (SystemClock.uptimeMillis() - startTime) + "ms.");
424                 }
425             }
426             mResources.finishPreloading();
427         } catch (RuntimeException e) {
428             Log.w(TAG, "Failure preloading resources", e);
429         }
430     }
431 
preloadColorStateLists(TypedArray ar)432     private static int preloadColorStateLists(TypedArray ar) {
433         int N = ar.length();
434         for (int i = 0; i < N; i++) {
435             int id = ar.getResourceId(i, 0);
436             if (false) {
437                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
438             }
439             if (id != 0) {
440                 if (mResources.getColorStateList(id, null) == null) {
441                     throw new IllegalArgumentException(
442                             "Unable to find preloaded color resource #0x"
443                                     + Integer.toHexString(id)
444                                     + " (" + ar.getString(i) + ")");
445                 }
446             }
447         }
448         return N;
449     }
450 
451 
preloadDrawables(TypedArray ar)452     private static int preloadDrawables(TypedArray ar) {
453         int N = ar.length();
454         for (int i = 0; i < N; i++) {
455             int id = ar.getResourceId(i, 0);
456             if (false) {
457                 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
458             }
459             if (id != 0) {
460                 if (mResources.getDrawable(id, null) == null) {
461                     throw new IllegalArgumentException(
462                             "Unable to find preloaded drawable resource #0x"
463                                     + Integer.toHexString(id)
464                                     + " (" + ar.getString(i) + ")");
465                 }
466             }
467         }
468         return N;
469     }
470 
471     /**
472      * Runs several special GCs to try to clean up a few generations of softly- and final-reachable
473      * objects, along with any other garbage. This is only useful just before a fork().
474      */
gcAndFinalize()475     private static void gcAndFinalize() {
476         ZygoteHooks.gcAndFinalize();
477     }
478 
shouldProfileSystemServer()479     private static boolean shouldProfileSystemServer() {
480         boolean defaultValue = SystemProperties.getBoolean("dalvik.vm.profilesystemserver",
481                 /*default=*/ false);
482         // Can't use DeviceConfig since it's not initialized at this point.
483         return SystemProperties.getBoolean(
484                 "persist.device_config." + DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT
485                         + ".profilesystemserver",
486                 defaultValue);
487     }
488 
489     /**
490      * Finish remaining work for the newly forked system server process.
491      */
handleSystemServerProcess(ZygoteArguments parsedArgs)492     private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
493         // set umask to 0077 so new files and directories will default to owner-only permissions.
494         Os.umask(S_IRWXG | S_IRWXO);
495 
496         if (parsedArgs.mNiceName != null) {
497             Process.setArgV0(parsedArgs.mNiceName);
498         }
499 
500         final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
501         if (systemServerClasspath != null) {
502             performSystemServerDexOpt(systemServerClasspath);
503             // Capturing profiles is only supported for debug or eng builds since selinux normally
504             // prevents it.
505             if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
506                 try {
507                     Log.d(TAG, "Preparing system server profile");
508                     prepareSystemServerProfile(systemServerClasspath);
509                 } catch (Exception e) {
510                     Log.wtf(TAG, "Failed to set up system server profile", e);
511                 }
512             }
513         }
514 
515         if (parsedArgs.mInvokeWith != null) {
516             String[] args = parsedArgs.mRemainingArgs;
517             // If we have a non-null system server class path, we'll have to duplicate the
518             // existing arguments and append the classpath to it. ART will handle the classpath
519             // correctly when we exec a new process.
520             if (systemServerClasspath != null) {
521                 String[] amendedArgs = new String[args.length + 2];
522                 amendedArgs[0] = "-cp";
523                 amendedArgs[1] = systemServerClasspath;
524                 System.arraycopy(args, 0, amendedArgs, 2, args.length);
525                 args = amendedArgs;
526             }
527 
528             WrapperInit.execApplication(parsedArgs.mInvokeWith,
529                     parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
530                     VMRuntime.getCurrentInstructionSet(), null, args);
531 
532             throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
533         } else {
534             ClassLoader cl = null;
535             if (systemServerClasspath != null) {
536                 cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
537 
538                 Thread.currentThread().setContextClassLoader(cl);
539             }
540 
541             /*
542              * Pass the remaining arguments to SystemServer.
543              */
544             return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
545                     parsedArgs.mDisabledCompatChanges,
546                     parsedArgs.mRemainingArgs, cl);
547         }
548 
549         /* should never reach here */
550     }
551 
552     /**
553      * Note that preparing the profiles for system server does not require special selinux
554      * permissions. From the installer perspective the system server is a regular package which can
555      * capture profile information.
556      */
prepareSystemServerProfile(String systemServerClasspath)557     private static void prepareSystemServerProfile(String systemServerClasspath)
558             throws RemoteException {
559         if (systemServerClasspath.isEmpty()) {
560             return;
561         }
562         String[] codePaths = systemServerClasspath.split(":");
563 
564         final IInstalld installd = IInstalld.Stub
565                 .asInterface(ServiceManager.getService("installd"));
566 
567         String systemServerPackageName = "android";
568         String systemServerProfileName = "primary.prof";
569         installd.prepareAppProfile(
570                 systemServerPackageName,
571                 UserHandle.USER_SYSTEM,
572                 UserHandle.getAppId(Process.SYSTEM_UID),
573                 systemServerProfileName,
574                 codePaths[0],
575                 /*dexMetadata*/ null);
576 
577         File profileDir = Environment.getDataProfilesDePackageDirectory(
578                 UserHandle.USER_SYSTEM, systemServerPackageName);
579         String profilePath = new File(profileDir, systemServerProfileName).getAbsolutePath();
580         VMRuntime.registerAppInfo(profilePath, codePaths);
581     }
582 
setApiBlacklistExemptions(String[] exemptions)583     public static void setApiBlacklistExemptions(String[] exemptions) {
584         VMRuntime.getRuntime().setHiddenApiExemptions(exemptions);
585     }
586 
setHiddenApiAccessLogSampleRate(int percent)587     public static void setHiddenApiAccessLogSampleRate(int percent) {
588         VMRuntime.getRuntime().setHiddenApiAccessLogSamplingRate(percent);
589     }
590 
591     /**
592      * Sets the implementation to be used for logging hidden API accesses
593      * @param logger the implementation of the VMRuntime.HiddenApiUsageLogger interface
594      */
setHiddenApiUsageLogger(VMRuntime.HiddenApiUsageLogger logger)595     public static void setHiddenApiUsageLogger(VMRuntime.HiddenApiUsageLogger logger) {
596         VMRuntime.getRuntime().setHiddenApiUsageLogger(logger);
597     }
598 
599     /**
600      * Creates a PathClassLoader for the given class path that is associated with a shared
601      * namespace, i.e., this classloader can access platform-private native libraries. The
602      * classloader will use java.library.path as the native library path.
603      */
createPathClassLoader(String classPath, int targetSdkVersion)604     static ClassLoader createPathClassLoader(String classPath, int targetSdkVersion) {
605         String libraryPath = System.getProperty("java.library.path");
606 
607         // We use the boot class loader, that's what the runtime expects at AOT.
608         ClassLoader parent = ClassLoader.getSystemClassLoader().getParent();
609 
610         return ClassLoaderFactory.createClassLoader(classPath, libraryPath, libraryPath,
611                 parent, targetSdkVersion, true /* isNamespaceShared */, null /* classLoaderName */);
612     }
613 
614     /**
615      * Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
616      * set of the current runtime.
617      */
performSystemServerDexOpt(String classPath)618     private static void performSystemServerDexOpt(String classPath) {
619         final String[] classPathElements = classPath.split(":");
620         final IInstalld installd = IInstalld.Stub
621                 .asInterface(ServiceManager.getService("installd"));
622         final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
623 
624         String classPathForElement = "";
625         for (String classPathElement : classPathElements) {
626             // We default to the verify filter because the compilation will happen on /data and
627             // system server cannot load executable code outside /system.
628             String systemServerFilter = SystemProperties.get(
629                     "dalvik.vm.systemservercompilerfilter", "verify");
630 
631             String classLoaderContext =
632                         getSystemServerClassLoaderContext(classPathForElement);
633             int dexoptNeeded;
634             try {
635                 dexoptNeeded = DexFile.getDexOptNeeded(
636                         classPathElement, instructionSet, systemServerFilter,
637                         classLoaderContext, false /* newProfile */, false /* downgrade */);
638             } catch (FileNotFoundException ignored) {
639                 // Do not add to the classpath.
640                 Log.w(TAG, "Missing classpath element for system server: " + classPathElement);
641                 continue;
642             } catch (IOException e) {
643                 // Not fully clear what to do here as we don't know the cause of the
644                 // IO exception. Add to the classpath to be conservative, but don't
645                 // attempt to compile it.
646                 Log.w(TAG, "Error checking classpath element for system server: "
647                         + classPathElement, e);
648                 dexoptNeeded = DexFile.NO_DEXOPT_NEEDED;
649             }
650 
651             if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
652                 final String packageName = "*";
653                 final String outputPath = null;
654                 final int dexFlags = 0;
655                 final String compilerFilter = systemServerFilter;
656                 final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
657                 final String seInfo = null;
658                 final int targetSdkVersion = 0;  // SystemServer targets the system's SDK version
659                 try {
660                     installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
661                             instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
662                             uuid, classLoaderContext, seInfo, false /* downgrade */,
663                             targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
664                             "server-dexopt");
665                 } catch (RemoteException | ServiceSpecificException e) {
666                     // Ignore (but log), we need this on the classpath for fallback mode.
667                     Log.w(TAG, "Failed compiling classpath element for system server: "
668                             + classPathElement, e);
669                 }
670             }
671 
672             classPathForElement = encodeSystemServerClassPath(
673                     classPathForElement, classPathElement);
674         }
675     }
676 
677     /**
678      * Encodes the system server class loader context in a format that is accepted by dexopt. This
679      * assumes the system server is always loaded with a {@link dalvik.system.PathClassLoader}.
680      *
681      * Note that ideally we would use the {@code DexoptUtils} to compute this. However we have no
682      * dependency here on the server so we hard code the logic again.
683      */
getSystemServerClassLoaderContext(String classPath)684     private static String getSystemServerClassLoaderContext(String classPath) {
685         return classPath == null ? "PCL[]" : "PCL[" + classPath + "]";
686     }
687 
688     /**
689      * Encodes the class path in a format accepted by dexopt.
690      *
691      * @param classPath  The old class path (may be empty).
692      * @param newElement  The new class path elements
693      * @return The class path encoding resulted from appending {@code newElement} to {@code
694      * classPath}.
695      */
encodeSystemServerClassPath(String classPath, String newElement)696     private static String encodeSystemServerClassPath(String classPath, String newElement) {
697         return (classPath == null || classPath.isEmpty())
698                 ? newElement
699                 : classPath + ":" + newElement;
700     }
701 
702     /**
703      * Prepare the arguments and forks for the system server process.
704      *
705      * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
706      * process; {@code null} in the parent.
707      */
forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)708     private static Runnable forkSystemServer(String abiList, String socketName,
709             ZygoteServer zygoteServer) {
710         long capabilities = posixCapabilitiesAsBits(
711                 OsConstants.CAP_IPC_LOCK,
712                 OsConstants.CAP_KILL,
713                 OsConstants.CAP_NET_ADMIN,
714                 OsConstants.CAP_NET_BIND_SERVICE,
715                 OsConstants.CAP_NET_BROADCAST,
716                 OsConstants.CAP_NET_RAW,
717                 OsConstants.CAP_SYS_MODULE,
718                 OsConstants.CAP_SYS_NICE,
719                 OsConstants.CAP_SYS_PTRACE,
720                 OsConstants.CAP_SYS_TIME,
721                 OsConstants.CAP_SYS_TTY_CONFIG,
722                 OsConstants.CAP_WAKE_ALARM,
723                 OsConstants.CAP_BLOCK_SUSPEND
724         );
725         /* Containers run without some capabilities, so drop any caps that are not available. */
726         StructCapUserHeader header = new StructCapUserHeader(
727                 OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
728         StructCapUserData[] data;
729         try {
730             data = Os.capget(header);
731         } catch (ErrnoException ex) {
732             throw new RuntimeException("Failed to capget()", ex);
733         }
734         capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
735 
736         /* Hardcoded command line to start the system server */
737         String args[] = {
738                 "--setuid=1000",
739                 "--setgid=1000",
740                 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
741                         + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
742                 "--capabilities=" + capabilities + "," + capabilities,
743                 "--nice-name=system_server",
744                 "--runtime-args",
745                 "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
746                 "com.android.server.SystemServer",
747         };
748         ZygoteArguments parsedArgs = null;
749 
750         int pid;
751 
752         try {
753             parsedArgs = new ZygoteArguments(args);
754             Zygote.applyDebuggerSystemProperty(parsedArgs);
755             Zygote.applyInvokeWithSystemProperty(parsedArgs);
756 
757             if (Zygote.nativeSupportsMemoryTagging()) {
758                 /* The system server is more privileged than regular app processes, so it has async
759                  * tag checks enabled on hardware that supports memory tagging. */
760                 parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
761             } else if (Zygote.nativeSupportsTaggedPointers()) {
762                 /* Enable pointer tagging in the system server. Hardware support for this is present
763                  * in all ARMv8 CPUs. */
764                 parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
765             }
766 
767             if (shouldProfileSystemServer()) {
768                 parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
769             }
770 
771             /* Request to fork the system server process */
772             pid = Zygote.forkSystemServer(
773                     parsedArgs.mUid, parsedArgs.mGid,
774                     parsedArgs.mGids,
775                     parsedArgs.mRuntimeFlags,
776                     null,
777                     parsedArgs.mPermittedCapabilities,
778                     parsedArgs.mEffectiveCapabilities);
779         } catch (IllegalArgumentException ex) {
780             throw new RuntimeException(ex);
781         }
782 
783         /* For child process */
784         if (pid == 0) {
785             if (hasSecondZygote(abiList)) {
786                 waitForSecondaryZygote(socketName);
787             }
788 
789             zygoteServer.closeServerSocket();
790             return handleSystemServerProcess(parsedArgs);
791         }
792 
793         return null;
794     }
795 
796     /**
797      * Gets the bit array representation of the provided list of POSIX capabilities.
798      */
posixCapabilitiesAsBits(int... capabilities)799     private static long posixCapabilitiesAsBits(int... capabilities) {
800         long result = 0;
801         for (int capability : capabilities) {
802             if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
803                 throw new IllegalArgumentException(String.valueOf(capability));
804             }
805             result |= (1L << capability);
806         }
807         return result;
808     }
809 
810     /**
811      * This is the entry point for a Zygote process.  It creates the Zygote server, loads resources,
812      * and handles other tasks related to preparing the process for forking into applications.
813      *
814      * This process is started with a nice value of -20 (highest priority).  All paths that flow
815      * into new processes are required to either set the priority to the default value or terminate
816      * before executing any non-system code.  The native side of this occurs in SpecializeCommon,
817      * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
818      * ZygoteConnection.handleChildProc, and Zygote.usapMain.
819      *
820      * @param argv  Command line arguments used to specify the Zygote's configuration.
821      */
822     @UnsupportedAppUsage
main(String argv[])823     public static void main(String argv[]) {
824         ZygoteServer zygoteServer = null;
825 
826         // Mark zygote start. This ensures that thread creation will throw
827         // an error.
828         ZygoteHooks.startZygoteNoThreadCreation();
829 
830         // Zygote goes into its own process group.
831         try {
832             Os.setpgid(0, 0);
833         } catch (ErrnoException ex) {
834             throw new RuntimeException("Failed to setpgid(0,0)", ex);
835         }
836 
837         Runnable caller;
838         try {
839             // Report Zygote start time to tron unless it is a runtime restart
840             if (!"1".equals(SystemProperties.get("sys.boot_completed"))) {
841                 MetricsLogger.histogram(null, "boot_zygote_init",
842                         (int) SystemClock.elapsedRealtime());
843             }
844 
845             String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
846             TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
847                     Trace.TRACE_TAG_DALVIK);
848             bootTimingsTraceLog.traceBegin("ZygoteInit");
849             RuntimeInit.preForkInit();
850 
851             boolean startSystemServer = false;
852             String zygoteSocketName = "zygote";
853             String abiList = null;
854             boolean enableLazyPreload = false;
855             for (int i = 1; i < argv.length; i++) {
856                 if ("start-system-server".equals(argv[i])) {
857                     startSystemServer = true;
858                 } else if ("--enable-lazy-preload".equals(argv[i])) {
859                     enableLazyPreload = true;
860                 } else if (argv[i].startsWith(ABI_LIST_ARG)) {
861                     abiList = argv[i].substring(ABI_LIST_ARG.length());
862                 } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
863                     zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
864                 } else {
865                     throw new RuntimeException("Unknown command line argument: " + argv[i]);
866                 }
867             }
868 
869             final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
870 
871             if (abiList == null) {
872                 throw new RuntimeException("No ABI list supplied.");
873             }
874 
875             // In some configurations, we avoid preloading resources and classes eagerly.
876             // In such cases, we will preload things prior to our first fork.
877             if (!enableLazyPreload) {
878                 bootTimingsTraceLog.traceBegin("ZygotePreload");
879                 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
880                         SystemClock.uptimeMillis());
881                 preload(bootTimingsTraceLog);
882                 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
883                         SystemClock.uptimeMillis());
884                 bootTimingsTraceLog.traceEnd(); // ZygotePreload
885             }
886 
887             // Do an initial gc to clean up after startup
888             bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
889             gcAndFinalize();
890             bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
891 
892             bootTimingsTraceLog.traceEnd(); // ZygoteInit
893 
894             Zygote.initNativeState(isPrimaryZygote);
895 
896             ZygoteHooks.stopZygoteNoThreadCreation();
897 
898             zygoteServer = new ZygoteServer(isPrimaryZygote);
899 
900             if (startSystemServer) {
901                 Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
902 
903                 // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
904                 // child (system_server) process.
905                 if (r != null) {
906                     r.run();
907                     return;
908                 }
909             }
910 
911             Log.i(TAG, "Accepting command socket connections");
912 
913             // The select loop returns early in the child process after a fork and
914             // loops forever in the zygote.
915             caller = zygoteServer.runSelectLoop(abiList);
916         } catch (Throwable ex) {
917             Log.e(TAG, "System zygote died with exception", ex);
918             throw ex;
919         } finally {
920             if (zygoteServer != null) {
921                 zygoteServer.closeServerSocket();
922             }
923         }
924 
925         // We're in the child process and have exited the select loop. Proceed to execute the
926         // command.
927         if (caller != null) {
928             caller.run();
929         }
930     }
931 
932     /**
933      * Return {@code true} if this device configuration has another zygote.
934      *
935      * We determine this by comparing the device ABI list with this zygotes list. If this zygote
936      * supports all ABIs this device supports, there won't be another zygote.
937      */
hasSecondZygote(String abiList)938     private static boolean hasSecondZygote(String abiList) {
939         return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
940     }
941 
waitForSecondaryZygote(String socketName)942     private static void waitForSecondaryZygote(String socketName) {
943         String otherZygoteName = Zygote.PRIMARY_SOCKET_NAME.equals(socketName)
944                 ? Zygote.SECONDARY_SOCKET_NAME : Zygote.PRIMARY_SOCKET_NAME;
945         ZygoteProcess.waitForConnectionToZygote(otherZygoteName);
946     }
947 
isPreloadComplete()948     static boolean isPreloadComplete() {
949         return sPreloadComplete;
950     }
951 
952     /**
953      * Class not instantiable.
954      */
ZygoteInit()955     private ZygoteInit() {
956     }
957 
958     /**
959      * The main function called when started through the zygote process. This could be unified with
960      * main(), if the native code in nativeFinishInit() were rationalized with Zygote startup.<p>
961      *
962      * Current recognized args:
963      * <ul>
964      * <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
965      * </ul>
966      *
967      * @param targetSdkVersion target SDK version
968      * @param disabledCompatChanges set of disabled compat changes for the process (all others
969      *                              are enabled)
970      * @param argv             arg strings
971      */
zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader)972     public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
973             String[] argv, ClassLoader classLoader) {
974         if (RuntimeInit.DEBUG) {
975             Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
976         }
977 
978         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
979         RuntimeInit.redirectLogStreams();
980 
981         RuntimeInit.commonInit();
982         ZygoteInit.nativeZygoteInit();
983         return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
984                 classLoader);
985     }
986 
987     /**
988      * The main function called when starting a child zygote process. This is used as an alternative
989      * to zygoteInit(), which skips calling into initialization routines that start the Binder
990      * threadpool.
991      */
childZygoteInit( int targetSdkVersion, String[] argv, ClassLoader classLoader)992     static final Runnable childZygoteInit(
993             int targetSdkVersion, String[] argv, ClassLoader classLoader) {
994         RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
995         return RuntimeInit.findStaticMain(args.startClass, args.startArgs, classLoader);
996     }
997 
nativeZygoteInit()998     private static final native void nativeZygoteInit();
999 }
1000