blob: d067ae792e2d491294a9c2484f6b42ded9362355 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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 com.android.internal.os;
18
Narayan Kamath6ac7e672015-01-16 16:26:54 +000019import static android.system.OsConstants.F_SETFD;
Elliott Hughes3fe59512014-12-12 14:07:34 -080020import static android.system.OsConstants.O_CLOEXEC;
Andreas Gampecbc42142017-07-12 19:17:52 -070021import static android.system.OsConstants.POLLIN;
Elliott Hughesdac83f52014-12-15 11:00:25 -080022import static android.system.OsConstants.STDERR_FILENO;
23import static android.system.OsConstants.STDIN_FILENO;
24import static android.system.OsConstants.STDOUT_FILENO;
Chris Wailes682b4792019-01-11 16:14:43 -080025
Andreas Gampe27497c62017-07-21 11:41:00 -070026import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
Andreas Gampe27497c62017-07-21 11:41:00 -070027import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
Elliott Hughes3fe59512014-12-12 14:07:34 -080028
Andrei Onea89acbab2019-01-25 16:29:44 +000029import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.net.Credentials;
31import android.net.LocalSocket;
32import android.os.Process;
Narayan Kamathfbb32f62015-06-12 15:34:35 +010033import android.os.Trace;
Elliott Hughes860c5912014-04-28 19:19:13 -070034import android.system.ErrnoException;
35import android.system.Os;
Andreas Gampecbc42142017-07-12 19:17:52 -070036import android.system.StructPollfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.util.Log;
Chris Wailes682b4792019-01-11 16:14:43 -080038
Andrei Onea89acbab2019-01-25 16:29:44 +000039import com.android.internal.logging.MetricsLogger;
40import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
41
Narayan Kamath37ad4b02015-01-19 16:05:24 +000042import dalvik.system.VMRuntime;
Chris Wailes682b4792019-01-11 16:14:43 -080043
44import libcore.io.IoUtils;
45
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import java.io.BufferedReader;
Andreas Gampecbc42142017-07-12 19:17:52 -070047import java.io.ByteArrayInputStream;
Jeff Brownebed7d62011-05-16 17:08:42 -070048import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.io.DataOutputStream;
50import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.io.IOException;
52import java.io.InputStreamReader;
Narayan Kamathc41638c2014-04-07 13:56:15 +010053import java.nio.charset.StandardCharsets;
Jeff Brownebed7d62011-05-16 17:08:42 -070054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055/**
56 * A connection that can make spawn requests.
57 */
58class ZygoteConnection {
59 private static final String TAG = "Zygote";
60
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 * The command socket.
63 *
64 * mSocket is retained in the child process in "peer wait" mode, so
65 * that it closes when the child process terminates. In other cases,
66 * it is closed in the peer.
67 */
68 private final LocalSocket mSocket;
69 private final DataOutputStream mSocketOutStream;
70 private final BufferedReader mSocketReader;
71 private final Credentials peer;
Narayan Kamathc41638c2014-04-07 13:56:15 +010072 private final String abiList;
Narayan Kamathbf99d062017-07-05 14:45:38 +010073 private boolean isEof;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074
75 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 * Constructs instance from connected socket.
77 *
78 * @param socket non-null; connected socket
Narayan Kamathc41638c2014-04-07 13:56:15 +010079 * @param abiList non-null; a list of ABIs this zygote supports.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 * @throws IOException
81 */
Narayan Kamathc41638c2014-04-07 13:56:15 +010082 ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 mSocket = socket;
Narayan Kamathc41638c2014-04-07 13:56:15 +010084 this.abiList = abiList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085
86 mSocketOutStream
87 = new DataOutputStream(socket.getOutputStream());
88
89 mSocketReader = new BufferedReader(
90 new InputStreamReader(socket.getInputStream()), 256);
91
92 mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
dcashmanfc4c0bf82015-03-05 17:17:47 -080093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 try {
95 peer = mSocket.getPeerCredentials();
96 } catch (IOException ex) {
97 Log.e(TAG, "Cannot read peer credentials", ex);
98 throw ex;
99 }
Narayan Kamathbf99d062017-07-05 14:45:38 +0100100
101 isEof = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 }
103
104 /**
105 * Returns the file descriptor of the associated socket.
106 *
107 * @return null-ok; file descriptor
108 */
Chris Wailes682b4792019-01-11 16:14:43 -0800109 FileDescriptor getFileDescriptor() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 return mSocket.getFileDescriptor();
111 }
112
113 /**
Narayan Kamathbf99d062017-07-05 14:45:38 +0100114 * Reads one start command from the command socket. If successful, a child is forked and a
115 * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
116 * process. {@code null} is always returned in the parent process (the zygote).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 *
Narayan Kamathbf99d062017-07-05 14:45:38 +0100118 * If the client closes the socket, an {@code EOF} condition is set, which callers can test
119 * for by calling {@code ZygoteConnection.isClosedByPeer}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100121 Runnable processOneCommand(ZygoteServer zygoteServer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 String args[];
Chris Wailes682b4792019-01-11 16:14:43 -0800123 ZygoteArguments parsedArgs = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 FileDescriptor[] descriptors;
125
126 try {
Chris Wailes682b4792019-01-11 16:14:43 -0800127 args = Zygote.readArgumentList(mSocketReader);
128
129 // TODO (chriswailes): Remove this and add an assert.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 descriptors = mSocket.getAncillaryFileDescriptors();
131 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100132 throw new IllegalStateException("IOException on command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 }
134
Narayan Kamathbf99d062017-07-05 14:45:38 +0100135 // readArgumentList returns null only when it has reached EOF with no available
136 // data to read. This will only happen when the remote socket has disconnected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 if (args == null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100138 isEof = true;
139 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 }
141
Jeff Brownebed7d62011-05-16 17:08:42 -0700142 int pid = -1;
143 FileDescriptor childPipeFd = null;
144 FileDescriptor serverPipeFd = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
Chris Wailes682b4792019-01-11 16:14:43 -0800146 parsedArgs = new ZygoteArguments(args);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100147
Chris Wailes682b4792019-01-11 16:14:43 -0800148 if (parsedArgs.mAbiListQuery) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100149 handleAbiListQuery();
150 return null;
151 }
Narayan Kamathc41638c2014-04-07 13:56:15 +0100152
Chris Wailes682b4792019-01-11 16:14:43 -0800153 if (parsedArgs.mPidQuery) {
Andreas Gampe8444dca2018-05-01 13:31:28 -0700154 handlePidQuery();
155 return null;
156 }
157
Chris Wailes682b4792019-01-11 16:14:43 -0800158 if (parsedArgs.mPreloadDefault) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100159 handlePreload();
160 return null;
161 }
Narayan Kamath5a3d0c62016-11-09 15:35:18 +0000162
Chris Wailes682b4792019-01-11 16:14:43 -0800163 if (parsedArgs.mPreloadPackage != null) {
164 handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
165 parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100166 return null;
167 }
Robert Sesekded20982016-08-15 13:59:13 -0400168
Chris Wailes682b4792019-01-11 16:14:43 -0800169 if (parsedArgs.mApiBlacklistExemptions != null) {
170 handleApiBlacklistExemptions(parsedArgs.mApiBlacklistExemptions);
Mathew Inwood8faeab82018-03-16 14:26:08 +0000171 return null;
172 }
173
Chris Wailes682b4792019-01-11 16:14:43 -0800174 if (parsedArgs.mHiddenApiAccessLogSampleRate != -1) {
175 handleHiddenApiAccessLogSampleRate(parsedArgs.mHiddenApiAccessLogSampleRate);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100176 return null;
177 }
178
Chris Wailes682b4792019-01-11 16:14:43 -0800179 if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
180 throw new ZygoteSecurityException("Client may not specify capabilities: "
181 + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
182 + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
Narayan Kamathbf99d062017-07-05 14:45:38 +0100183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184
Chris Wailes682b4792019-01-11 16:14:43 -0800185 Zygote.applyUidSecurityPolicy(parsedArgs, peer);
186 Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Jeff Brownebed7d62011-05-16 17:08:42 -0700187
Chris Wailes682b4792019-01-11 16:14:43 -0800188 Zygote.applyDebuggerSystemProperty(parsedArgs);
189 Zygote.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
Narayan Kamathbf99d062017-07-05 14:45:38 +0100191 int[][] rlimits = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Chris Wailes682b4792019-01-11 16:14:43 -0800193 if (parsedArgs.mRLimits != null) {
194 rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196
Narayan Kamathbf99d062017-07-05 14:45:38 +0100197 int[] fdsToIgnore = null;
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800198
Chris Wailes682b4792019-01-11 16:14:43 -0800199 if (parsedArgs.mInvokeWith != null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100200 try {
Elliott Hughes3fe59512014-12-12 14:07:34 -0800201 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
Jeff Brownebed7d62011-05-16 17:08:42 -0700202 childPipeFd = pipeFds[1];
203 serverPipeFd = pipeFds[0];
Narayan Kamath6ac7e672015-01-16 16:26:54 +0000204 Os.fcntlInt(childPipeFd, F_SETFD, 0);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100205 fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
206 } catch (ErrnoException errnoEx) {
207 throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
Jeff Brownebed7d62011-05-16 17:08:42 -0700208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 }
210
Narayan Kamathbf99d062017-07-05 14:45:38 +0100211 /**
212 * In order to avoid leaking descriptors to the Zygote child,
213 * the native code must close the two Zygote socket descriptors
214 * in the child process before it switches from Zygote-root to
215 * the UID and privileges of the application being launched.
216 *
217 * In order to avoid "bad file descriptor" errors when the
218 * two LocalSocket objects are closed, the Posix file
219 * descriptors are released via a dup2() call which closes
220 * the socket and substitutes an open descriptor to /dev/null.
221 */
222
223 int [] fdsToClose = { -1, -1 };
224
225 FileDescriptor fd = mSocket.getFileDescriptor();
226
227 if (fd != null) {
228 fdsToClose[0] = fd.getInt$();
229 }
230
Chris Wailescffbf1c2019-01-11 17:13:00 -0800231 fd = zygoteServer.getZygoteSocketFileDescriptor();
Narayan Kamathbf99d062017-07-05 14:45:38 +0100232
233 if (fd != null) {
234 fdsToClose[1] = fd.getInt$();
235 }
236
237 fd = null;
238
Chris Wailes682b4792019-01-11 16:14:43 -0800239 pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
240 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
241 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
242 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100243
Jeff Brownebed7d62011-05-16 17:08:42 -0700244 try {
245 if (pid == 0) {
246 // in child
Narayan Kamathbf99d062017-07-05 14:45:38 +0100247 zygoteServer.setForkChild();
248
Simon Baldwinba816e02016-01-19 16:34:54 +0000249 zygoteServer.closeServerSocket();
Jeff Brownebed7d62011-05-16 17:08:42 -0700250 IoUtils.closeQuietly(serverPipeFd);
251 serverPipeFd = null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700252
Robert Sesekd0a190df2018-02-12 18:46:01 -0500253 return handleChildProc(parsedArgs, descriptors, childPipeFd,
Chris Wailes682b4792019-01-11 16:14:43 -0800254 parsedArgs.mStartChildZygote);
Jeff Brownebed7d62011-05-16 17:08:42 -0700255 } else {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100256 // In the parent. A pid < 0 indicates a failure and will be handled in
257 // handleParentProc.
Jeff Brownebed7d62011-05-16 17:08:42 -0700258 IoUtils.closeQuietly(childPipeFd);
259 childPipeFd = null;
Narayan Kamathbf99d062017-07-05 14:45:38 +0100260 handleParentProc(pid, descriptors, serverPipeFd);
261 return null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700262 }
263 } finally {
264 IoUtils.closeQuietly(childPipeFd);
265 IoUtils.closeQuietly(serverPipeFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 }
267 }
268
Narayan Kamathbf99d062017-07-05 14:45:38 +0100269 private void handleAbiListQuery() {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100270 try {
271 final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
272 mSocketOutStream.writeInt(abiListBytes.length);
273 mSocketOutStream.write(abiListBytes);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100274 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100275 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100276 }
277 }
278
Andreas Gampe8444dca2018-05-01 13:31:28 -0700279 private void handlePidQuery() {
280 try {
281 String pidString = String.valueOf(Process.myPid());
282 final byte[] pidStringBytes = pidString.getBytes(StandardCharsets.US_ASCII);
283 mSocketOutStream.writeInt(pidStringBytes.length);
284 mSocketOutStream.write(pidStringBytes);
285 } catch (IOException ioe) {
286 throw new IllegalStateException("Error writing to command socket", ioe);
287 }
288 }
289
Narayan Kamath669afcc2017-02-06 20:24:08 +0000290 /**
291 * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
292 * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
293 * if no preload was initiated. The latter implies that the zygote is not configured to load
294 * resources lazy or that the zygote has already handled a previous request to handlePreload.
295 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100296 private void handlePreload() {
Narayan Kamath669afcc2017-02-06 20:24:08 +0000297 try {
298 if (isPreloadComplete()) {
299 mSocketOutStream.writeInt(1);
300 } else {
301 preload();
302 mSocketOutStream.writeInt(0);
303 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000304 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100305 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000306 }
307 }
308
Mathew Inwood8faeab82018-03-16 14:26:08 +0000309 private void handleApiBlacklistExemptions(String[] exemptions) {
310 try {
311 ZygoteInit.setApiBlacklistExemptions(exemptions);
312 mSocketOutStream.writeInt(0);
313 } catch (IOException ioe) {
314 throw new IllegalStateException("Error writing to command socket", ioe);
315 }
316 }
317
Andrei Oneae6efa052019-02-06 14:44:22 +0000318 private static class HiddenApiUsageLogger implements VMRuntime.HiddenApiUsageLogger {
Andrei Onea89acbab2019-01-25 16:29:44 +0000319
320 private final MetricsLogger mMetricsLogger = new MetricsLogger();
Andrei Oneae6efa052019-02-06 14:44:22 +0000321 private static HiddenApiUsageLogger sInstance = new HiddenApiUsageLogger();
322
323 public static HiddenApiUsageLogger getInstance() {
324 return HiddenApiUsageLogger.sInstance;
325 }
Andrei Onea89acbab2019-01-25 16:29:44 +0000326
327 public void hiddenApiUsed(String packageName, String signature,
328 int accessMethod, boolean accessDenied) {
329 int accessMethodMetric = HiddenApiUsageLogger.ACCESS_METHOD_NONE;
330 switch(accessMethod) {
331 case HiddenApiUsageLogger.ACCESS_METHOD_NONE:
332 accessMethodMetric = MetricsEvent.ACCESS_METHOD_NONE;
333 break;
334 case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION:
335 accessMethodMetric = MetricsEvent.ACCESS_METHOD_REFLECTION;
336 break;
337 case HiddenApiUsageLogger.ACCESS_METHOD_JNI:
338 accessMethodMetric = MetricsEvent.ACCESS_METHOD_JNI;
339 break;
340 case HiddenApiUsageLogger.ACCESS_METHOD_LINKING:
341 accessMethodMetric = MetricsEvent.ACCESS_METHOD_LINKING;
342 break;
343 }
344 LogMaker logMaker = new LogMaker(MetricsEvent.ACTION_HIDDEN_API_ACCESSED)
345 .setPackageName(packageName)
346 .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_SIGNATURE, signature)
347 .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_METHOD,
348 accessMethodMetric);
349 if (accessDenied) {
350 logMaker.addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_DENIED, 1);
351 }
352 mMetricsLogger.write(logMaker);
353 }
354 }
355
356 private void handleHiddenApiAccessLogSampleRate(int samplingRate) {
Mathew Inwood04194fe2018-04-04 14:48:03 +0100357 try {
Andrei Onea89acbab2019-01-25 16:29:44 +0000358 ZygoteInit.setHiddenApiAccessLogSampleRate(samplingRate);
Andrei Oneae6efa052019-02-06 14:44:22 +0000359 ZygoteInit.setHiddenApiUsageLogger(HiddenApiUsageLogger.getInstance());
Mathew Inwood04194fe2018-04-04 14:48:03 +0100360 mSocketOutStream.writeInt(0);
361 } catch (IOException ioe) {
362 throw new IllegalStateException("Error writing to command socket", ioe);
363 }
364 }
365
Narayan Kamath669afcc2017-02-06 20:24:08 +0000366 protected void preload() {
367 ZygoteInit.lazyPreload();
368 }
369
370 protected boolean isPreloadComplete() {
371 return ZygoteInit.isPreloadComplete();
Torne (Richard Coles)bb658932017-01-05 16:11:06 +0000372 }
373
Narayan Kamath24a33062017-07-03 14:12:26 +0100374 protected DataOutputStream getSocketOutputStream() {
375 return mSocketOutStream;
376 }
377
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500378 protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
379 String cacheKey) {
Robert Sesekded20982016-08-15 13:59:13 -0400380 throw new RuntimeException("Zyogte does not support package preloading");
381 }
382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 /**
384 * Closes socket associated with this connection.
385 */
386 void closeSocket() {
387 try {
388 mSocket.close();
389 } catch (IOException ex) {
390 Log.e(TAG, "Exception while closing command "
391 + "socket in parent", ex);
392 }
393 }
394
Narayan Kamathbf99d062017-07-05 14:45:38 +0100395 boolean isClosedByPeer() {
396 return isEof;
397 }
398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 * Handles post-fork setup of child proc, closing sockets as appropriate,
401 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
402 * if successful or returning if failed.
403 *
404 * @param parsedArgs non-null; zygote args
405 * @param descriptors null-ok; new file descriptors for stdio if available.
Jeff Brownebed7d62011-05-16 17:08:42 -0700406 * @param pipeFd null-ok; pipe for communication back to Zygote.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500407 * @param isZygote whether this new child process is itself a new Zygote.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 */
Chris Wailes682b4792019-01-11 16:14:43 -0800409 private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500410 FileDescriptor pipeFd, boolean isZygote) {
Dave Platt89d4c892014-02-05 17:06:42 -0800411 /**
412 * By the time we get here, the native code has closed the two actual Zygote
413 * socket connections, and substituted /dev/null in their place. The LocalSocket
414 * objects still need to be closed properly.
415 */
416
Nick Kralevich468f6c12013-01-30 08:45:03 -0800417 closeSocket();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 if (descriptors != null) {
419 try {
Elliott Hughesdac83f52014-12-15 11:00:25 -0800420 Os.dup2(descriptors[0], STDIN_FILENO);
421 Os.dup2(descriptors[1], STDOUT_FILENO);
422 Os.dup2(descriptors[2], STDERR_FILENO);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423
424 for (FileDescriptor fd: descriptors) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700425 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 }
Elliott Hughesdac83f52014-12-15 11:00:25 -0800427 } catch (ErrnoException ex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 Log.e(TAG, "Error reopening stdio", ex);
429 }
430 }
431
Chris Wailes682b4792019-01-11 16:14:43 -0800432 if (parsedArgs.mNiceName != null) {
433 Process.setArgV0(parsedArgs.mNiceName);
Jeff Brownebed7d62011-05-16 17:08:42 -0700434 }
435
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100436 // End of the postFork event.
437 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Chris Wailes682b4792019-01-11 16:14:43 -0800438 if (parsedArgs.mInvokeWith != null) {
439 WrapperInit.execApplication(parsedArgs.mInvokeWith,
440 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000441 VMRuntime.getCurrentInstructionSet(),
Chris Wailes682b4792019-01-11 16:14:43 -0800442 pipeFd, parsedArgs.mRemainingArgs);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100443
444 // Should not get here.
445 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
Jeff Brownebed7d62011-05-16 17:08:42 -0700446 } else {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500447 if (!isZygote) {
Chris Wailes682b4792019-01-11 16:14:43 -0800448 return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
449 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500450 } else {
Chris Wailes682b4792019-01-11 16:14:43 -0800451 return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
452 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 }
455 }
456
457 /**
458 * Handles post-fork cleanup of parent proc
459 *
460 * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
461 * if &lt; 0;
462 * @param descriptors null-ok; file descriptors for child's new stdio if
463 * specified.
Jeff Brownebed7d62011-05-16 17:08:42 -0700464 * @param pipeFd null-ok; pipe for communication with child.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100466 private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700467 if (pid > 0) {
468 setChildPgid(pid);
469 }
470
471 if (descriptors != null) {
472 for (FileDescriptor fd: descriptors) {
473 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 }
475 }
476
Jeff Brown3f9dd282011-07-08 20:02:19 -0700477 boolean usingWrapper = false;
Jeff Brownebed7d62011-05-16 17:08:42 -0700478 if (pipeFd != null && pid > 0) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700479 int innerPid = -1;
480 try {
Andreas Gampecbc42142017-07-12 19:17:52 -0700481 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
482 // bail) happens in a timely manner.
Andreas Gampecbc42142017-07-12 19:17:52 -0700483 final int BYTES_REQUIRED = 4; // Bytes in an int.
484
485 StructPollfd fds[] = new StructPollfd[] {
486 new StructPollfd()
487 };
488
489 byte data[] = new byte[BYTES_REQUIRED];
490
Andreas Gampe27497c62017-07-21 11:41:00 -0700491 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
Andreas Gampecbc42142017-07-12 19:17:52 -0700492 int dataIndex = 0;
493 long startTime = System.nanoTime();
494
495 while (dataIndex < data.length && remainingSleepTime > 0) {
496 fds[0].fd = pipeFd;
497 fds[0].events = (short) POLLIN;
498 fds[0].revents = 0;
499 fds[0].userData = null;
500
501 int res = android.system.Os.poll(fds, remainingSleepTime);
502 long endTime = System.nanoTime();
Andreas Gampe27497c62017-07-21 11:41:00 -0700503 int elapsedTimeMs = (int)((endTime - startTime) / 1000000l);
504 remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
Andreas Gampecbc42142017-07-12 19:17:52 -0700505
506 if (res > 0) {
507 if ((fds[0].revents & POLLIN) != 0) {
508 // Only read one byte, so as not to block.
509 int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
510 if (readBytes < 0) {
511 throw new RuntimeException("Some error");
512 }
513 dataIndex += readBytes;
514 } else {
515 // Error case. revents should contain one of the error bits.
516 break;
517 }
518 } else if (res == 0) {
519 Log.w(TAG, "Timed out waiting for child.");
520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 }
Andreas Gampecbc42142017-07-12 19:17:52 -0700522
523 if (dataIndex == data.length) {
524 DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
525 innerPid = is.readInt();
526 }
527
528 if (innerPid == -1) {
529 Log.w(TAG, "Error reading pid from wrapped process, child may have died");
530 }
531 } catch (Exception ex) {
532 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700534
535 // Ensure that the pid reported by the wrapped process is either the
536 // child process that we forked, or a descendant of it.
537 if (innerPid > 0) {
538 int parentPid = innerPid;
539 while (parentPid > 0 && parentPid != pid) {
540 parentPid = Process.getParentPid(parentPid);
541 }
542 if (parentPid > 0) {
543 Log.i(TAG, "Wrapped process has pid " + innerPid);
544 pid = innerPid;
Jeff Brown3f9dd282011-07-08 20:02:19 -0700545 usingWrapper = true;
Jeff Brownebed7d62011-05-16 17:08:42 -0700546 } else {
547 Log.w(TAG, "Wrapped process reported a pid that is not a child of "
548 + "the process that we forked: childPid=" + pid
549 + " innerPid=" + innerPid);
550 }
551 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 }
553
554 try {
555 mSocketOutStream.writeInt(pid);
Jeff Brown3f9dd282011-07-08 20:02:19 -0700556 mSocketOutStream.writeBoolean(usingWrapper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100558 throw new IllegalStateException("Error writing to command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 }
561
Jeff Brownebed7d62011-05-16 17:08:42 -0700562 private void setChildPgid(int pid) {
563 // Try to move the new child into the peer's process group.
564 try {
Elliott Hughes26b56e62014-12-17 12:28:29 -0800565 Os.setpgid(pid, Os.getpgid(peer.getPid()));
566 } catch (ErrnoException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700567 // This exception is expected in the case where
568 // the peer is not in our session
569 // TODO get rid of this log message in the case where
570 // getsid(0) != getsid(peer.getPid())
571 Log.i(TAG, "Zygote: setpgid failed. This is "
572 + "normal if peer is not in our session");
573 }
574 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575}