blob: 4a976403e7a87ad01daa89a5008b936ecdd36835 [file] [log] [blame]
Robert Sesek8f8d1872016-03-18 16:52:57 -04001/*
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
17package android.os;
18
19import android.net.LocalSocket;
20import android.net.LocalSocketAddress;
21import android.util.Log;
Gustav Senntonf0c52b52017-04-27 17:00:50 +010022import android.util.Slog;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010023
Robert Sesekded20982016-08-15 13:59:13 -040024import com.android.internal.annotations.GuardedBy;
Robert Sesek8f8d1872016-03-18 16:52:57 -040025import com.android.internal.os.Zygote;
Robert Sesekded20982016-08-15 13:59:13 -040026import com.android.internal.util.Preconditions;
Nicolas Geoffray81edac42017-09-07 14:13:29 +010027
Robert Sesek8f8d1872016-03-18 16:52:57 -040028import java.io.BufferedWriter;
29import java.io.DataInputStream;
30import java.io.IOException;
31import java.io.OutputStreamWriter;
32import java.nio.charset.StandardCharsets;
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.List;
36
37/*package*/ class ZygoteStartFailedEx extends Exception {
38 ZygoteStartFailedEx(String s) {
39 super(s);
40 }
41
42 ZygoteStartFailedEx(Throwable cause) {
43 super(cause);
44 }
45
46 ZygoteStartFailedEx(String s, Throwable cause) {
47 super(s, cause);
48 }
49}
50
51/**
52 * Maintains communication state with the zygote processes. This class is responsible
53 * for the sockets opened to the zygotes and for starting processes on behalf of the
54 * {@link android.os.Process} class.
55 *
56 * {@hide}
57 */
58public class ZygoteProcess {
59 private static final String LOG_TAG = "ZygoteProcess";
60
61 /**
62 * The name of the socket used to communicate with the primary zygote.
63 */
Robert Sesek5ac8abf2018-01-26 14:26:53 -050064 private final LocalSocketAddress mSocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -040065
66 /**
67 * The name of the secondary (alternate ABI) zygote socket.
68 */
Robert Sesek5ac8abf2018-01-26 14:26:53 -050069 private final LocalSocketAddress mSecondarySocket;
Robert Sesek8f8d1872016-03-18 16:52:57 -040070
71 public ZygoteProcess(String primarySocket, String secondarySocket) {
Robert Sesek5ac8abf2018-01-26 14:26:53 -050072 this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
73 new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
74 }
75
76 public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
Robert Sesek8f8d1872016-03-18 16:52:57 -040077 mSocket = primarySocket;
78 mSecondarySocket = secondarySocket;
79 }
80
Robert Sesek5ac8abf2018-01-26 14:26:53 -050081 public LocalSocketAddress getPrimarySocketAddress() {
82 return mSocket;
83 }
84
Robert Sesek8f8d1872016-03-18 16:52:57 -040085 /**
86 * State for communicating with the zygote process.
87 */
88 public static class ZygoteState {
89 final LocalSocket socket;
90 final DataInputStream inputStream;
91 final BufferedWriter writer;
92 final List<String> abiList;
93
94 boolean mClosed;
95
96 private ZygoteState(LocalSocket socket, DataInputStream inputStream,
97 BufferedWriter writer, List<String> abiList) {
98 this.socket = socket;
99 this.inputStream = inputStream;
100 this.writer = writer;
101 this.abiList = abiList;
102 }
103
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500104 public static ZygoteState connect(LocalSocketAddress address) throws IOException {
Robert Sesek8f8d1872016-03-18 16:52:57 -0400105 DataInputStream zygoteInputStream = null;
106 BufferedWriter zygoteWriter = null;
107 final LocalSocket zygoteSocket = new LocalSocket();
108
109 try {
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500110 zygoteSocket.connect(address);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400111
112 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
113
114 zygoteWriter = new BufferedWriter(new OutputStreamWriter(
115 zygoteSocket.getOutputStream()), 256);
116 } catch (IOException ex) {
117 try {
118 zygoteSocket.close();
119 } catch (IOException ignore) {
120 }
121
122 throw ex;
123 }
124
125 String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500126 Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
127 + address.getName() + " opened, supported ABIS: " + abiListString);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400128
129 return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
130 Arrays.asList(abiListString.split(",")));
131 }
132
133 boolean matches(String abi) {
134 return abiList.contains(abi);
135 }
136
137 public void close() {
138 try {
139 socket.close();
140 } catch (IOException ex) {
141 Log.e(LOG_TAG,"I/O exception on routine close", ex);
142 }
143
144 mClosed = true;
145 }
146
147 boolean isClosed() {
148 return mClosed;
149 }
150 }
151
152 /**
Robert Sesekded20982016-08-15 13:59:13 -0400153 * Lock object to protect access to the two ZygoteStates below. This lock must be
154 * acquired while communicating over the ZygoteState's socket, to prevent
155 * interleaved access.
156 */
157 private final Object mLock = new Object();
158
159 /**
Robert Sesek8f8d1872016-03-18 16:52:57 -0400160 * The state of the connection to the primary zygote.
161 */
162 private ZygoteState primaryZygoteState;
163
164 /**
165 * The state of the connection to the secondary zygote.
166 */
167 private ZygoteState secondaryZygoteState;
168
169 /**
170 * Start a new process.
171 *
172 * <p>If processes are enabled, a new process is created and the
173 * static main() function of a <var>processClass</var> is executed there.
174 * The process will continue running after this function returns.
175 *
176 * <p>If processes are not enabled, a new thread in the caller's
177 * process is created and main() of <var>processClass</var> called there.
178 *
179 * <p>The niceName parameter, if not an empty string, is a custom name to
180 * give to the process instead of using processClass. This allows you to
181 * make easily identifyable processes even if you are using the same base
182 * <var>processClass</var> to start them.
183 *
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000184 * When invokeWith is not null, the process will be started as a fresh app
Tamas Berghammer0ca16fa2016-11-11 16:08:26 +0000185 * and not a zygote fork. Note that this is only allowed for uid 0 or when
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100186 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000187 *
Robert Sesek8f8d1872016-03-18 16:52:57 -0400188 * @param processClass The class to use as the process's main entry
189 * point.
190 * @param niceName A more readable name to use for the process.
191 * @param uid The user-id under which the process will run.
192 * @param gid The group-id under which the process will run.
193 * @param gids Additional group-ids associated with the process.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100194 * @param runtimeFlags Additional flags.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400195 * @param targetSdkVersion The target SDK version for the app.
196 * @param seInfo null-ok SELinux information for the new process.
197 * @param abi non-null the ABI this app should be started with.
198 * @param instructionSet null-ok the instruction set to use.
199 * @param appDataDir null-ok the data directory of the app.
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000200 * @param invokeWith null-ok the command to invoke with.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400201 * @param zygoteArgs Additional arguments to supply to the zygote process.
202 *
203 * @return An object that describes the result of the attempt to start the process.
204 * @throws RuntimeException on fatal start failure
205 */
206 public final Process.ProcessStartResult start(final String processClass,
207 final String niceName,
208 int uid, int gid, int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100209 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400210 int targetSdkVersion,
211 String seInfo,
212 String abi,
213 String instructionSet,
214 String appDataDir,
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000215 String invokeWith,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400216 String[] zygoteArgs) {
217 try {
218 return startViaZygote(processClass, niceName, uid, gid, gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100219 runtimeFlags, mountExternal, targetSdkVersion, seInfo,
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000220 abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400221 } catch (ZygoteStartFailedEx ex) {
222 Log.e(LOG_TAG,
223 "Starting VM process through Zygote failed");
224 throw new RuntimeException(
225 "Starting VM process through Zygote failed", ex);
226 }
227 }
228
229 /** retry interval for opening a zygote socket */
230 static final int ZYGOTE_RETRY_MILLIS = 500;
231
232 /**
233 * Queries the zygote for the list of ABIS it supports.
234 *
235 * @throws ZygoteStartFailedEx if the query failed.
236 */
Robert Sesekded20982016-08-15 13:59:13 -0400237 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400238 private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
239 throws IOException {
240 // Each query starts with the argument count (1 in this case)
241 writer.write("1");
242 // ... followed by a new-line.
243 writer.newLine();
244 // ... followed by our only argument.
245 writer.write("--query-abi-list");
246 writer.newLine();
247 writer.flush();
248
249 // The response is a length prefixed stream of ASCII bytes.
250 int numBytes = inputStream.readInt();
251 byte[] bytes = new byte[numBytes];
252 inputStream.readFully(bytes);
253
254 return new String(bytes, StandardCharsets.US_ASCII);
255 }
256
257 /**
258 * Sends an argument list to the zygote process, which starts a new child
259 * and returns the child's pid. Please note: the present implementation
260 * replaces newlines in the argument list with spaces.
261 *
262 * @throws ZygoteStartFailedEx if process start failed for any reason
263 */
Robert Sesekded20982016-08-15 13:59:13 -0400264 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400265 private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
266 ZygoteState zygoteState, ArrayList<String> args)
267 throws ZygoteStartFailedEx {
268 try {
Robert Sesek0b58f192016-10-10 18:34:42 -0400269 // Throw early if any of the arguments are malformed. This means we can
270 // avoid writing a partial response to the zygote.
271 int sz = args.size();
272 for (int i = 0; i < sz; i++) {
273 if (args.get(i).indexOf('\n') >= 0) {
274 throw new ZygoteStartFailedEx("embedded newlines not allowed");
275 }
276 }
277
Robert Sesek8f8d1872016-03-18 16:52:57 -0400278 /**
279 * See com.android.internal.os.SystemZygoteInit.readArgumentList()
280 * Presently the wire format to the zygote process is:
281 * a) a count of arguments (argc, in essence)
282 * b) a number of newline-separated argument strings equal to count
283 *
284 * After the zygote process reads these it will write the pid of
285 * the child or -1 on failure, followed by boolean to
286 * indicate whether a wrapper process was used.
287 */
288 final BufferedWriter writer = zygoteState.writer;
289 final DataInputStream inputStream = zygoteState.inputStream;
290
291 writer.write(Integer.toString(args.size()));
292 writer.newLine();
293
Robert Sesek8f8d1872016-03-18 16:52:57 -0400294 for (int i = 0; i < sz; i++) {
295 String arg = args.get(i);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400296 writer.write(arg);
297 writer.newLine();
298 }
299
300 writer.flush();
301
302 // Should there be a timeout on this?
303 Process.ProcessStartResult result = new Process.ProcessStartResult();
Robert Sesek0b58f192016-10-10 18:34:42 -0400304
305 // Always read the entire result from the input stream to avoid leaving
306 // bytes in the stream for future process starts to accidentally stumble
307 // upon.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400308 result.pid = inputStream.readInt();
Robert Sesek0b58f192016-10-10 18:34:42 -0400309 result.usingWrapper = inputStream.readBoolean();
310
Robert Sesek8f8d1872016-03-18 16:52:57 -0400311 if (result.pid < 0) {
312 throw new ZygoteStartFailedEx("fork() failed");
313 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400314 return result;
315 } catch (IOException ex) {
316 zygoteState.close();
317 throw new ZygoteStartFailedEx(ex);
318 }
319 }
320
321 /**
322 * Starts a new process via the zygote mechanism.
323 *
324 * @param processClass Class name whose static main() to run
325 * @param niceName 'nice' process name to appear in ps
326 * @param uid a POSIX uid that the new process should setuid() to
327 * @param gid a POSIX gid that the new process shuold setgid() to
328 * @param gids null-ok; a list of supplementary group IDs that the
329 * new process should setgroup() to.
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100330 * @param runtimeFlags Additional flags for the runtime.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400331 * @param targetSdkVersion The target SDK version for the app.
332 * @param seInfo null-ok SELinux information for the new process.
333 * @param abi the ABI the process should use.
334 * @param instructionSet null-ok the instruction set to use.
335 * @param appDataDir null-ok the data directory of the app.
336 * @param extraArgs Additional arguments to supply to the zygote process.
337 * @return An object that describes the result of the attempt to start the process.
338 * @throws ZygoteStartFailedEx if process start failed for any reason
339 */
340 private Process.ProcessStartResult startViaZygote(final String processClass,
341 final String niceName,
342 final int uid, final int gid,
343 final int[] gids,
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100344 int runtimeFlags, int mountExternal,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400345 int targetSdkVersion,
346 String seInfo,
347 String abi,
348 String instructionSet,
349 String appDataDir,
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000350 String invokeWith,
Robert Sesek8f8d1872016-03-18 16:52:57 -0400351 String[] extraArgs)
352 throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400353 ArrayList<String> argsForZygote = new ArrayList<String>();
Robert Sesek8f8d1872016-03-18 16:52:57 -0400354
Robert Sesekded20982016-08-15 13:59:13 -0400355 // --runtime-args, --setuid=, --setgid=,
356 // and --setgroups= must go first
357 argsForZygote.add("--runtime-args");
358 argsForZygote.add("--setuid=" + uid);
359 argsForZygote.add("--setgid=" + gid);
Nicolas Geoffray81edac42017-09-07 14:13:29 +0100360 argsForZygote.add("--runtime-flags=" + runtimeFlags);
Robert Sesekded20982016-08-15 13:59:13 -0400361 if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
362 argsForZygote.add("--mount-external-default");
363 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
364 argsForZygote.add("--mount-external-read");
365 } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
366 argsForZygote.add("--mount-external-write");
367 }
368 argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400369
Robert Sesekded20982016-08-15 13:59:13 -0400370 // --setgroups is a comma-separated list
371 if (gids != null && gids.length > 0) {
372 StringBuilder sb = new StringBuilder();
373 sb.append("--setgroups=");
Robert Sesek8f8d1872016-03-18 16:52:57 -0400374
Robert Sesekded20982016-08-15 13:59:13 -0400375 int sz = gids.length;
376 for (int i = 0; i < sz; i++) {
377 if (i != 0) {
378 sb.append(',');
Robert Sesek8f8d1872016-03-18 16:52:57 -0400379 }
Robert Sesekded20982016-08-15 13:59:13 -0400380 sb.append(gids[i]);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400381 }
382
Robert Sesekded20982016-08-15 13:59:13 -0400383 argsForZygote.add(sb.toString());
384 }
385
386 if (niceName != null) {
387 argsForZygote.add("--nice-name=" + niceName);
388 }
389
390 if (seInfo != null) {
391 argsForZygote.add("--seinfo=" + seInfo);
392 }
393
394 if (instructionSet != null) {
395 argsForZygote.add("--instruction-set=" + instructionSet);
396 }
397
398 if (appDataDir != null) {
399 argsForZygote.add("--app-data-dir=" + appDataDir);
400 }
401
Tamas Berghammerb8f7c352016-11-11 16:08:26 +0000402 if (invokeWith != null) {
403 argsForZygote.add("--invoke-with");
404 argsForZygote.add(invokeWith);
405 }
406
Robert Sesekded20982016-08-15 13:59:13 -0400407 argsForZygote.add(processClass);
408
409 if (extraArgs != null) {
410 for (String arg : extraArgs) {
411 argsForZygote.add(arg);
Robert Sesek8f8d1872016-03-18 16:52:57 -0400412 }
Robert Sesekded20982016-08-15 13:59:13 -0400413 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400414
Robert Sesekded20982016-08-15 13:59:13 -0400415 synchronized(mLock) {
Robert Sesek8f8d1872016-03-18 16:52:57 -0400416 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
417 }
418 }
419
420 /**
421 * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block
422 * and retry if the zygote is unresponsive. This method is a no-op if a connection is
423 * already open.
424 */
425 public void establishZygoteConnectionForAbi(String abi) {
426 try {
Robert Sesekded20982016-08-15 13:59:13 -0400427 synchronized(mLock) {
428 openZygoteSocketIfNeeded(abi);
429 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400430 } catch (ZygoteStartFailedEx ex) {
431 throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
432 }
433 }
434
435 /**
436 * Tries to open socket to Zygote process if not already open. If
Robert Sesekded20982016-08-15 13:59:13 -0400437 * already open, does nothing. May block and retry. Requires that mLock be held.
Robert Sesek8f8d1872016-03-18 16:52:57 -0400438 */
Robert Sesekded20982016-08-15 13:59:13 -0400439 @GuardedBy("mLock")
Robert Sesek8f8d1872016-03-18 16:52:57 -0400440 private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Robert Sesekded20982016-08-15 13:59:13 -0400441 Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
442
Robert Sesek8f8d1872016-03-18 16:52:57 -0400443 if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
444 try {
445 primaryZygoteState = ZygoteState.connect(mSocket);
446 } catch (IOException ioe) {
447 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
448 }
449 }
450
451 if (primaryZygoteState.matches(abi)) {
452 return primaryZygoteState;
453 }
454
455 // The primary zygote didn't match. Try the secondary.
456 if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
457 try {
458 secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
459 } catch (IOException ioe) {
460 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
461 }
462 }
463
464 if (secondaryZygoteState.matches(abi)) {
465 return secondaryZygoteState;
466 }
467
468 throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
469 }
Robert Sesekded20982016-08-15 13:59:13 -0400470
471 /**
472 * Instructs the zygote to pre-load the classes and native libraries at the given paths
473 * for the specified abi. Not all zygotes support this function.
474 */
Narayan Kamathbae484a2017-07-03 14:12:26 +0100475 public boolean preloadPackageForAbi(String packagePath, String libsPath, String cacheKey,
476 String abi) throws ZygoteStartFailedEx, IOException {
Robert Sesekded20982016-08-15 13:59:13 -0400477 synchronized(mLock) {
478 ZygoteState state = openZygoteSocketIfNeeded(abi);
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000479 state.writer.write("4");
Robert Sesekded20982016-08-15 13:59:13 -0400480 state.writer.newLine();
481
482 state.writer.write("--preload-package");
483 state.writer.newLine();
484
485 state.writer.write(packagePath);
486 state.writer.newLine();
487
488 state.writer.write(libsPath);
489 state.writer.newLine();
490
Torne (Richard Coles)04526702017-01-13 14:19:39 +0000491 state.writer.write(cacheKey);
492 state.writer.newLine();
493
Robert Sesekded20982016-08-15 13:59:13 -0400494 state.writer.flush();
Narayan Kamathbae484a2017-07-03 14:12:26 +0100495
496 return (state.inputStream.readInt() == 0);
Robert Sesekded20982016-08-15 13:59:13 -0400497 }
498 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000499
500 /**
501 * Instructs the zygote to preload the default set of classes and resources. Returns
502 * {@code true} if a preload was performed as a result of this call, and {@code false}
503 * otherwise. The latter usually means that the zygote eagerly preloaded at startup
504 * or due to a previous call to {@code preloadDefault}. Note that this call is synchronous.
505 */
506 public boolean preloadDefault(String abi) throws ZygoteStartFailedEx, IOException {
507 synchronized (mLock) {
508 ZygoteState state = openZygoteSocketIfNeeded(abi);
509 // Each query starts with the argument count (1 in this case)
510 state.writer.write("1");
511 state.writer.newLine();
512 state.writer.write("--preload-default");
513 state.writer.newLine();
514 state.writer.flush();
515
516 return (state.inputStream.readInt() == 0);
517 }
518 }
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100519
520 /**
521 * Try connecting to the Zygote over and over again until we hit a time-out.
522 * @param socketName The name of the socket to connect to.
523 */
524 public static void waitForConnectionToZygote(String socketName) {
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500525 final LocalSocketAddress address =
526 new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED);
527 waitForConnectionToZygote(address);
528 }
529
530 /**
531 * Try connecting to the Zygote over and over again until we hit a time-out.
532 * @param address The name of the socket to connect to.
533 */
534 public static void waitForConnectionToZygote(LocalSocketAddress address) {
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100535 for (int n = 20; n >= 0; n--) {
536 try {
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500537 final ZygoteState zs = ZygoteState.connect(address);
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100538 zs.close();
539 return;
540 } catch (IOException ioe) {
541 Log.w(LOG_TAG,
542 "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
543 }
544
545 try {
546 Thread.sleep(1000);
547 } catch (InterruptedException ie) {
548 }
549 }
Robert Sesek5ac8abf2018-01-26 14:26:53 -0500550 Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
Gustav Senntonf0c52b52017-04-27 17:00:50 +0100551 }
Robert Sesek8f8d1872016-03-18 16:52:57 -0400552}