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