1 /*
2  * Copyright (C) 2016 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 android.os;
18 
19 import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
20 import static android.os.Process.ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.content.pm.ApplicationInfo;
26 import android.net.LocalSocket;
27 import android.net.LocalSocketAddress;
28 import android.util.Log;
29 import android.util.Pair;
30 import android.util.Slog;
31 
32 import com.android.internal.annotations.GuardedBy;
33 import com.android.internal.os.Zygote;
34 import com.android.internal.os.ZygoteConfig;
35 
36 import java.io.BufferedWriter;
37 import java.io.DataInputStream;
38 import java.io.IOException;
39 import java.io.OutputStreamWriter;
40 import java.nio.charset.StandardCharsets;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Base64;
44 import java.util.Collections;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.UUID;
48 
49 /*package*/ class ZygoteStartFailedEx extends Exception {
50     @UnsupportedAppUsage
ZygoteStartFailedEx(String s)51     ZygoteStartFailedEx(String s) {
52         super(s);
53     }
54 
55     @UnsupportedAppUsage
ZygoteStartFailedEx(Throwable cause)56     ZygoteStartFailedEx(Throwable cause) {
57         super(cause);
58     }
59 
ZygoteStartFailedEx(String s, Throwable cause)60     ZygoteStartFailedEx(String s, Throwable cause) {
61         super(s, cause);
62     }
63 }
64 
65 /**
66  * Maintains communication state with the zygote processes. This class is responsible
67  * for the sockets opened to the zygotes and for starting processes on behalf of the
68  * {@link android.os.Process} class.
69  *
70  * {@hide}
71  */
72 public class ZygoteProcess {
73 
74     private static final int ZYGOTE_CONNECT_TIMEOUT_MS = 60000;
75 
76     /**
77      * Use a relatively short delay, because for app zygote, this is in the critical path of
78      * service launch.
79      */
80     private static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
81 
82     private static final String LOG_TAG = "ZygoteProcess";
83 
84     /**
85      * The name of the socket used to communicate with the primary zygote.
86      */
87     private final LocalSocketAddress mZygoteSocketAddress;
88 
89     /**
90      * The name of the secondary (alternate ABI) zygote socket.
91      */
92     private final LocalSocketAddress mZygoteSecondarySocketAddress;
93 
94     /**
95      * The name of the socket used to communicate with the primary USAP pool.
96      */
97     private final LocalSocketAddress mUsapPoolSocketAddress;
98 
99     /**
100      * The name of the socket used to communicate with the secondary (alternate ABI) USAP pool.
101      */
102     private final LocalSocketAddress mUsapPoolSecondarySocketAddress;
103 
ZygoteProcess()104     public ZygoteProcess() {
105         mZygoteSocketAddress =
106                 new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME,
107                                        LocalSocketAddress.Namespace.RESERVED);
108         mZygoteSecondarySocketAddress =
109                 new LocalSocketAddress(Zygote.SECONDARY_SOCKET_NAME,
110                                        LocalSocketAddress.Namespace.RESERVED);
111 
112         mUsapPoolSocketAddress =
113                 new LocalSocketAddress(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME,
114                                        LocalSocketAddress.Namespace.RESERVED);
115         mUsapPoolSecondarySocketAddress =
116                 new LocalSocketAddress(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME,
117                                        LocalSocketAddress.Namespace.RESERVED);
118 
119         // This constructor is used to create the primary and secondary Zygotes, which can support
120         // Unspecialized App Process Pools.
121         mUsapPoolSupported = true;
122     }
123 
ZygoteProcess(LocalSocketAddress primarySocketAddress, LocalSocketAddress secondarySocketAddress)124     public ZygoteProcess(LocalSocketAddress primarySocketAddress,
125                          LocalSocketAddress secondarySocketAddress) {
126         mZygoteSocketAddress = primarySocketAddress;
127         mZygoteSecondarySocketAddress = secondarySocketAddress;
128 
129         mUsapPoolSocketAddress = null;
130         mUsapPoolSecondarySocketAddress = null;
131 
132         // This constructor is used to create the primary and secondary Zygotes, which CAN NOT
133         // support Unspecialized App Process Pools.
134         mUsapPoolSupported = false;
135     }
136 
getPrimarySocketAddress()137     public LocalSocketAddress getPrimarySocketAddress() {
138         return mZygoteSocketAddress;
139     }
140 
141     /**
142      * State for communicating with the zygote process.
143      */
144     private static class ZygoteState implements AutoCloseable {
145         final LocalSocketAddress mZygoteSocketAddress;
146         final LocalSocketAddress mUsapSocketAddress;
147 
148         private final LocalSocket mZygoteSessionSocket;
149 
150         final DataInputStream mZygoteInputStream;
151         final BufferedWriter mZygoteOutputWriter;
152 
153         private final List<String> mAbiList;
154 
155         private boolean mClosed;
156 
ZygoteState(LocalSocketAddress zygoteSocketAddress, LocalSocketAddress usapSocketAddress, LocalSocket zygoteSessionSocket, DataInputStream zygoteInputStream, BufferedWriter zygoteOutputWriter, List<String> abiList)157         private ZygoteState(LocalSocketAddress zygoteSocketAddress,
158                             LocalSocketAddress usapSocketAddress,
159                             LocalSocket zygoteSessionSocket,
160                             DataInputStream zygoteInputStream,
161                             BufferedWriter zygoteOutputWriter,
162                             List<String> abiList) {
163             this.mZygoteSocketAddress = zygoteSocketAddress;
164             this.mUsapSocketAddress = usapSocketAddress;
165             this.mZygoteSessionSocket = zygoteSessionSocket;
166             this.mZygoteInputStream = zygoteInputStream;
167             this.mZygoteOutputWriter = zygoteOutputWriter;
168             this.mAbiList = abiList;
169         }
170 
171         /**
172          * Create a new ZygoteState object by connecting to the given Zygote socket and saving the
173          * given USAP socket address.
174          *
175          * @param zygoteSocketAddress  Zygote socket to connect to
176          * @param usapSocketAddress  USAP socket address to save for later
177          * @return  A new ZygoteState object containing a session socket for the given Zygote socket
178          * address
179          * @throws IOException
180          */
connect(@onNull LocalSocketAddress zygoteSocketAddress, @Nullable LocalSocketAddress usapSocketAddress)181         static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
182                 @Nullable LocalSocketAddress usapSocketAddress)
183                 throws IOException {
184 
185             DataInputStream zygoteInputStream;
186             BufferedWriter zygoteOutputWriter;
187             final LocalSocket zygoteSessionSocket = new LocalSocket();
188 
189             if (zygoteSocketAddress == null) {
190                 throw new IllegalArgumentException("zygoteSocketAddress can't be null");
191             }
192 
193             try {
194                 zygoteSessionSocket.connect(zygoteSocketAddress);
195                 zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
196                 zygoteOutputWriter =
197                         new BufferedWriter(
198                                 new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
199                                 Zygote.SOCKET_BUFFER_SIZE);
200             } catch (IOException ex) {
201                 try {
202                     zygoteSessionSocket.close();
203                 } catch (IOException ignore) { }
204 
205                 throw ex;
206             }
207 
208             return new ZygoteState(zygoteSocketAddress, usapSocketAddress,
209                                    zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter,
210                                    getAbiList(zygoteOutputWriter, zygoteInputStream));
211         }
212 
getUsapSessionSocket()213         LocalSocket getUsapSessionSocket() throws IOException {
214             final LocalSocket usapSessionSocket = new LocalSocket();
215             usapSessionSocket.connect(this.mUsapSocketAddress);
216 
217             return usapSessionSocket;
218         }
219 
matches(String abi)220         boolean matches(String abi) {
221             return mAbiList.contains(abi);
222         }
223 
close()224         public void close() {
225             try {
226                 mZygoteSessionSocket.close();
227             } catch (IOException ex) {
228                 Log.e(LOG_TAG,"I/O exception on routine close", ex);
229             }
230 
231             mClosed = true;
232         }
233 
isClosed()234         boolean isClosed() {
235             return mClosed;
236         }
237     }
238 
239     /**
240      * Lock object to protect access to the two ZygoteStates below. This lock must be
241      * acquired while communicating over the ZygoteState's socket, to prevent
242      * interleaved access.
243      */
244     private final Object mLock = new Object();
245 
246     /**
247      * List of exemptions to the API deny list. These are prefix matches on the runtime format
248      * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
249      * list.
250      */
251     private List<String> mApiDenylistExemptions = Collections.emptyList();
252 
253     /**
254      * Proportion of hidden API accesses that should be logged to the event log; 0 - 0x10000.
255      */
256     private int mHiddenApiAccessLogSampleRate;
257 
258     /**
259      * Proportion of hidden API accesses that should be logged to statslog; 0 - 0x10000.
260      */
261     private int mHiddenApiAccessStatslogSampleRate;
262 
263     /**
264      * The state of the connection to the primary zygote.
265      */
266     private ZygoteState primaryZygoteState;
267 
268     /**
269      * The state of the connection to the secondary zygote.
270      */
271     private ZygoteState secondaryZygoteState;
272 
273     /**
274      * If this Zygote supports the creation and maintenance of a USAP pool.
275      *
276      * Currently only the primary and secondary Zygotes support USAP pools. Any
277      * child Zygotes will be unable to create or use a USAP pool.
278      */
279     private final boolean mUsapPoolSupported;
280 
281     /**
282      * If the USAP pool should be created and used to start applications.
283      *
284      * Setting this value to false will disable the creation, maintenance, and use of the USAP
285      * pool.  When the USAP pool is disabled the application lifecycle will be identical to
286      * previous versions of Android.
287      */
288     private boolean mUsapPoolEnabled = false;
289 
290     /**
291      * Start a new process.
292      *
293      * <p>If processes are enabled, a new process is created and the
294      * static main() function of a <var>processClass</var> is executed there.
295      * The process will continue running after this function returns.
296      *
297      * <p>If processes are not enabled, a new thread in the caller's
298      * process is created and main() of <var>processclass</var> called there.
299      *
300      * <p>The niceName parameter, if not an empty string, is a custom name to
301      * give to the process instead of using processClass.  This allows you to
302      * make easily identifyable processes even if you are using the same base
303      * <var>processClass</var> to start them.
304      *
305      * When invokeWith is not null, the process will be started as a fresh app
306      * and not a zygote fork. Note that this is only allowed for uid 0 or when
307      * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
308      *
309      * @param processClass The class to use as the process's main entry
310      *                     point.
311      * @param niceName A more readable name to use for the process.
312      * @param uid The user-id under which the process will run.
313      * @param gid The group-id under which the process will run.
314      * @param gids Additional group-ids associated with the process.
315      * @param runtimeFlags Additional flags.
316      * @param targetSdkVersion The target SDK version for the app.
317      * @param seInfo null-ok SELinux information for the new process.
318      * @param abi non-null the ABI this app should be started with.
319      * @param instructionSet null-ok the instruction set to use.
320      * @param appDataDir null-ok the data directory of the app.
321      * @param invokeWith null-ok the command to invoke with.
322      * @param packageName null-ok the name of the package this process belongs to.
323      * @param zygotePolicyFlags Flags used to determine how to launch the application.
324      * @param isTopApp Whether the process starts for high priority application.
325      * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
326      *                             started.
327      * @param pkgDataInfoMap Map from related package names to private data directory
328      *                       volume UUID and inode number.
329      * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
330      *                       volume UUID and inode number.
331      * @param bindMountAppsData whether zygote needs to mount CE and DE data.
332      * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
333      *
334      * @param zygoteArgs Additional arguments to supply to the Zygote process.
335      * @return An object that describes the result of the attempt to start the process.
336      * @throws RuntimeException on fatal start failure
337      */
start(@onNull final String processClass, final String niceName, int uid, int gid, @Nullable int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, int zygotePolicyFlags, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, boolean bindOverrideSysprops, @Nullable String[] zygoteArgs)338     public final Process.ProcessStartResult start(@NonNull final String processClass,
339                                                   final String niceName,
340                                                   int uid, int gid, @Nullable int[] gids,
341                                                   int runtimeFlags, int mountExternal,
342                                                   int targetSdkVersion,
343                                                   @Nullable String seInfo,
344                                                   @NonNull String abi,
345                                                   @Nullable String instructionSet,
346                                                   @Nullable String appDataDir,
347                                                   @Nullable String invokeWith,
348                                                   @Nullable String packageName,
349                                                   int zygotePolicyFlags,
350                                                   boolean isTopApp,
351                                                   @Nullable long[] disabledCompatChanges,
352                                                   @Nullable Map<String, Pair<String, Long>>
353                                                           pkgDataInfoMap,
354                                                   @Nullable Map<String, Pair<String, Long>>
355                                                           allowlistedDataInfoList,
356                                                   boolean bindMountAppsData,
357                                                   boolean bindMountAppStorageDirs,
358                                                   boolean bindOverrideSysprops,
359                                                   @Nullable String[] zygoteArgs) {
360         // TODO (chriswailes): Is there a better place to check this value?
361         if (fetchUsapPoolEnabledPropWithMinInterval()) {
362             informZygotesOfUsapPoolStatus();
363         }
364 
365         try {
366             return startViaZygote(processClass, niceName, uid, gid, gids,
367                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
368                     abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
369                     packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
370                     pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
371                     bindMountAppStorageDirs, bindOverrideSysprops, zygoteArgs);
372         } catch (ZygoteStartFailedEx ex) {
373             Log.e(LOG_TAG,
374                     "Starting VM process through Zygote failed");
375             throw new RuntimeException(
376                     "Starting VM process through Zygote failed", ex);
377         }
378     }
379 
380     /** retry interval for opening a zygote socket */
381     static final int ZYGOTE_RETRY_MILLIS = 500;
382 
383     /**
384      * Queries the zygote for the list of ABIS it supports.
385      */
386     @GuardedBy("mLock")
getAbiList(BufferedWriter writer, DataInputStream inputStream)387     private static List<String> getAbiList(BufferedWriter writer, DataInputStream inputStream)
388             throws IOException {
389         // Each query starts with the argument count (1 in this case)
390         writer.write("1");
391         // ... followed by a new-line.
392         writer.newLine();
393         // ... followed by our only argument.
394         writer.write("--query-abi-list");
395         writer.newLine();
396         writer.flush();
397 
398         // The response is a length prefixed stream of ASCII bytes.
399         int numBytes = inputStream.readInt();
400         byte[] bytes = new byte[numBytes];
401         inputStream.readFully(bytes);
402 
403         final String rawList = new String(bytes, StandardCharsets.US_ASCII);
404 
405         return Arrays.asList(rawList.split(","));
406     }
407 
408     /**
409      * Sends an argument list to the zygote process, which starts a new child
410      * and returns the child's pid. Please note: the present implementation
411      * replaces newlines in the argument list with spaces.
412      *
413      * @throws ZygoteStartFailedEx if process start failed for any reason
414      */
415     @GuardedBy("mLock")
zygoteSendArgsAndGetResult( ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)416     private Process.ProcessStartResult zygoteSendArgsAndGetResult(
417             ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
418             throws ZygoteStartFailedEx {
419         // Throw early if any of the arguments are malformed. This means we can
420         // avoid writing a partial response to the zygote.
421         for (String arg : args) {
422             // Making two indexOf calls here is faster than running a manually fused loop due
423             // to the fact that indexOf is an optimized intrinsic.
424             if (arg.indexOf('\n') >= 0) {
425                 throw new ZygoteStartFailedEx("Embedded newlines not allowed");
426             } else if (arg.indexOf('\r') >= 0) {
427                 throw new ZygoteStartFailedEx("Embedded carriage returns not allowed");
428             } else if (arg.indexOf('\u0000') >= 0) {
429                 throw new ZygoteStartFailedEx("Embedded nulls not allowed");
430             }
431         }
432 
433         /*
434          * See com.android.internal.os.ZygoteArguments.parseArgs()
435          * Presently the wire format to the zygote process is:
436          * a) a count of arguments (argc, in essence)
437          * b) a number of newline-separated argument strings equal to count
438          *
439          * After the zygote process reads these it will write the pid of
440          * the child or -1 on failure, followed by boolean to
441          * indicate whether a wrapper process was used.
442          */
443         String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
444 
445         if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {
446             try {
447                 return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
448             } catch (IOException ex) {
449                 // If there was an IOException using the USAP pool we will log the error and
450                 // attempt to start the process through the Zygote.
451                 Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
452                         + ex.getMessage());
453             }
454         }
455 
456         return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
457     }
458 
attemptZygoteSendArgsAndGetResult( ZygoteState zygoteState, String msgStr)459     private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
460             ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
461         try {
462             final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
463             final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
464 
465             zygoteWriter.write(msgStr);
466             zygoteWriter.flush();
467 
468             // Always read the entire result from the input stream to avoid leaving
469             // bytes in the stream for future process starts to accidentally stumble
470             // upon.
471             Process.ProcessStartResult result = new Process.ProcessStartResult();
472             result.pid = zygoteInputStream.readInt();
473             result.usingWrapper = zygoteInputStream.readBoolean();
474 
475             if (result.pid < 0) {
476                 throw new ZygoteStartFailedEx("fork() failed");
477             }
478 
479             return result;
480         } catch (IOException ex) {
481             zygoteState.close();
482             Log.e(LOG_TAG, "IO Exception while communicating with Zygote - "
483                     + ex.toString());
484             throw new ZygoteStartFailedEx(ex);
485         }
486     }
487 
attemptUsapSendArgsAndGetResult( ZygoteState zygoteState, String msgStr)488     private Process.ProcessStartResult attemptUsapSendArgsAndGetResult(
489             ZygoteState zygoteState, String msgStr)
490             throws ZygoteStartFailedEx, IOException {
491         try (LocalSocket usapSessionSocket = zygoteState.getUsapSessionSocket()) {
492             final BufferedWriter usapWriter =
493                     new BufferedWriter(
494                             new OutputStreamWriter(usapSessionSocket.getOutputStream()),
495                             Zygote.SOCKET_BUFFER_SIZE);
496             final DataInputStream usapReader =
497                     new DataInputStream(usapSessionSocket.getInputStream());
498 
499             usapWriter.write(msgStr);
500             usapWriter.flush();
501 
502             Process.ProcessStartResult result = new Process.ProcessStartResult();
503             result.pid = usapReader.readInt();
504             // USAPs can't be used to spawn processes that need wrappers.
505             result.usingWrapper = false;
506 
507             if (result.pid >= 0) {
508                 return result;
509             } else {
510                 throw new ZygoteStartFailedEx("USAP specialization failed");
511             }
512         }
513     }
514 
515     /**
516      * Test various member properties and parameters to determine if a launch event should be
517      * handled using an Unspecialized App Process Pool or not.
518      *
519      * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the
520      *                          Zygote command
521      * @param args Arguments that will be passed to the Zygote
522      * @return If the command should be sent to a USAP Pool member or an actual Zygote
523      */
shouldAttemptUsapLaunch(int zygotePolicyFlags, ArrayList<String> args)524     private boolean shouldAttemptUsapLaunch(int zygotePolicyFlags, ArrayList<String> args) {
525         return mUsapPoolSupported
526                 && mUsapPoolEnabled
527                 && policySpecifiesUsapPoolLaunch(zygotePolicyFlags)
528                 && commandSupportedByUsap(args);
529     }
530 
531     /**
532      * Tests a Zygote policy flag set for various properties that determine if it is eligible for
533      * being handled by an Unspecialized App Process Pool.
534      *
535      * @param zygotePolicyFlags Policy flags indicating special behavioral observations about the
536      *                          Zygote command
537      * @return If the policy allows for use of a USAP pool
538      */
policySpecifiesUsapPoolLaunch(int zygotePolicyFlags)539     private static boolean policySpecifiesUsapPoolLaunch(int zygotePolicyFlags) {
540         /*
541          * Zygote USAP Pool Policy: Launch the new process from the USAP Pool iff the launch event
542          * is latency sensitive but *NOT* a system process.  All system processes are equally
543          * important so we don't want to prioritize one over another.
544          */
545         return (zygotePolicyFlags
546                 & (ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS | ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE))
547                 == ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
548     }
549 
550     /**
551      * Flags that may not be passed to a USAP.  These may appear as prefixes to individual Zygote
552      * arguments.
553      */
554     private static final String[] INVALID_USAP_FLAGS = {
555         "--query-abi-list",
556         "--get-pid",
557         "--preload-default",
558         "--preload-package",
559         "--preload-app",
560         "--start-child-zygote",
561         "--set-api-denylist-exemptions",
562         "--hidden-api-log-sampling-rate",
563         "--hidden-api-statslog-sampling-rate",
564         "--invoke-with"
565     };
566 
567     /**
568      * Tests a command list to see if it is valid to send to a USAP.
569      *
570      * @param args  Zygote/USAP command arguments
571      * @return  True if the command can be passed to a USAP; false otherwise
572      */
commandSupportedByUsap(ArrayList<String> args)573     private static boolean commandSupportedByUsap(ArrayList<String> args) {
574         for (String flag : args) {
575             for (String badFlag : INVALID_USAP_FLAGS) {
576                 if (flag.startsWith(badFlag)) {
577                     return false;
578                 }
579             }
580             if (flag.startsWith("--nice-name=")) {
581                 // Check if the wrap property is set, usap would ignore it.
582                 if (Zygote.getWrapProperty(flag.substring(12)) != null) {
583                     return false;
584                 }
585             }
586         }
587 
588         return true;
589     }
590 
591     /**
592      * Starts a new process via the zygote mechanism.
593      *
594      * @param processClass Class name whose static main() to run
595      * @param niceName 'nice' process name to appear in ps
596      * @param uid a POSIX uid that the new process should setuid() to
597      * @param gid a POSIX gid that the new process shuold setgid() to
598      * @param gids null-ok; a list of supplementary group IDs that the
599      * new process should setgroup() to.
600      * @param runtimeFlags Additional flags for the runtime.
601      * @param targetSdkVersion The target SDK version for the app.
602      * @param seInfo null-ok SELinux information for the new process.
603      * @param abi the ABI the process should use.
604      * @param instructionSet null-ok the instruction set to use.
605      * @param appDataDir null-ok the data directory of the app.
606      * @param startChildZygote Start a sub-zygote. This creates a new zygote process
607      * that has its state cloned from this zygote process.
608      * @param packageName null-ok the name of the package this process belongs to.
609      * @param zygotePolicyFlags Flags used to determine how to launch the application.
610      * @param isTopApp Whether the process starts for high priority application.
611      * @param disabledCompatChanges a list of disabled compat changes for the process being started.
612      * @param pkgDataInfoMap Map from related package names to private data directory volume UUID
613      *                       and inode number.
614      * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
615      *                       volume UUID and inode number.
616      * @param bindMountAppsData whether zygote needs to mount CE and DE data.
617      * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
618      * @param extraArgs Additional arguments to supply to the zygote process.
619      * @return An object that describes the result of the attempt to start the process.
620      * @throws ZygoteStartFailedEx if process start failed for any reason
621      */
startViaZygote(@onNull final String processClass, @Nullable final String niceName, final int uid, final int gid, @Nullable final int[] gids, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String invokeWith, boolean startChildZygote, @Nullable String packageName, int zygotePolicyFlags, boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, boolean bindMountOverrideSysprops, @Nullable String[] extraArgs)622     private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
623                                                       @Nullable final String niceName,
624                                                       final int uid, final int gid,
625                                                       @Nullable final int[] gids,
626                                                       int runtimeFlags, int mountExternal,
627                                                       int targetSdkVersion,
628                                                       @Nullable String seInfo,
629                                                       @NonNull String abi,
630                                                       @Nullable String instructionSet,
631                                                       @Nullable String appDataDir,
632                                                       @Nullable String invokeWith,
633                                                       boolean startChildZygote,
634                                                       @Nullable String packageName,
635                                                       int zygotePolicyFlags,
636                                                       boolean isTopApp,
637                                                       @Nullable long[] disabledCompatChanges,
638                                                       @Nullable Map<String, Pair<String, Long>>
639                                                               pkgDataInfoMap,
640                                                       @Nullable Map<String, Pair<String, Long>>
641                                                               allowlistedDataInfoList,
642                                                       boolean bindMountAppsData,
643                                                       boolean bindMountAppStorageDirs,
644                                                       boolean bindMountOverrideSysprops,
645                                                       @Nullable String[] extraArgs)
646                                                       throws ZygoteStartFailedEx {
647         ArrayList<String> argsForZygote = new ArrayList<>();
648 
649         // --runtime-args, --setuid=, --setgid=,
650         // and --setgroups= must go first
651         argsForZygote.add("--runtime-args");
652         argsForZygote.add("--setuid=" + uid);
653         argsForZygote.add("--setgid=" + gid);
654         argsForZygote.add("--runtime-flags=" + runtimeFlags);
655         if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
656             argsForZygote.add("--mount-external-default");
657         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
658             argsForZygote.add("--mount-external-installer");
659         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
660             argsForZygote.add("--mount-external-pass-through");
661         } else if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
662             argsForZygote.add("--mount-external-android-writable");
663         }
664 
665         argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
666 
667         // --setgroups is a comma-separated list
668         if (gids != null && gids.length > 0) {
669             final StringBuilder sb = new StringBuilder();
670             sb.append("--setgroups=");
671 
672             final int sz = gids.length;
673             for (int i = 0; i < sz; i++) {
674                 if (i != 0) {
675                     sb.append(',');
676                 }
677                 sb.append(gids[i]);
678             }
679 
680             argsForZygote.add(sb.toString());
681         }
682 
683         if (niceName != null) {
684             argsForZygote.add("--nice-name=" + niceName);
685         }
686 
687         if (seInfo != null) {
688             argsForZygote.add("--seinfo=" + seInfo);
689         }
690 
691         if (instructionSet != null) {
692             argsForZygote.add("--instruction-set=" + instructionSet);
693         }
694 
695         if (appDataDir != null) {
696             argsForZygote.add("--app-data-dir=" + appDataDir);
697         }
698 
699         if (invokeWith != null) {
700             argsForZygote.add("--invoke-with");
701             argsForZygote.add(invokeWith);
702         }
703 
704         if (startChildZygote) {
705             argsForZygote.add("--start-child-zygote");
706         }
707 
708         if (packageName != null) {
709             argsForZygote.add("--package-name=" + packageName);
710         }
711 
712         if (isTopApp) {
713             argsForZygote.add(Zygote.START_AS_TOP_APP_ARG);
714         }
715         if (pkgDataInfoMap != null && pkgDataInfoMap.size() > 0) {
716             StringBuilder sb = new StringBuilder();
717             sb.append(Zygote.PKG_DATA_INFO_MAP);
718             sb.append("=");
719             boolean started = false;
720             for (Map.Entry<String, Pair<String, Long>> entry : pkgDataInfoMap.entrySet()) {
721                 if (started) {
722                     sb.append(',');
723                 }
724                 started = true;
725                 sb.append(entry.getKey());
726                 sb.append(',');
727                 sb.append(entry.getValue().first);
728                 sb.append(',');
729                 sb.append(entry.getValue().second);
730             }
731             argsForZygote.add(sb.toString());
732         }
733         if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) {
734             StringBuilder sb = new StringBuilder();
735             sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP);
736             sb.append("=");
737             boolean started = false;
738             for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) {
739                 if (started) {
740                     sb.append(',');
741                 }
742                 started = true;
743                 sb.append(entry.getKey());
744                 sb.append(',');
745                 sb.append(entry.getValue().first);
746                 sb.append(',');
747                 sb.append(entry.getValue().second);
748             }
749             argsForZygote.add(sb.toString());
750         }
751 
752         if (bindMountAppStorageDirs) {
753             argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
754         }
755 
756         if (bindMountAppsData) {
757             argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS);
758         }
759 
760         if (bindMountOverrideSysprops) {
761             argsForZygote.add(Zygote.BIND_MOUNT_SYSPROP_OVERRIDES);
762         }
763 
764         if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
765             StringBuilder sb = new StringBuilder();
766             sb.append("--disabled-compat-changes=");
767 
768             int sz = disabledCompatChanges.length;
769             for (int i = 0; i < sz; i++) {
770                 if (i != 0) {
771                     sb.append(',');
772                 }
773                 sb.append(disabledCompatChanges[i]);
774             }
775 
776             argsForZygote.add(sb.toString());
777         }
778 
779         argsForZygote.add(processClass);
780 
781         if (extraArgs != null) {
782             Collections.addAll(argsForZygote, extraArgs);
783         }
784 
785         synchronized(mLock) {
786             // The USAP pool can not be used if the application will not use the systems graphics
787             // driver.  If that driver is requested use the Zygote application start path.
788             return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
789                                               zygotePolicyFlags,
790                                               argsForZygote);
791         }
792     }
793 
fetchUsapPoolEnabledProp()794     private boolean fetchUsapPoolEnabledProp() {
795         boolean origVal = mUsapPoolEnabled;
796 
797         mUsapPoolEnabled = ZygoteConfig.getBool(
798             ZygoteConfig.USAP_POOL_ENABLED, ZygoteConfig.USAP_POOL_ENABLED_DEFAULT);
799 
800         boolean valueChanged = origVal != mUsapPoolEnabled;
801 
802         if (valueChanged) {
803             Log.i(LOG_TAG, "usapPoolEnabled = " + mUsapPoolEnabled);
804         }
805 
806         return valueChanged;
807     }
808 
809     private boolean mIsFirstPropCheck = true;
810     private long mLastPropCheckTimestamp = 0;
811 
fetchUsapPoolEnabledPropWithMinInterval()812     private boolean fetchUsapPoolEnabledPropWithMinInterval() {
813         // If this Zygote doesn't support USAPs there is no need to fetch any
814         // properties.
815         if (!mUsapPoolSupported) return false;
816 
817         final long currentTimestamp = SystemClock.elapsedRealtime();
818 
819         if (mIsFirstPropCheck
820                 || (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) {
821             mIsFirstPropCheck = false;
822             mLastPropCheckTimestamp = currentTimestamp;
823             return fetchUsapPoolEnabledProp();
824         }
825 
826         return false;
827     }
828 
829     /**
830      * Closes the connections to the zygote, if they exist.
831      */
close()832     public void close() {
833         if (primaryZygoteState != null) {
834             primaryZygoteState.close();
835         }
836         if (secondaryZygoteState != null) {
837             secondaryZygoteState.close();
838         }
839     }
840 
841     /**
842      * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
843      * and retry if the zygote is unresponsive. This method is a no-op if a connection is
844      * already open.
845      */
establishZygoteConnectionForAbi(String abi)846     public void establishZygoteConnectionForAbi(String abi) {
847         try {
848             synchronized(mLock) {
849                 openZygoteSocketIfNeeded(abi);
850             }
851         } catch (ZygoteStartFailedEx ex) {
852             throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
853         }
854     }
855 
856     /**
857      * Attempt to retrieve the PID of the zygote serving the given abi.
858      */
getZygotePid(String abi)859     public int getZygotePid(String abi) {
860         try {
861             synchronized (mLock) {
862                 ZygoteState state = openZygoteSocketIfNeeded(abi);
863 
864                 // Each query starts with the argument count (1 in this case)
865                 state.mZygoteOutputWriter.write("1");
866                 // ... followed by a new-line.
867                 state.mZygoteOutputWriter.newLine();
868                 // ... followed by our only argument.
869                 state.mZygoteOutputWriter.write("--get-pid");
870                 state.mZygoteOutputWriter.newLine();
871                 state.mZygoteOutputWriter.flush();
872 
873                 // The response is a length prefixed stream of ASCII bytes.
874                 int numBytes = state.mZygoteInputStream.readInt();
875                 byte[] bytes = new byte[numBytes];
876                 state.mZygoteInputStream.readFully(bytes);
877 
878                 return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
879             }
880         } catch (Exception ex) {
881             throw new RuntimeException("Failure retrieving pid", ex);
882         }
883     }
884 
885     /**
886      * Notify the Zygote processes that boot completed.
887      */
bootCompleted()888     public void bootCompleted() {
889         // Notify both the 32-bit and 64-bit zygote.
890         if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
891             bootCompleted(Build.SUPPORTED_32_BIT_ABIS[0]);
892         }
893         if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
894             bootCompleted(Build.SUPPORTED_64_BIT_ABIS[0]);
895         }
896     }
897 
bootCompleted(String abi)898     private void bootCompleted(String abi) {
899         try {
900             synchronized (mLock) {
901                 ZygoteState state = openZygoteSocketIfNeeded(abi);
902                 state.mZygoteOutputWriter.write("1\n--boot-completed\n");
903                 state.mZygoteOutputWriter.flush();
904                 state.mZygoteInputStream.readInt();
905             }
906         } catch (Exception ex) {
907             throw new RuntimeException("Failed to inform zygote of boot_completed", ex);
908         }
909     }
910 
911     /**
912      * Push hidden API deny-listing exemptions into the zygote process(es).
913      *
914      * <p>The list of exemptions will take affect for all new processes forked from the zygote after
915      * this call.
916      *
917      * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
918      *        allowed/public APIs (i.e. allowed, no logging of usage).
919      */
setApiDenylistExemptions(List<String> exemptions)920     public boolean setApiDenylistExemptions(List<String> exemptions) {
921         synchronized (mLock) {
922             mApiDenylistExemptions = exemptions;
923             boolean ok = maybeSetApiDenylistExemptions(primaryZygoteState, true);
924             if (ok) {
925                 ok = maybeSetApiDenylistExemptions(secondaryZygoteState, true);
926             }
927             return ok;
928         }
929     }
930 
931     /**
932      * Set the precentage of detected hidden API accesses that are logged to the event log.
933      *
934      * <p>This rate will take affect for all new processes forked from the zygote after this call.
935      *
936      * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
937      */
setHiddenApiAccessLogSampleRate(int rate)938     public void setHiddenApiAccessLogSampleRate(int rate) {
939         synchronized (mLock) {
940             mHiddenApiAccessLogSampleRate = rate;
941             maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
942             maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
943         }
944     }
945 
946     /**
947      * Set the precentage of detected hidden API accesses that are logged to the new event log.
948      *
949      * <p>This rate will take affect for all new processes forked from the zygote after this call.
950      *
951      * @param rate An integer between 0 and 0x10000 inclusive. 0 means no event logging.
952      */
setHiddenApiAccessStatslogSampleRate(int rate)953     public void setHiddenApiAccessStatslogSampleRate(int rate) {
954         synchronized (mLock) {
955             mHiddenApiAccessStatslogSampleRate = rate;
956             maybeSetHiddenApiAccessStatslogSampleRate(primaryZygoteState);
957             maybeSetHiddenApiAccessStatslogSampleRate(secondaryZygoteState);
958         }
959     }
960 
961     @GuardedBy("mLock")
maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty)962     private boolean maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfEmpty) {
963         if (state == null || state.isClosed()) {
964             Slog.e(LOG_TAG, "Can't set API denylist exemptions: no zygote connection");
965             return false;
966         } else if (!sendIfEmpty && mApiDenylistExemptions.isEmpty()) {
967             return true;
968         }
969 
970         for (/* NonNull */ String s : mApiDenylistExemptions) {
971             // indexOf() is intrinsified and faster than contains().
972             if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0 || s.indexOf('\u0000') >= 0) {
973                 Slog.e(LOG_TAG, "Failed to set API denylist exemptions: Bad character");
974                 mApiDenylistExemptions = Collections.emptyList();
975                 return false;
976             }
977         }
978         try {
979             state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1));
980             state.mZygoteOutputWriter.newLine();
981             state.mZygoteOutputWriter.write("--set-api-denylist-exemptions");
982             state.mZygoteOutputWriter.newLine();
983             for (int i = 0; i < mApiDenylistExemptions.size(); ++i) {
984                 state.mZygoteOutputWriter.write(mApiDenylistExemptions.get(i));
985                 state.mZygoteOutputWriter.newLine();
986             }
987             state.mZygoteOutputWriter.flush();
988             int status = state.mZygoteInputStream.readInt();
989             if (status != 0) {
990                 Slog.e(LOG_TAG, "Failed to set API denylist exemptions; status " + status);
991             }
992             return true;
993         } catch (IOException ioe) {
994             Slog.e(LOG_TAG, "Failed to set API denylist exemptions", ioe);
995             mApiDenylistExemptions = Collections.emptyList();
996             return false;
997         }
998     }
999 
maybeSetHiddenApiAccessLogSampleRate(ZygoteState state)1000     private void maybeSetHiddenApiAccessLogSampleRate(ZygoteState state) {
1001         if (state == null || state.isClosed() || mHiddenApiAccessLogSampleRate == -1) {
1002             return;
1003         }
1004 
1005         try {
1006             state.mZygoteOutputWriter.write(Integer.toString(1));
1007             state.mZygoteOutputWriter.newLine();
1008             state.mZygoteOutputWriter.write("--hidden-api-log-sampling-rate="
1009                     + mHiddenApiAccessLogSampleRate);
1010             state.mZygoteOutputWriter.newLine();
1011             state.mZygoteOutputWriter.flush();
1012             int status = state.mZygoteInputStream.readInt();
1013             if (status != 0) {
1014                 Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate; status " + status);
1015             }
1016         } catch (IOException ioe) {
1017             Slog.e(LOG_TAG, "Failed to set hidden API log sampling rate", ioe);
1018         }
1019     }
1020 
maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state)1021     private void maybeSetHiddenApiAccessStatslogSampleRate(ZygoteState state) {
1022         if (state == null || state.isClosed() || mHiddenApiAccessStatslogSampleRate == -1) {
1023             return;
1024         }
1025 
1026         try {
1027             state.mZygoteOutputWriter.write(Integer.toString(1));
1028             state.mZygoteOutputWriter.newLine();
1029             state.mZygoteOutputWriter.write("--hidden-api-statslog-sampling-rate="
1030                     + mHiddenApiAccessStatslogSampleRate);
1031             state.mZygoteOutputWriter.newLine();
1032             state.mZygoteOutputWriter.flush();
1033             int status = state.mZygoteInputStream.readInt();
1034             if (status != 0) {
1035                 Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate; status "
1036                         + status);
1037             }
1038         } catch (IOException ioe) {
1039             Slog.e(LOG_TAG, "Failed to set hidden API statslog sampling rate", ioe);
1040         }
1041     }
1042 
1043     /**
1044      * Creates a ZygoteState for the primary zygote if it doesn't exist or has been disconnected.
1045      */
1046     @GuardedBy("mLock")
attemptConnectionToPrimaryZygote()1047     private void attemptConnectionToPrimaryZygote() throws IOException {
1048         if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
1049             primaryZygoteState =
1050                     ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
1051 
1052             maybeSetApiDenylistExemptions(primaryZygoteState, false);
1053             maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
1054         }
1055     }
1056 
1057     /**
1058      * Creates a ZygoteState for the secondary zygote if it doesn't exist or has been disconnected.
1059      */
1060     @GuardedBy("mLock")
attemptConnectionToSecondaryZygote()1061     private void attemptConnectionToSecondaryZygote() throws IOException {
1062         if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
1063             secondaryZygoteState =
1064                     ZygoteState.connect(mZygoteSecondarySocketAddress,
1065                             mUsapPoolSecondarySocketAddress);
1066 
1067             maybeSetApiDenylistExemptions(secondaryZygoteState, false);
1068             maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
1069         }
1070     }
1071 
1072     /**
1073      * Tries to open a session socket to a Zygote process with a compatible ABI if one is not
1074      * already open. If a compatible session socket is already open that session socket is returned.
1075      * This function may block and may have to try connecting to multiple Zygotes to find the
1076      * appropriate one.  Requires that mLock be held.
1077      */
1078     @GuardedBy("mLock")
openZygoteSocketIfNeeded(String abi)1079     private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
1080         try {
1081             attemptConnectionToPrimaryZygote();
1082 
1083             if (primaryZygoteState.matches(abi)) {
1084                 return primaryZygoteState;
1085             }
1086 
1087             if (mZygoteSecondarySocketAddress != null) {
1088                 // The primary zygote didn't match. Try the secondary.
1089                 attemptConnectionToSecondaryZygote();
1090 
1091                 if (secondaryZygoteState.matches(abi)) {
1092                     return secondaryZygoteState;
1093                 }
1094             }
1095         } catch (IOException ioe) {
1096             throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
1097         }
1098 
1099         throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
1100     }
1101 
1102     /**
1103      * Instructs the zygote to pre-load the application code for the given Application.
1104      * Only the app zygote supports this function.
1105      * TODO preloadPackageForAbi() can probably be removed and the callers an use this instead.
1106      */
preloadApp(ApplicationInfo appInfo, String abi)1107     public boolean preloadApp(ApplicationInfo appInfo, String abi)
1108             throws ZygoteStartFailedEx, IOException {
1109         synchronized (mLock) {
1110             ZygoteState state = openZygoteSocketIfNeeded(abi);
1111             state.mZygoteOutputWriter.write("2");
1112             state.mZygoteOutputWriter.newLine();
1113 
1114             state.mZygoteOutputWriter.write("--preload-app");
1115             state.mZygoteOutputWriter.newLine();
1116 
1117             // Zygote args needs to be strings, so in order to pass ApplicationInfo,
1118             // write it to a Parcel, and base64 the raw Parcel bytes to the other side.
1119             Parcel parcel = Parcel.obtain();
1120             appInfo.writeToParcel(parcel, 0 /* flags */);
1121             String encodedParcelData = Base64.getEncoder().encodeToString(parcel.marshall());
1122             parcel.recycle();
1123             state.mZygoteOutputWriter.write(encodedParcelData);
1124             state.mZygoteOutputWriter.newLine();
1125 
1126             state.mZygoteOutputWriter.flush();
1127 
1128             return (state.mZygoteInputStream.readInt() == 0);
1129         }
1130     }
1131 
1132     /**
1133      * Instructs the zygote to pre-load the classes and native libraries at the given paths
1134      * for the specified abi. Not all zygotes support this function.
1135      */
preloadPackageForAbi( String packagePath, String libsPath, String libFileName, String cacheKey, String abi)1136     public boolean preloadPackageForAbi(
1137             String packagePath, String libsPath, String libFileName, String cacheKey, String abi)
1138             throws ZygoteStartFailedEx, IOException {
1139         synchronized (mLock) {
1140             ZygoteState state = openZygoteSocketIfNeeded(abi);
1141             state.mZygoteOutputWriter.write("5");
1142             state.mZygoteOutputWriter.newLine();
1143 
1144             state.mZygoteOutputWriter.write("--preload-package");
1145             state.mZygoteOutputWriter.newLine();
1146 
1147             state.mZygoteOutputWriter.write(packagePath);
1148             state.mZygoteOutputWriter.newLine();
1149 
1150             state.mZygoteOutputWriter.write(libsPath);
1151             state.mZygoteOutputWriter.newLine();
1152 
1153             state.mZygoteOutputWriter.write(libFileName);
1154             state.mZygoteOutputWriter.newLine();
1155 
1156             state.mZygoteOutputWriter.write(cacheKey);
1157             state.mZygoteOutputWriter.newLine();
1158 
1159             state.mZygoteOutputWriter.flush();
1160 
1161             return (state.mZygoteInputStream.readInt() == 0);
1162         }
1163     }
1164 
1165     /**
1166      * Instructs the zygote to preload the default set of classes and resources. Returns
1167      * {@code true} if a preload was performed as a result of this call, and {@code false}
1168      * otherwise. The latter usually means that the zygote eagerly preloaded at startup
1169      * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
1170      */
preloadDefault(String abi)1171     public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
1172         synchronized (mLock) {
1173             ZygoteState state = openZygoteSocketIfNeeded(abi);
1174             // Each query starts with the argument count (1 in this case)
1175             state.mZygoteOutputWriter.write("1");
1176             state.mZygoteOutputWriter.newLine();
1177             state.mZygoteOutputWriter.write("--preload-default");
1178             state.mZygoteOutputWriter.newLine();
1179             state.mZygoteOutputWriter.flush();
1180 
1181             return (state.mZygoteInputStream.readInt() == 0);
1182         }
1183     }
1184 
1185     /**
1186      * Try connecting to the Zygote over and over again until we hit a time-out.
1187      * @param zygoteSocketName The name of the socket to connect to.
1188      */
waitForConnectionToZygote(String zygoteSocketName)1189     public static void waitForConnectionToZygote(String zygoteSocketName) {
1190         final LocalSocketAddress zygoteSocketAddress =
1191                 new LocalSocketAddress(zygoteSocketName, LocalSocketAddress.Namespace.RESERVED);
1192         waitForConnectionToZygote(zygoteSocketAddress);
1193     }
1194 
1195     /**
1196      * Try connecting to the Zygote over and over again until we hit a time-out.
1197      * @param zygoteSocketAddress The name of the socket to connect to.
1198      */
waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress)1199     public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
1200         int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS;
1201         for (int n = numRetries; n >= 0; n--) {
1202             try {
1203                 final ZygoteState zs =
1204                         ZygoteState.connect(zygoteSocketAddress, null);
1205                 zs.close();
1206                 return;
1207             } catch (IOException ioe) {
1208                 Log.w(LOG_TAG,
1209                         "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
1210             }
1211 
1212             try {
1213                 Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
1214             } catch (InterruptedException ignored) { }
1215         }
1216         Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket "
1217                 + zygoteSocketAddress.getName());
1218     }
1219 
1220     /**
1221      * Sends messages to the zygotes telling them to change the status of their USAP pools.  If
1222      * this notification fails the ZygoteProcess will fall back to the previous behavior.
1223      */
informZygotesOfUsapPoolStatus()1224     private void informZygotesOfUsapPoolStatus() {
1225         final String command = "1\n--usap-pool-enabled=" + mUsapPoolEnabled + "\n";
1226 
1227         synchronized (mLock) {
1228             try {
1229                 attemptConnectionToPrimaryZygote();
1230 
1231                 primaryZygoteState.mZygoteOutputWriter.write(command);
1232                 primaryZygoteState.mZygoteOutputWriter.flush();
1233             } catch (IOException ioe) {
1234                 mUsapPoolEnabled = !mUsapPoolEnabled;
1235                 Log.w(LOG_TAG, "Failed to inform zygotes of USAP pool status: "
1236                         + ioe.getMessage());
1237                 return;
1238             }
1239 
1240             if (mZygoteSecondarySocketAddress != null) {
1241                 try {
1242                     attemptConnectionToSecondaryZygote();
1243 
1244                     try {
1245                         secondaryZygoteState.mZygoteOutputWriter.write(command);
1246                         secondaryZygoteState.mZygoteOutputWriter.flush();
1247 
1248                         // Wait for the secondary Zygote to finish its work.
1249                         secondaryZygoteState.mZygoteInputStream.readInt();
1250                     } catch (IOException ioe) {
1251                         throw new IllegalStateException(
1252                                 "USAP pool state change cause an irrecoverable error",
1253                                 ioe);
1254                     }
1255                 } catch (IOException ioe) {
1256                     // No secondary zygote present.  This is expected on some devices.
1257                 }
1258             }
1259 
1260             // Wait for the response from the primary zygote here so the primary/secondary zygotes
1261             // can work concurrently.
1262             try {
1263                 // Wait for the primary zygote to finish its work.
1264                 primaryZygoteState.mZygoteInputStream.readInt();
1265             } catch (IOException ioe) {
1266                 throw new IllegalStateException(
1267                         "USAP pool state change cause an irrecoverable error",
1268                         ioe);
1269             }
1270         }
1271     }
1272 
1273     /**
1274      * Starts a new zygote process as a child of this zygote. This is used to create
1275      * secondary zygotes that inherit data from the zygote that this object
1276      * communicates with. This returns a new ZygoteProcess representing a connection
1277      * to the newly created zygote. Throws an exception if the zygote cannot be started.
1278      *
1279      * @param processClass The class to use as the child zygote's main entry
1280      *                     point.
1281      * @param niceName A more readable name to use for the process.
1282      * @param uid The user-id under which the child zygote will run.
1283      * @param gid The group-id under which the child zygote will run.
1284      * @param gids Additional group-ids associated with the child zygote process.
1285      * @param runtimeFlags Additional flags.
1286      * @param seInfo null-ok SELinux information for the child zygote process.
1287      * @param abi non-null the ABI of the child zygote
1288      * @param acceptedAbiList ABIs this child zygote will accept connections for; this
1289      *                        may be different from <code>abi</code> in case the children
1290      *                        spawned from this Zygote only communicate using ABI-safe methods.
1291      * @param instructionSet null-ok the instruction set to use.
1292      * @param uidRangeStart The first UID in the range the child zygote may setuid()/setgid() to
1293      * @param uidRangeEnd The last UID in the range the child zygote may setuid()/setgid() to
1294      */
startChildZygote(final String processClass, final String niceName, int uid, int gid, int[] gids, int runtimeFlags, String seInfo, String abi, String acceptedAbiList, String instructionSet, int uidRangeStart, int uidRangeEnd)1295     public ChildZygoteProcess startChildZygote(final String processClass,
1296                                                final String niceName,
1297                                                int uid, int gid, int[] gids,
1298                                                int runtimeFlags,
1299                                                String seInfo,
1300                                                String abi,
1301                                                String acceptedAbiList,
1302                                                String instructionSet,
1303                                                int uidRangeStart,
1304                                                int uidRangeEnd) {
1305         // Create an unguessable address in the global abstract namespace.
1306         final LocalSocketAddress serverAddress = new LocalSocketAddress(
1307                 processClass + "/" + UUID.randomUUID().toString());
1308 
1309         final String[] extraArgs = {Zygote.CHILD_ZYGOTE_SOCKET_NAME_ARG + serverAddress.getName(),
1310                                     Zygote.CHILD_ZYGOTE_ABI_LIST_ARG + acceptedAbiList,
1311                                     Zygote.CHILD_ZYGOTE_UID_RANGE_START + uidRangeStart,
1312                                     Zygote.CHILD_ZYGOTE_UID_RANGE_END + uidRangeEnd};
1313 
1314         Process.ProcessStartResult result;
1315         try {
1316             // We will bind mount app data dirs so app zygote can't access /data/data, while
1317             // we don't need to bind mount storage dirs as /storage won't be mounted.
1318             result = startViaZygote(processClass, niceName, uid, gid,
1319                     gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
1320                     abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
1321                     true /* startChildZygote */, null /* packageName */,
1322                     ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
1323                     null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
1324                     null /* allowlistedDataInfoList */, true /* bindMountAppsData*/,
1325                     /* bindMountAppStorageDirs */ false, /*bindMountOverrideSysprops */ false,
1326                     extraArgs);
1327 
1328         } catch (ZygoteStartFailedEx ex) {
1329             throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
1330         }
1331 
1332         return new ChildZygoteProcess(serverAddress, result.pid);
1333     }
1334 }
1335