• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.O_CLOEXEC;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.compat.annotation.ChangeId;
24 import android.compat.annotation.Disabled;
25 import android.compat.annotation.EnabledAfter;
26 import android.content.Context;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.ProcessInfo;
29 import android.net.Credentials;
30 import android.net.LocalServerSocket;
31 import android.net.LocalSocket;
32 import android.os.Build;
33 import android.os.FactoryTest;
34 import android.os.IVold;
35 import android.os.Process;
36 import android.os.RemoteException;
37 import android.os.ServiceManager;
38 import android.os.SystemProperties;
39 import android.os.Trace;
40 import android.provider.DeviceConfig;
41 import android.system.ErrnoException;
42 import android.system.Os;
43 import android.util.Log;
44 
45 import com.android.internal.compat.IPlatformCompat;
46 import com.android.internal.net.NetworkUtilsInternal;
47 
48 import dalvik.annotation.optimization.CriticalNative;
49 import dalvik.annotation.optimization.FastNative;
50 import dalvik.system.ZygoteHooks;
51 
52 import libcore.io.IoUtils;
53 
54 import java.io.ByteArrayOutputStream;
55 import java.io.DataOutputStream;
56 import java.io.FileDescriptor;
57 import java.io.IOException;
58 
59 /** @hide */
60 public final class Zygote {
61     /*
62     * Bit values for "runtimeFlags" argument.  The definitions are duplicated
63     * in the native code.
64     */
65 
66     /** enable debugging over JDWP */
67     public static final int DEBUG_ENABLE_JDWP   = 1;
68     /** enable JNI checks */
69     public static final int DEBUG_ENABLE_CHECKJNI   = 1 << 1;
70     /** enable Java programming language "assert" statements */
71     public static final int DEBUG_ENABLE_ASSERT     = 1 << 2;
72     /** disable the AOT compiler and JIT */
73     public static final int DEBUG_ENABLE_SAFEMODE   = 1 << 3;
74     /** Enable logging of third-party JNI activity. */
75     public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
76     /** Force generation of native debugging information. */
77     public static final int DEBUG_GENERATE_DEBUG_INFO = 1 << 5;
78     /** Always use JIT-ed code. */
79     public static final int DEBUG_ALWAYS_JIT = 1 << 6;
80     /** Make the code native debuggable by turning off some optimizations. */
81     public static final int DEBUG_NATIVE_DEBUGGABLE = 1 << 7;
82     /** Make the code Java debuggable by turning off some optimizations. */
83     public static final int DEBUG_JAVA_DEBUGGABLE = 1 << 8;
84 
85     /** Turn off the verifier. */
86     public static final int DISABLE_VERIFIER = 1 << 9;
87     /** Only use oat files located in /system. Otherwise use dex/jar/apk . */
88     public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10;
89     /** Force generation of native debugging information for backtraces. */
90     public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11;
91     /**
92      * Hidden API access restrictions. This is a mask for bits representing the API enforcement
93      * policy, defined by {@code @ApplicationInfo.HiddenApiEnforcementPolicy}.
94      */
95     public static final int API_ENFORCEMENT_POLICY_MASK = (1 << 12) | (1 << 13);
96     /**
97      * Bit shift for use with {@link #API_ENFORCEMENT_POLICY_MASK}.
98      *
99      * (flags & API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT gives
100      * {@link ApplicationInfo.HiddenApiEnforcementPolicy} values.
101      */
102     public static final int API_ENFORCEMENT_POLICY_SHIFT =
103             Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK);
104     /**
105      * Enable system server ART profiling.
106      */
107     public static final int PROFILE_SYSTEM_SERVER = 1 << 14;
108 
109     /**
110      * Enable profiling from shell.
111      */
112     public static final int PROFILE_FROM_SHELL = 1 << 15;
113 
114     /*
115      * Enable using the ART app image startup cache
116      */
117     public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16;
118 
119     /**
120      * When set, application specified signal handlers are not chained (i.e, ignored)
121      * by the runtime.
122      *
123      * Used for debugging only. Usage: set debug.ignoreappsignalhandler to 1.
124      */
125     public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17;
126 
127     /**
128      * Disable runtime access to {@link android.annotation.TestApi} annotated members.
129      *
130      * <p>This only takes effect if Hidden API access restrictions are enabled as well.
131      */
132     public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18;
133 
134     public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20);
135 
136     public static final int MEMORY_TAG_LEVEL_NONE = 0;
137 
138     /**
139      * Enable pointer tagging in this process.
140      * Tags are checked during memory deallocation, but not on access.
141      * TBI stands for Top-Byte-Ignore, an ARM CPU feature.
142      * {@link https://developer.arm.com/docs/den0024/latest/the-memory-management-unit/translation-table-configuration/virtual-address-tagging}
143      */
144     public static final int MEMORY_TAG_LEVEL_TBI = 1 << 19;
145 
146     /**
147      * Enable asynchronous memory tag checks in this process.
148      */
149     public static final int MEMORY_TAG_LEVEL_ASYNC = 2 << 19;
150 
151     /**
152      * Enable synchronous memory tag checks in this process.
153      */
154     public static final int MEMORY_TAG_LEVEL_SYNC = 3 << 19;
155 
156     /**
157      * A two-bit field for GWP-ASan level of this process. See the possible values below.
158      */
159     public static final int GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22);
160 
161     /**
162      * Disable GWP-ASan in this process.
163      * GWP-ASan is a low-overhead memory bug detector using guard pages on a small
164      * subset of heap allocations.
165      */
166     public static final int GWP_ASAN_LEVEL_NEVER = 0 << 21;
167 
168     /**
169      * Enable GWP-ASan in this process with a small sampling rate.
170      * With approx. 1% chance GWP-ASan will be activated and apply its protection
171      * to a small subset of heap allocations.
172      * Otherwise (~99% chance) this process is unaffected.
173      */
174     public static final int GWP_ASAN_LEVEL_LOTTERY = 1 << 21;
175 
176     /**
177      * Always enable GWP-ASan in this process.
178      * GWP-ASan is activated unconditionally (but still, only a small subset of
179      * allocations is protected).
180      */
181     public static final int GWP_ASAN_LEVEL_ALWAYS = 1 << 22;
182 
183     /** Enable automatic zero-initialization of native heap memory allocations. */
184     public static final int NATIVE_HEAP_ZERO_INIT_ENABLED = 1 << 23;
185 
186     /**
187      * Enable profiling from system services. This loads profiling related plugins in ART.
188      */
189     public static final int PROFILEABLE = 1 << 24;
190 
191     /** No external storage should be mounted. */
192     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
193     /** Default external storage should be mounted. */
194     public static final int MOUNT_EXTERNAL_DEFAULT = IVold.REMOUNT_MODE_DEFAULT;
195     /**
196      * Mount mode for package installers which should give them access to
197      * all obb dirs in addition to their package sandboxes
198      */
199     public static final int MOUNT_EXTERNAL_INSTALLER = IVold.REMOUNT_MODE_INSTALLER;
200     /** The lower file system should be bind mounted directly on external storage */
201     public static final int MOUNT_EXTERNAL_PASS_THROUGH = IVold.REMOUNT_MODE_PASS_THROUGH;
202 
203     /** Use the regular scoped storage filesystem, but Android/ should be writable.
204      * Used to support the applications hosting DownloadManager and the MTP server.
205      */
206     public static final int MOUNT_EXTERNAL_ANDROID_WRITABLE = IVold.REMOUNT_MODE_ANDROID_WRITABLE;
207 
208     /** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */
209     static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8;
210 
211     /** Make the new process have top application priority. */
212     public static final String START_AS_TOP_APP_ARG = "--is-top-app";
213 
214     /** List of packages with the same uid, and its app data info: volume uuid and inode. */
215     public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
216 
217     /** List of allowlisted packages and its app data info: volume uuid and inode. */
218     public static final String ALLOWLISTED_DATA_INFO_MAP = "--allowlisted-data-info-map";
219 
220     /** Bind mount app storage dirs to lower fs not via fuse */
221     public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
222 
223     /** Bind mount app storage dirs to lower fs not via fuse */
224     public static final String BIND_MOUNT_APP_DATA_DIRS = "--bind-mount-data-dirs";
225 
226     /**
227      * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
228      * in the abstract socket namespace. This socket name is what the new child zygote
229      * should listen for connections on.
230      */
231     public static final String CHILD_ZYGOTE_SOCKET_NAME_ARG = "--zygote-socket=";
232 
233     /**
234      * An extraArg passed when a zygote process is forking a child-zygote, specifying the
235      * requested ABI for the child Zygote.
236      */
237     public static final String CHILD_ZYGOTE_ABI_LIST_ARG = "--abi-list=";
238 
239     /**
240      * An extraArg passed when a zygote process is forking a child-zygote, specifying the
241      * start of the UID range the children of the Zygote may setuid()/setgid() to. This
242      * will be enforced with a seccomp filter.
243      */
244     public static final String CHILD_ZYGOTE_UID_RANGE_START = "--uid-range-start=";
245 
246     /**
247      * An extraArg passed when a zygote process is forking a child-zygote, specifying the
248      * end of the UID range the children of the Zygote may setuid()/setgid() to. This
249      * will be enforced with a seccomp filter.
250      */
251     public static final String CHILD_ZYGOTE_UID_RANGE_END = "--uid-range-end=";
252 
253     private static final String TAG = "Zygote";
254 
255     /** Prefix prepended to socket names created by init */
256     private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
257 
258     /**
259      * The duration to wait before re-checking Zygote related system properties.
260      *
261      * One minute in milliseconds.
262      */
263     public static final long PROPERTY_CHECK_INTERVAL = 60000;
264 
265     /**
266      * @hide for internal use only
267      */
268     public static final int SOCKET_BUFFER_SIZE = 256;
269 
270     /**
271      * @hide for internal use only
272      */
273     private static final int PRIORITY_MAX = -20;
274 
275     /** a prototype instance for a future List.toArray() */
276     static final int[][] INT_ARRAY_2D = new int[0][0];
277 
278     /**
279      * @hide for internal use only.
280      */
281     public static final String PRIMARY_SOCKET_NAME = "zygote";
282 
283     /**
284      * @hide for internal use only.
285      */
286     public static final String SECONDARY_SOCKET_NAME = "zygote_secondary";
287 
288     /**
289      * @hide for internal use only
290      */
291     public static final String USAP_POOL_PRIMARY_SOCKET_NAME = "usap_pool_primary";
292 
293     /**
294      * @hide for internal use only
295      */
296     public static final String USAP_POOL_SECONDARY_SOCKET_NAME = "usap_pool_secondary";
297 
Zygote()298     private Zygote() {}
299 
containsInetGid(int[] gids)300     private static boolean containsInetGid(int[] gids) {
301         for (int i = 0; i < gids.length; i++) {
302             if (gids[i] == android.os.Process.INET_GID) return true;
303         }
304         return false;
305     }
306 
307     /**
308      * Forks a new VM instance.  The current VM must have been started
309      * with the -Xzygote flag. <b>NOTE: new instance keeps all
310      * root capabilities. The new process is expected to call capset()</b>.
311      *
312      * @param uid the UNIX uid that the new process should setuid() to after
313      * fork()ing and and before spawning any threads.
314      * @param gid the UNIX gid that the new process should setgid() to after
315      * fork()ing and and before spawning any threads.
316      * @param gids null-ok; a list of UNIX gids that the new process should
317      * setgroups() to after fork and before spawning any threads.
318      * @param runtimeFlags bit flags that enable ART features.
319      * @param rlimits null-ok an array of rlimit tuples, with the second
320      * dimension having a length of 3 and representing
321      * (resource, rlim_cur, rlim_max). These are set via the posix
322      * setrlimit(2) call.
323      * @param seInfo null-ok a string specifying SELinux information for
324      * the new process.
325      * @param niceName null-ok a string specifying the process name.
326      * @param fdsToClose an array of ints, holding one or more POSIX
327      * file descriptor numbers that are to be closed by the child
328      * (and replaced by /dev/null) after forking.  An integer value
329      * of -1 in any entry in the array means "ignore this one".
330      * @param fdsToIgnore null-ok an array of ints, either null or holding
331      * one or more POSIX file descriptor numbers that are to be ignored
332      * in the file descriptor table check.
333      * @param startChildZygote if true, the new child process will itself be a
334      * new zygote process.
335      * @param instructionSet null-ok the instruction set to use.
336      * @param appDataDir null-ok the data directory of the app.
337      * @param isTopApp true if the process is for top (high priority) application.
338      * @param pkgDataInfoList A list that stores related packages and its app data
339      * info: volume uuid and inode.
340      * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
341      * @param bindMountAppDataDirs  True if the zygote needs to mount data dirs.
342      * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
343      *
344      * @return 0 if this is the child, pid of the child
345      * if this is the parent, or -1 on error.
346      */
forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs)347     static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
348             int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
349             int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
350             boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList,
351             boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
352         ZygoteHooks.preFork();
353 
354         int pid = nativeForkAndSpecialize(
355                 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
356                 fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
357                 pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs,
358                 bindMountAppStorageDirs);
359         if (pid == 0) {
360             // Note that this event ends at the end of handleChildProc,
361             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
362 
363             // If no GIDs were specified, don't make any permissions changes based on groups.
364             if (gids != null && gids.length > 0) {
365                 NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
366             }
367         }
368 
369         // Set the Java Language thread priority to the default value for new apps.
370         Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
371 
372         ZygoteHooks.postForkCommon();
373         return pid;
374     }
375 
nativeForkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs)376     private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
377             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
378             int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
379             String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
380             String[] allowlistedDataInfoList, boolean bindMountAppDataDirs,
381             boolean bindMountAppStorageDirs);
382 
383     /**
384      * Specialize an unspecialized app process.  The current VM must have been started
385      * with the -Xzygote flag.
386      *
387      * @param uid  The UNIX uid that the new process should setuid() to before spawning any threads
388      * @param gid  The UNIX gid that the new process should setgid() to before spawning any threads
389      * @param gids null-ok;  A list of UNIX gids that the new process should
390      * setgroups() to before spawning any threads
391      * @param runtimeFlags  Bit flags that enable ART features
392      * @param rlimits null-ok  An array of rlimit tuples, with the second
393      * dimension having a length of 3 and representing
394      * (resource, rlim_cur, rlim_max). These are set via the posix
395      * setrlimit(2) call.
396      * @param seInfo null-ok  A string specifying SELinux information for
397      * the new process.
398      * @param niceName null-ok  A string specifying the process name.
399      * @param startChildZygote  If true, the new child process will itself be a
400      * new zygote process.
401      * @param instructionSet null-ok  The instruction set to use.
402      * @param appDataDir null-ok  The data directory of the app.
403      * @param isTopApp  True if the process is for top (high priority) application.
404      * @param pkgDataInfoList A list that stores related packages and its app data
405      * volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
406      * app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
407      * app_b_ce_inode, ...];
408      * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps.
409      * @param bindMountAppDataDirs  True if the zygote needs to mount data dirs.
410      * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
411      */
specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs)412     private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
413             int[][] rlimits, int mountExternal, String seInfo, String niceName,
414             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
415             String[] pkgDataInfoList, String[] allowlistedDataInfoList,
416             boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
417         nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
418                 niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
419                 pkgDataInfoList, allowlistedDataInfoList,
420                 bindMountAppDataDirs, bindMountAppStorageDirs);
421 
422         // Note that this event ends at the end of handleChildProc.
423         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
424 
425         if (gids != null && gids.length > 0) {
426             NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
427         }
428 
429         // Set the Java Language thread priority to the default value for new apps.
430         Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
431 
432         /*
433          * This is called here (instead of after the fork but before the specialize) to maintain
434          * consistancy with the code paths for forkAndSpecialize.
435          *
436          * TODO (chriswailes): Look into moving this to immediately after the fork.
437          */
438         ZygoteHooks.postForkCommon();
439     }
440 
nativeSpecializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs)441     private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
442             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
443             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
444             String[] pkgDataInfoList, String[] allowlistedDataInfoList,
445             boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs);
446 
447     /**
448      * Called to do any initialization before starting an application.
449      */
nativePreApplicationInit()450     static native void nativePreApplicationInit();
451 
452     /**
453      * Special method to start the system server process. In addition to the
454      * common actions performed in forkAndSpecialize, the pid of the child
455      * process is recorded such that the death of the child process will cause
456      * zygote to exit.
457      *
458      * @param uid the UNIX uid that the new process should setuid() to after
459      * fork()ing and and before spawning any threads.
460      * @param gid the UNIX gid that the new process should setgid() to after
461      * fork()ing and and before spawning any threads.
462      * @param gids null-ok; a list of UNIX gids that the new process should
463      * setgroups() to after fork and before spawning any threads.
464      * @param runtimeFlags bit flags that enable ART features.
465      * @param rlimits null-ok an array of rlimit tuples, with the second
466      * dimension having a length of 3 and representing
467      * (resource, rlim_cur, rlim_max). These are set via the posix
468      * setrlimit(2) call.
469      * @param permittedCapabilities argument for setcap()
470      * @param effectiveCapabilities argument for setcap()
471      *
472      * @return 0 if this is the child, pid of the child
473      * if this is the parent, or -1 on error.
474      */
forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)475     static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
476             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
477         ZygoteHooks.preFork();
478 
479         int pid = nativeForkSystemServer(
480                 uid, gid, gids, runtimeFlags, rlimits,
481                 permittedCapabilities, effectiveCapabilities);
482 
483         // Set the Java Language thread priority to the default value for new apps.
484         Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
485 
486         ZygoteHooks.postForkCommon();
487         return pid;
488     }
489 
nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities)490     private static native int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
491             int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
492 
493     /**
494      * Lets children of the zygote inherit open file descriptors to this path.
495      */
nativeAllowFileAcrossFork(String path)496     protected static native void nativeAllowFileAcrossFork(String path);
497 
498     /**
499      * Lets children of the zygote inherit open file descriptors that belong to the
500      * ApplicationInfo that is passed in.
501      *
502      * @param appInfo ApplicationInfo of the application
503      */
allowAppFilesAcrossFork(ApplicationInfo appInfo)504     static void allowAppFilesAcrossFork(ApplicationInfo appInfo) {
505         for (String path : appInfo.getAllApkPaths()) {
506             Zygote.nativeAllowFileAcrossFork(path);
507         }
508     }
509 
510     /**
511      * Scans file descriptors in /proc/self/fd/, stores their metadata from readlink(2)/stat(2) when
512      * available. Saves this information in a global on native side, to be used by subsequent call
513      * to allowFilesOpenedByPreload(). Fatally fails if the FDs are of unsupported type and are not
514      * explicitly allowed. Ignores repeated invocations.
515      *
516      * Inspecting the FDs is more permissive than in forkAndSpecialize() because preload is invoked
517      * earlier and hence needs to allow a few open sockets. The checks in forkAndSpecialize()
518      * enforce that these sockets are closed when forking.
519      */
markOpenedFilesBeforePreload()520     static void markOpenedFilesBeforePreload() {
521         nativeMarkOpenedFilesBeforePreload();
522     }
523 
nativeMarkOpenedFilesBeforePreload()524     private static native void nativeMarkOpenedFilesBeforePreload();
525 
526     /**
527      * By scanning /proc/self/fd/ determines file descriptor numbers in this process opened since
528      * the first call to markOpenedFilesBeforePreload(). These FDs are treated as 'owned' by the
529      * custom preload of the App Zygote - the app is responsible for not sharing data with its other
530      * processes using these FDs, including by lseek(2). File descriptor types and file names are
531      * not checked. Changes in FDs recorded by markOpenedFilesBeforePreload() are not expected and
532      * kill the current process.
533      */
allowFilesOpenedByPreload()534     static void allowFilesOpenedByPreload() {
535         nativeAllowFilesOpenedByPreload();
536     }
537 
nativeAllowFilesOpenedByPreload()538     private static native void nativeAllowFilesOpenedByPreload();
539 
540     /**
541      * Installs a seccomp filter that limits setresuid()/setresgid() to the passed-in range
542      * @param uidGidMin The smallest allowed uid/gid
543      * @param uidGidMax The largest allowed uid/gid
544      */
nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax)545     native protected static void nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax);
546 
547     /**
548      * Initialize the native state of the Zygote.  This inclues
549      *   - Fetching socket FDs from the environment
550      *   - Initializing security properties
551      *   - Unmounting storage as appropriate
552      *   - Loading necessary performance profile information
553      *
554      * @param isPrimary  True if this is the zygote process, false if it is zygote_secondary
555      */
initNativeState(boolean isPrimary)556     static void initNativeState(boolean isPrimary) {
557         nativeInitNativeState(isPrimary);
558     }
559 
nativeInitNativeState(boolean isPrimary)560     protected static native void nativeInitNativeState(boolean isPrimary);
561 
562     /**
563      * Returns the raw string value of a system property.
564      *
565      * Note that Device Config is not available without an application so SystemProperties is used
566      * instead.
567      *
568      * TODO (chriswailes): Cache the system property location in native code and then write a JNI
569      *                     function to fetch it.
570      */
getConfigurationProperty(String propertyName, String defaultValue)571     public static String getConfigurationProperty(String propertyName, String defaultValue) {
572         return SystemProperties.get(
573                 String.join(".",
574                         "persist.device_config",
575                         DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
576                         propertyName),
577                 defaultValue);
578     }
579 
emptyUsapPool()580     static void emptyUsapPool() {
581         nativeEmptyUsapPool();
582     }
583 
nativeEmptyUsapPool()584     private static native void nativeEmptyUsapPool();
585 
586     /**
587      * Returns the value of a system property converted to a boolean using specific logic.
588      *
589      * Note that Device Config is not available without an application so SystemProperties is used
590      * instead.
591      *
592      * @see SystemProperties#getBoolean
593      *
594      * TODO (chriswailes): Cache the system property location in native code and then write a JNI
595      *                     function to fetch it.
596      * TODO (chriswailes): Move into ZygoteConfig.java once the necessary CL lands (go/ag/6580627)
597      */
getConfigurationPropertyBoolean( String propertyName, Boolean defaultValue)598     public static boolean getConfigurationPropertyBoolean(
599             String propertyName, Boolean defaultValue) {
600         return SystemProperties.getBoolean(
601                 String.join(".",
602                         "persist.device_config",
603                         DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
604                         propertyName),
605                 defaultValue);
606     }
607 
608     /**
609      * @return Number of unspecialized app processes currently in the pool
610      */
getUsapPoolCount()611     static int getUsapPoolCount() {
612         return nativeGetUsapPoolCount();
613     }
614 
nativeGetUsapPoolCount()615     private static native int nativeGetUsapPoolCount();
616 
617     /**
618      * @return The event FD used for communication between the signal handler and the ZygoteServer
619      *         poll loop
620      */
getUsapPoolEventFD()621     static FileDescriptor getUsapPoolEventFD() {
622         FileDescriptor fd = new FileDescriptor();
623         fd.setInt$(nativeGetUsapPoolEventFD());
624 
625         return fd;
626     }
627 
nativeGetUsapPoolEventFD()628     private static native int nativeGetUsapPoolEventFD();
629 
630     /**
631      * Fork a new unspecialized app process from the zygote. Adds the Usap to the native
632      * Usap table.
633      *
634      * @param usapPoolSocket  The server socket the USAP will call accept on
635      * @param sessionSocketRawFDs  Anonymous session sockets that are currently open.
636      *         These are closed in the child.
637      * @param isPriorityFork Raise the initial process priority level because this is on the
638      *         critical path for application startup.
639      * @return In the child process, this returns a Runnable that waits for specialization
640      *         info to start an app process. In the sygote/parent process this returns null.
641      */
forkUsap(LocalServerSocket usapPoolSocket, int[] sessionSocketRawFDs, boolean isPriorityFork)642     static @Nullable Runnable forkUsap(LocalServerSocket usapPoolSocket,
643                                        int[] sessionSocketRawFDs,
644                                        boolean isPriorityFork) {
645         FileDescriptor readFD;
646         FileDescriptor writeFD;
647 
648         try {
649             FileDescriptor[] pipeFDs = Os.pipe2(O_CLOEXEC);
650             readFD = pipeFDs[0];
651             writeFD = pipeFDs[1];
652         } catch (ErrnoException errnoEx) {
653             throw new IllegalStateException("Unable to create USAP pipe.", errnoEx);
654         }
655 
656         int pid = nativeForkApp(readFD.getInt$(), writeFD.getInt$(),
657                                 sessionSocketRawFDs, /*argsKnown=*/ false, isPriorityFork);
658         if (pid == 0) {
659             IoUtils.closeQuietly(readFD);
660             return childMain(null, usapPoolSocket, writeFD);
661         } else if (pid == -1) {
662             // Fork failed.
663             return null;
664         } else {
665             // readFD will be closed by the native code. See removeUsapTableEntry();
666             IoUtils.closeQuietly(writeFD);
667             nativeAddUsapTableEntry(pid, readFD.getInt$());
668             return null;
669         }
670     }
671 
nativeForkApp(int readPipeFD, int writePipeFD, int[] sessionSocketRawFDs, boolean argsKnown, boolean isPriorityFork)672     private static native int nativeForkApp(int readPipeFD,
673                                             int writePipeFD,
674                                             int[] sessionSocketRawFDs,
675                                             boolean argsKnown,
676                                             boolean isPriorityFork);
677 
678     /**
679      * Add an entry for a new Usap to the table maintained in native code.
680      */
681     @CriticalNative
nativeAddUsapTableEntry(int pid, int readPipeFD)682     private static native void nativeAddUsapTableEntry(int pid, int readPipeFD);
683 
684     /**
685      * Fork a new app process from the zygote. argBuffer contains a fork command that
686      * request neither a child zygote, nor a wrapped process. Continue to accept connections
687      * on the specified socket, use those to refill argBuffer, and continue to process
688      * sufficiently simple fork requests. We presume that the only open file descriptors
689      * requiring special treatment are the session socket embedded in argBuffer, and
690      * zygoteSocket.
691      * @param argBuffer containing initial command and the connected socket from which to
692      *         read more
693      * @param zygoteSocket socket from which to obtain new connections when current argBuffer
694      *         one is disconnected
695      * @param expectedUId Uid of peer for initial requests. Subsequent requests from a different
696      *               peer will cause us to return rather than perform the requested fork.
697      * @param minUid Minimum Uid enforced for all but first fork request. The caller checks
698      *               the Uid policy for the initial request.
699      * @param firstNiceName name of first created process. Used for error reporting only.
700      * @return A Runnable in each child process, null in the parent.
701      * If this returns in then argBuffer still contains a command needing to be executed.
702      */
forkSimpleApps(@onNull ZygoteCommandBuffer argBuffer, @NonNull FileDescriptor zygoteSocket, int expectedUid, int minUid, @Nullable String firstNiceName)703     static @Nullable Runnable forkSimpleApps(@NonNull ZygoteCommandBuffer argBuffer,
704                                              @NonNull FileDescriptor zygoteSocket,
705                                              int expectedUid,
706                                              int minUid,
707                                              @Nullable String firstNiceName) {
708         boolean in_child =
709                 argBuffer.forkRepeatedly(zygoteSocket, expectedUid, minUid, firstNiceName);
710         if (in_child) {
711             return childMain(argBuffer, /*usapPoolSocket=*/null, /*writePipe=*/null);
712         } else {
713             return null;
714         }
715     }
716 
717     /**
718      * Specialize the current process into one described by argBuffer or the command read from
719      * usapPoolSocket. Exactly one of those must be null. If we are given an argBuffer, we close
720      * it. Used both for a specializing a USAP process, and for process creation without USAPs.
721      * In both cases, we specialize the process after first returning to Java code.
722      *
723      * @param writePipe  The write end of the reporting pipe used to communicate with the poll loop
724      *                   of the ZygoteServer.
725      * @return A runnable oject representing the new application.
726      */
childMain(@ullable ZygoteCommandBuffer argBuffer, @Nullable LocalServerSocket usapPoolSocket, FileDescriptor writePipe)727     private static Runnable childMain(@Nullable ZygoteCommandBuffer argBuffer,
728                                       @Nullable LocalServerSocket usapPoolSocket,
729                                       FileDescriptor writePipe) {
730         final int pid = Process.myPid();
731 
732         DataOutputStream usapOutputStream = null;
733         ZygoteArguments args = null;
734 
735         LocalSocket sessionSocket = null;
736         if (argBuffer == null) {
737             // Read arguments from usapPoolSocket instead.
738 
739             Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
740 
741             // Change the priority to max before calling accept so we can respond to new
742             // specialization requests as quickly as possible.  This will be reverted to the
743             // default priority in the native specialization code.
744             boostUsapPriority();
745 
746             while (true) {
747                 ZygoteCommandBuffer tmpArgBuffer = null;
748                 try {
749                     sessionSocket = usapPoolSocket.accept();
750                     // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
751                     // This is safe from a race condition because the pool is only flushed after
752                     // the SystemServer changes its internal state to stop using the USAP pool.
753                     blockSigTerm();
754 
755                     usapOutputStream =
756                             new DataOutputStream(sessionSocket.getOutputStream());
757                     Credentials peerCredentials = sessionSocket.getPeerCredentials();
758                     tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket);
759                     args = ZygoteArguments.getInstance(tmpArgBuffer);
760                     applyUidSecurityPolicy(args, peerCredentials);
761                     // TODO (chriswailes): Should this only be run for debug builds?
762                     validateUsapCommand(args);
763                     break;
764                 } catch (Exception ex) {
765                     Log.e("USAP", ex.getMessage());
766                 }
767                 // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary.
768                 unblockSigTerm();
769                 IoUtils.closeQuietly(sessionSocket);
770                 IoUtils.closeQuietly(tmpArgBuffer);
771             }
772         } else {
773             // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool.
774             blockSigTerm();
775             try {
776                 args = ZygoteArguments.getInstance(argBuffer);
777             } catch (Exception ex) {
778                 Log.e("AppStartup", ex.getMessage());
779                 throw new AssertionError("Failed to parse application start command", ex);
780             }
781             // peerCredentials were checked in parent.
782         }
783         if (args == null) {
784             throw new AssertionError("Empty command line");
785         }
786         try {
787             // SIGTERM is blocked here.  This prevents a USAP that is specializing from being
788             // killed during a pool flush.
789 
790             applyDebuggerSystemProperty(args);
791 
792             int[][] rlimits = null;
793 
794             if (args.mRLimits != null) {
795                 rlimits = args.mRLimits.toArray(INT_ARRAY_2D);
796             }
797 
798             if (argBuffer == null) {
799                 // This must happen before the SELinux policy for this process is
800                 // changed when specializing.
801                 try {
802                     // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a
803                     // Process.ProcessStartResult object.
804                     usapOutputStream.writeInt(pid);
805                 } catch (IOException ioEx) {
806                     Log.e("USAP", "Failed to write response to session socket: "
807                             + ioEx.getMessage());
808                     throw new RuntimeException(ioEx);
809                 } finally {
810                     try {
811                         // Since the raw FD is created by init and then loaded from an environment
812                         // variable (as opposed to being created by the LocalSocketImpl itself),
813                         // the LocalSocket/LocalSocketImpl does not own the Os-level socket. See
814                         // the spec for LocalSocket.createConnectedLocalSocket(FileDescriptor fd).
815                         // Thus closing the LocalSocket does not suffice. See b/130309968 for more
816                         // discussion.
817                         FileDescriptor fd = usapPoolSocket.getFileDescriptor();
818                         usapPoolSocket.close();
819                         Os.close(fd);
820                     } catch (ErrnoException | IOException ex) {
821                         Log.e("USAP", "Failed to close USAP pool socket");
822                         throw new RuntimeException(ex);
823                     }
824                 }
825             }
826 
827             if (writePipe != null) {
828                 try {
829                     ByteArrayOutputStream buffer =
830                             new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES);
831                     DataOutputStream outputStream = new DataOutputStream(buffer);
832 
833                     // This is written as a long so that the USAP reporting pipe and USAP pool
834                     // event FD handlers in ZygoteServer.runSelectLoop can be unified.  These two
835                     // cases should both send/receive 8 bytes.
836                     // TODO: Needs tweaking to handle the non-Usap invoke-with case, which expects
837                     // a different format.
838                     outputStream.writeLong(pid);
839                     outputStream.flush();
840                     Os.write(writePipe, buffer.toByteArray(), 0, buffer.size());
841                 } catch (Exception ex) {
842                     Log.e("USAP",
843                             String.format("Failed to write PID (%d) to pipe (%d): %s",
844                                     pid, writePipe.getInt$(), ex.getMessage()));
845                     throw new RuntimeException(ex);
846                 } finally {
847                     IoUtils.closeQuietly(writePipe);
848                 }
849             }
850 
851             specializeAppProcess(args.mUid, args.mGid, args.mGids,
852                                  args.mRuntimeFlags, rlimits, args.mMountExternal,
853                                  args.mSeInfo, args.mNiceName, args.mStartChildZygote,
854                                  args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
855                                  args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
856                                  args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
857 
858             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
859 
860             return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
861                                          args.mDisabledCompatChanges,
862                                          args.mRemainingArgs,
863                                          null /* classLoader */);
864         } finally {
865             // Unblock SIGTERM to restore the process to default behavior.
866             unblockSigTerm();
867         }
868     }
869 
blockSigTerm()870     private static void blockSigTerm() {
871         nativeBlockSigTerm();
872     }
873 
nativeBlockSigTerm()874     private static native void nativeBlockSigTerm();
875 
unblockSigTerm()876     private static void unblockSigTerm() {
877         nativeUnblockSigTerm();
878     }
879 
nativeUnblockSigTerm()880     private static native void nativeUnblockSigTerm();
881 
boostUsapPriority()882     private static void boostUsapPriority() {
883         nativeBoostUsapPriority();
884     }
885 
nativeBoostUsapPriority()886     private static native void nativeBoostUsapPriority();
887 
setAppProcessName(ZygoteArguments args, String loggingTag)888     static void setAppProcessName(ZygoteArguments args, String loggingTag) {
889         if (args.mNiceName != null) {
890             Process.setArgV0(args.mNiceName);
891         } else if (args.mPackageName != null) {
892             Process.setArgV0(args.mPackageName);
893         } else {
894             Log.w(loggingTag, "Unable to set package name.");
895         }
896     }
897 
898     private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: ";
899 
900     /**
901      * Checks a set of zygote arguments to see if they can be handled by a USAP.  Throws an
902      * exception if an invalid arugment is encountered.
903      * @param args  The arguments to test
904      */
validateUsapCommand(ZygoteArguments args)905     private static void validateUsapCommand(ZygoteArguments args) {
906         if (args.mAbiListQuery) {
907             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--query-abi-list");
908         } else if (args.mPidQuery) {
909             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--get-pid");
910         } else if (args.mPreloadDefault) {
911             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-default");
912         } else if (args.mPreloadPackage != null) {
913             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-package");
914         } else if (args.mPreloadApp != null) {
915             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--preload-app");
916         } else if (args.mStartChildZygote) {
917             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote");
918         } else if (args.mApiDenylistExemptions != null) {
919             throw new IllegalArgumentException(
920                     USAP_ERROR_PREFIX + "--set-api-denylist-exemptions");
921         } else if (args.mHiddenApiAccessLogSampleRate != -1) {
922             throw new IllegalArgumentException(
923                     USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
924         } else if (args.mHiddenApiAccessStatslogSampleRate != -1) {
925             throw new IllegalArgumentException(
926                     USAP_ERROR_PREFIX + "--hidden-api-statslog-sampling-rate=");
927         } else if (args.mInvokeWith != null) {
928             throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--invoke-with");
929         } else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) {
930             throw new ZygoteSecurityException("Client may not specify capabilities: "
931                 + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities)
932                 + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities));
933         }
934     }
935 
936     /**
937      * @return  Raw file descriptors for the read-end of USAP reporting pipes.
938      */
getUsapPipeFDs()939     static int[] getUsapPipeFDs() {
940         return nativeGetUsapPipeFDs();
941     }
942 
nativeGetUsapPipeFDs()943     private static native int[] nativeGetUsapPipeFDs();
944 
945     /**
946      * Remove the USAP table entry for the provided process ID.
947      *
948      * @param usapPID  Process ID of the entry to remove
949      * @return True if the entry was removed; false if it doesn't exist
950      */
removeUsapTableEntry(int usapPID)951     static boolean removeUsapTableEntry(int usapPID) {
952         return nativeRemoveUsapTableEntry(usapPID);
953     }
954 
955     @CriticalNative
nativeRemoveUsapTableEntry(int usapPID)956     private static native boolean nativeRemoveUsapTableEntry(int usapPID);
957 
958     /**
959      * Return the minimum child uid that the given peer is allowed to create.
960      * uid 1000 (Process.SYSTEM_UID) may specify any uid &ge; 1000 in normal
961      * operation. It may also specify any gid and setgroups() list it chooses.
962      * In factory test mode, it may specify any UID.
963      */
minChildUid(Credentials peer)964     static int minChildUid(Credentials peer) {
965         if (peer.getUid() == Process.SYSTEM_UID
966                 && FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF) {
967             /* In normal operation, SYSTEM_UID can only specify a restricted
968              * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid.
969              */
970             return Process.SYSTEM_UID;
971         } else {
972             return 0;
973         }
974     }
975 
976     /*
977      * Adjust uid and gid arguments, ensuring that the security policy is satisfied.
978      * @param args non-null; zygote spawner arguments
979      * @param peer non-null; peer credentials
980      * @throws ZygoteSecurityException Indicates a security issue when applying the UID based
981      *  security policies
982      */
applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)983     static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer)
984             throws ZygoteSecurityException {
985 
986         if (args.mUidSpecified && (args.mUid < minChildUid(peer))) {
987             throw new ZygoteSecurityException(
988                     "System UID may not launch process with UID < "
989                     + Process.SYSTEM_UID);
990         }
991 
992         // If not otherwise specified, uid and gid are inherited from peer
993         if (!args.mUidSpecified) {
994             args.mUid = peer.getUid();
995             args.mUidSpecified = true;
996         }
997         if (!args.mGidSpecified) {
998             args.mGid = peer.getGid();
999             args.mGidSpecified = true;
1000         }
1001     }
1002 
1003     /**
1004      * Applies debugger system properties to the zygote arguments.
1005      *
1006      * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
1007      * the debugger state is specified via the "--enable-jdwp" flag
1008      * in the spawn request.
1009      *
1010      * @param args non-null; zygote spawner args
1011      */
applyDebuggerSystemProperty(ZygoteArguments args)1012     static void applyDebuggerSystemProperty(ZygoteArguments args) {
1013         if (RoSystemProperties.DEBUGGABLE) {
1014             args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
1015         }
1016     }
1017 
1018     /**
1019      * Applies zygote security policy.
1020      * Based on the credentials of the process issuing a zygote command:
1021      * <ol>
1022      * <li> uid 0 (root) may specify --invoke-with to launch Zygote with a
1023      * wrapper command.
1024      * <li> Any other uid may not specify any invoke-with argument.
1025      * </ul>
1026      *
1027      * @param args non-null; zygote spawner arguments
1028      * @param peer non-null; peer credentials
1029      * @throws ZygoteSecurityException Thrown when `--invoke-with` is specified for a non-debuggable
1030      *  application.
1031      */
applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer)1032     static void applyInvokeWithSecurityPolicy(ZygoteArguments args, Credentials peer)
1033             throws ZygoteSecurityException {
1034         int peerUid = peer.getUid();
1035 
1036         if (args.mInvokeWith != null && peerUid != 0
1037                 && (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
1038             throw new ZygoteSecurityException("Peer is permitted to specify an "
1039                 + "explicit invoke-with wrapper command only for debuggable "
1040                 + "applications.");
1041         }
1042     }
1043 
1044     /**
1045      * Gets the wrap property if set.
1046      *
1047      * @param appName the application name to check
1048      * @return value of wrap property or null if property not set or
1049      * null if app_name is null or null if app_name is empty
1050      */
getWrapProperty(String appName)1051     public static String getWrapProperty(String appName) {
1052         if (appName == null || appName.isEmpty()) {
1053             return null;
1054         }
1055 
1056         String propertyValue = SystemProperties.get("wrap." + appName);
1057         if (propertyValue != null && !propertyValue.isEmpty()) {
1058             return propertyValue;
1059         }
1060         return null;
1061     }
1062 
1063     /**
1064      * Applies invoke-with system properties to the zygote arguments.
1065      *
1066      * @param args non-null; zygote args
1067      */
applyInvokeWithSystemProperty(ZygoteArguments args)1068     static void applyInvokeWithSystemProperty(ZygoteArguments args) {
1069         if (args.mInvokeWith == null) {
1070             args.mInvokeWith = getWrapProperty(args.mNiceName);
1071         }
1072     }
1073 
1074     /**
1075      * Creates a managed LocalServerSocket object using a file descriptor
1076      * created by an init.rc script.  The init scripts that specify the
1077      * sockets name can be found in system/core/rootdir.  The socket is bound
1078      * to the file system in the /dev/sockets/ directory, and the file
1079      * descriptor is shared via the ANDROID_SOCKET_<socketName> environment
1080      * variable.
1081      */
createManagedSocketFromInitSocket(String socketName)1082     static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
1083         int fileDesc;
1084         final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
1085 
1086         try {
1087             String env = System.getenv(fullSocketName);
1088             fileDesc = Integer.parseInt(env);
1089         } catch (RuntimeException ex) {
1090             throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
1091         }
1092 
1093         try {
1094             FileDescriptor fd = new FileDescriptor();
1095             fd.setInt$(fileDesc);
1096             return new LocalServerSocket(fd);
1097         } catch (IOException ex) {
1098             throw new RuntimeException(
1099                 "Error building socket from file descriptor: " + fileDesc, ex);
1100         }
1101     }
1102 
1103     // This function is called from native code in com_android_internal_os_Zygote.cpp
1104     @SuppressWarnings("unused")
callPostForkSystemServerHooks(int runtimeFlags)1105     private static void callPostForkSystemServerHooks(int runtimeFlags) {
1106         // SystemServer specific post fork hooks run before child post fork hooks.
1107         ZygoteHooks.postForkSystemServer(runtimeFlags);
1108     }
1109 
1110     // This function is called from native code in com_android_internal_os_Zygote.cpp
1111     @SuppressWarnings("unused")
callPostForkChildHooks(int runtimeFlags, boolean isSystemServer, boolean isZygote, String instructionSet)1112     private static void callPostForkChildHooks(int runtimeFlags, boolean isSystemServer,
1113             boolean isZygote, String instructionSet) {
1114         ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
1115     }
1116 
1117     /**
1118      * Executes "/system/bin/sh -c &lt;command&gt;" using the exec() system call.
1119      * This method throws a runtime exception if exec() failed, otherwise, this
1120      * method never returns.
1121      *
1122      * @param command The shell command to execute.
1123      */
execShell(String command)1124     static void execShell(String command) {
1125         String[] args = { "/system/bin/sh", "-c", command };
1126         try {
1127             Os.execv(args[0], args);
1128         } catch (ErrnoException e) {
1129             throw new RuntimeException(e);
1130         }
1131     }
1132 
1133     /**
1134      * Appends quotes shell arguments to the specified string builder.
1135      * The arguments are quoted using single-quotes, escaped if necessary,
1136      * prefixed with a space, and appended to the command.
1137      *
1138      * @param command A string builder for the shell command being constructed.
1139      * @param args An array of argument strings to be quoted and appended to the command.
1140      * @see #execShell(String)
1141      */
appendQuotedShellArgs(StringBuilder command, String[] args)1142     static void appendQuotedShellArgs(StringBuilder command, String[] args) {
1143         for (String arg : args) {
1144             command.append(" '").append(arg.replace("'", "'\\''")).append("'");
1145         }
1146     }
1147 
1148     /**
1149      * Parse the given unsolicited zygote message as type SIGCHLD,
1150      * extract the payload information into the given output buffer.
1151      *
1152      * @param in The unsolicited zygote message to be parsed
1153      * @param length The number of bytes in the message
1154      * @param out The output buffer where the payload information will be placed
1155      * @return Number of elements being place into output buffer, or -1 if
1156      *         either the message is malformed or not the type as expected here.
1157      *
1158      * @hide
1159      */
1160     @FastNative
nativeParseSigChld(byte[] in, int length, int[] out)1161     public static native int nativeParseSigChld(byte[] in, int length, int[] out);
1162 
1163     /**
1164      * Returns whether the hardware supports memory tagging (ARM MTE).
1165      */
nativeSupportsMemoryTagging()1166     public static native boolean nativeSupportsMemoryTagging();
1167 
1168     /**
1169      * Returns whether the kernel supports tagged pointers. Present in the
1170      * Android Common Kernel from 4.14 and up. By default, you should prefer
1171      * fully-feature Memory Tagging, rather than the static Tagged Pointers.
1172      */
nativeSupportsTaggedPointers()1173     public static native boolean nativeSupportsTaggedPointers();
1174 
1175     /**
1176      * Returns the current native tagging level, as one of the
1177      * MEMORY_TAG_LEVEL_* constants. Returns zero if no tagging is present, or
1178      * we failed to determine the level.
1179      */
nativeCurrentTaggingLevel()1180     public static native int nativeCurrentTaggingLevel();
1181 
1182     /**
1183      * Native heap allocations will now have a non-zero tag in the most significant byte.
1184      *
1185      * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
1186      *     Pointers</a>
1187      */
1188     @ChangeId
1189     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
1190     private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
1191 
1192     /**
1193      * Native heap allocations in AppZygote process and its descendants will now have a non-zero tag
1194      * in the most significant byte.
1195      *
1196      * @see <a href="https://source.android.com/devices/tech/debug/tagged-pointers">Tagged
1197      *     Pointers</a>
1198      */
1199     @ChangeId
1200     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.S)
1201     private static final long NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE = 207557677;
1202 
1203     /**
1204      * Enable asynchronous (ASYNC) memory tag checking in this process. This flag will only have an
1205      * effect on hardware supporting the ARM Memory Tagging Extension (MTE).
1206      */
1207     @ChangeId @Disabled
1208     private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id.
1209 
1210     /**
1211      * Enable synchronous (SYNC) memory tag checking in this process. This flag will only have an
1212      * effect on hardware supporting the ARM Memory Tagging Extension (MTE). If both
1213      * NATIVE_MEMTAG_ASYNC and this option is selected, this option takes preference and MTE is
1214      * enabled in SYNC mode.
1215      */
1216     @ChangeId @Disabled
1217     private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id.
1218 
1219     /** Enable automatic zero-initialization of native heap memory allocations. */
1220     @ChangeId @Disabled
1221     private static final long NATIVE_HEAP_ZERO_INIT = 178038272; // This is a bug id.
1222 
1223     /**
1224      * Enable sampled memory bug detection in the app.
1225      *
1226      * @see <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
1227      */
1228     @ChangeId @Disabled private static final long GWP_ASAN = 135634846; // This is a bug id.
1229 
memtagModeToZygoteMemtagLevel(int memtagMode)1230     private static int memtagModeToZygoteMemtagLevel(int memtagMode) {
1231         switch (memtagMode) {
1232             case ApplicationInfo.MEMTAG_ASYNC:
1233                 return MEMORY_TAG_LEVEL_ASYNC;
1234             case ApplicationInfo.MEMTAG_SYNC:
1235                 return MEMORY_TAG_LEVEL_SYNC;
1236             default:
1237                 return MEMORY_TAG_LEVEL_NONE;
1238         }
1239     }
1240 
isCompatChangeEnabled( long change, @NonNull ApplicationInfo info, @Nullable IPlatformCompat platformCompat, int enabledAfter)1241     private static boolean isCompatChangeEnabled(
1242             long change,
1243             @NonNull ApplicationInfo info,
1244             @Nullable IPlatformCompat platformCompat,
1245             int enabledAfter) {
1246         try {
1247             if (platformCompat != null) return platformCompat.isChangeEnabled(change, info);
1248         } catch (RemoteException ignore) {
1249         }
1250         return enabledAfter > 0 && info.targetSdkVersion > enabledAfter;
1251     }
1252 
1253     // Returns the requested memory tagging level.
getRequestedMemtagLevel( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1254     private static int getRequestedMemtagLevel(
1255             @NonNull ApplicationInfo info,
1256             @Nullable ProcessInfo processInfo,
1257             @Nullable IPlatformCompat platformCompat) {
1258         // Look at the process attribute first.
1259         if (processInfo != null && processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) {
1260             return memtagModeToZygoteMemtagLevel(processInfo.memtagMode);
1261         }
1262 
1263         // Then at the application attribute.
1264         if (info.getMemtagMode() != ApplicationInfo.MEMTAG_DEFAULT) {
1265             return memtagModeToZygoteMemtagLevel(info.getMemtagMode());
1266         }
1267 
1268         if (isCompatChangeEnabled(NATIVE_MEMTAG_SYNC, info, platformCompat, 0)) {
1269             return MEMORY_TAG_LEVEL_SYNC;
1270         }
1271 
1272         if (isCompatChangeEnabled(NATIVE_MEMTAG_ASYNC, info, platformCompat, 0)) {
1273             return MEMORY_TAG_LEVEL_ASYNC;
1274         }
1275 
1276         // Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute.
1277         if (!info.allowsNativeHeapPointerTagging()) {
1278             return MEMORY_TAG_LEVEL_NONE;
1279         }
1280 
1281         String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
1282         if ("sync".equals(defaultLevel)) {
1283             return MEMORY_TAG_LEVEL_SYNC;
1284         } else if ("async".equals(defaultLevel)) {
1285             return MEMORY_TAG_LEVEL_ASYNC;
1286         }
1287 
1288         // Check to see that the compat feature for TBI is enabled.
1289         if (isCompatChangeEnabled(
1290                 NATIVE_HEAP_POINTER_TAGGING, info, platformCompat, Build.VERSION_CODES.Q)) {
1291             return MEMORY_TAG_LEVEL_TBI;
1292         }
1293 
1294         return MEMORY_TAG_LEVEL_NONE;
1295     }
1296 
decideTaggingLevel( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1297     private static int decideTaggingLevel(
1298             @NonNull ApplicationInfo info,
1299             @Nullable ProcessInfo processInfo,
1300             @Nullable IPlatformCompat platformCompat) {
1301         // Get the desired tagging level (app manifest + compat features).
1302         int level = getRequestedMemtagLevel(info, processInfo, platformCompat);
1303 
1304         // Take into account the hardware capabilities.
1305         if (nativeSupportsMemoryTagging()) {
1306             // MTE devices can not do TBI, because the Zygote process already has live MTE
1307             // allocations. Downgrade TBI to NONE.
1308             if (level == MEMORY_TAG_LEVEL_TBI) {
1309                 level = MEMORY_TAG_LEVEL_NONE;
1310             }
1311         } else if (nativeSupportsTaggedPointers()) {
1312             // TBI-but-not-MTE devices downgrade MTE modes to TBI.
1313             // The idea is that if an app opts into full hardware tagging (MTE), it must be ok with
1314             // the "fake" pointer tagging (TBI).
1315             if (level == MEMORY_TAG_LEVEL_ASYNC || level == MEMORY_TAG_LEVEL_SYNC) {
1316                 level = MEMORY_TAG_LEVEL_TBI;
1317             }
1318         } else {
1319             // Otherwise disable all tagging.
1320             level = MEMORY_TAG_LEVEL_NONE;
1321         }
1322 
1323         return level;
1324     }
1325 
decideGwpAsanLevel( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1326     private static int decideGwpAsanLevel(
1327             @NonNull ApplicationInfo info,
1328             @Nullable ProcessInfo processInfo,
1329             @Nullable IPlatformCompat platformCompat) {
1330         // Look at the process attribute first.
1331         if (processInfo != null && processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) {
1332             return processInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_ALWAYS
1333                     ? GWP_ASAN_LEVEL_ALWAYS
1334                     : GWP_ASAN_LEVEL_NEVER;
1335         }
1336         // Then at the application attribute.
1337         if (info.getGwpAsanMode() != ApplicationInfo.GWP_ASAN_DEFAULT) {
1338             return info.getGwpAsanMode() == ApplicationInfo.GWP_ASAN_ALWAYS
1339                     ? GWP_ASAN_LEVEL_ALWAYS
1340                     : GWP_ASAN_LEVEL_NEVER;
1341         }
1342         // If the app does not specify gwpAsanMode, the default behavior is lottery among the
1343         // system apps, and disabled for user apps, unless overwritten by the compat feature.
1344         if (isCompatChangeEnabled(GWP_ASAN, info, platformCompat, 0)) {
1345             return GWP_ASAN_LEVEL_ALWAYS;
1346         }
1347         if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
1348             return GWP_ASAN_LEVEL_LOTTERY;
1349         }
1350         return GWP_ASAN_LEVEL_NEVER;
1351     }
1352 
enableNativeHeapZeroInit( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable IPlatformCompat platformCompat)1353     private static boolean enableNativeHeapZeroInit(
1354             @NonNull ApplicationInfo info,
1355             @Nullable ProcessInfo processInfo,
1356             @Nullable IPlatformCompat platformCompat) {
1357         // Look at the process attribute first.
1358         if (processInfo != null
1359                 && processInfo.nativeHeapZeroInitialized != ApplicationInfo.ZEROINIT_DEFAULT) {
1360             return processInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_ENABLED;
1361         }
1362         // Then at the application attribute.
1363         if (info.getNativeHeapZeroInitialized() != ApplicationInfo.ZEROINIT_DEFAULT) {
1364             return info.getNativeHeapZeroInitialized() == ApplicationInfo.ZEROINIT_ENABLED;
1365         }
1366         // Compat feature last.
1367         if (isCompatChangeEnabled(NATIVE_HEAP_ZERO_INIT, info, platformCompat, 0)) {
1368             return true;
1369         }
1370         return false;
1371     }
1372 
1373     /**
1374      * Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit)
1375      * for a given app.
1376      */
getMemorySafetyRuntimeFlags( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo, @Nullable String instructionSet, @Nullable IPlatformCompat platformCompat)1377     public static int getMemorySafetyRuntimeFlags(
1378             @NonNull ApplicationInfo info,
1379             @Nullable ProcessInfo processInfo,
1380             @Nullable String instructionSet,
1381             @Nullable IPlatformCompat platformCompat) {
1382         int runtimeFlags = decideGwpAsanLevel(info, processInfo, platformCompat);
1383         // If instructionSet is non-null, this indicates that the system_server is spawning a
1384         // process with an ISA that may be different from its own. System (kernel and hardware)
1385         // compatibility for these features is checked in the decideTaggingLevel in the
1386         // system_server process (not the child process). As both MTE and TBI are only supported
1387         // in aarch64, we can simply ensure that the new process is also aarch64. This prevents
1388         // the mismatch where a 64-bit system server spawns a 32-bit child that thinks it should
1389         // enable some tagging variant. Theoretically, a 32-bit system server could exist that
1390         // spawns 64-bit processes, in which case the new process won't get any tagging. This is
1391         // fine as we haven't seen this configuration in practice, and we can reasonable assume
1392         // that if tagging is desired, the system server will be 64-bit.
1393         if (instructionSet == null || instructionSet.equals("arm64")) {
1394             runtimeFlags |= decideTaggingLevel(info, processInfo, platformCompat);
1395         }
1396         if (enableNativeHeapZeroInit(info, processInfo, platformCompat)) {
1397             runtimeFlags |= NATIVE_HEAP_ZERO_INIT_ENABLED;
1398         }
1399         return runtimeFlags;
1400     }
1401 
1402     /**
1403      * Returns Zygote runtimeFlags for memory safety features (MTE, GWP-ASan, nativeHeadZeroInit)
1404      * for a secondary zygote (AppZygote or WebViewZygote).
1405      */
getMemorySafetyRuntimeFlagsForSecondaryZygote( @onNull ApplicationInfo info, @Nullable ProcessInfo processInfo)1406     public static int getMemorySafetyRuntimeFlagsForSecondaryZygote(
1407             @NonNull ApplicationInfo info, @Nullable ProcessInfo processInfo) {
1408         final IPlatformCompat platformCompat =
1409                 IPlatformCompat.Stub.asInterface(
1410                         ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
1411         int runtimeFlags =
1412                 getMemorySafetyRuntimeFlags(
1413                         info, processInfo, null /*instructionSet*/, platformCompat);
1414 
1415         // TBI ("fake" pointer tagging) in AppZygote is controlled by a separate compat feature.
1416         if ((runtimeFlags & MEMORY_TAG_LEVEL_MASK) == MEMORY_TAG_LEVEL_TBI
1417                 && isCompatChangeEnabled(
1418                         NATIVE_HEAP_POINTER_TAGGING_SECONDARY_ZYGOTE,
1419                         info,
1420                         platformCompat,
1421                         Build.VERSION_CODES.S)) {
1422             // Reset memory tag level to NONE.
1423             runtimeFlags &= ~MEMORY_TAG_LEVEL_MASK;
1424             runtimeFlags |= MEMORY_TAG_LEVEL_NONE;
1425         }
1426         return runtimeFlags;
1427     }
1428 }
1429