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