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