blob: 0d4ec41adf6e2b2591bd3441ef51c942ff2edf23 [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;
Sudheer Shankad81b1d72018-09-05 16:37:30 -070022
Andreas Gampe27497c62017-07-21 11:41:00 -070023import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
Andreas Gampe27497c62017-07-21 11:41:00 -070024import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
Elliott Hughes3fe59512014-12-12 14:07:34 -080025
Andrei Onea15884392019-03-22 17:28:11 +000026import android.annotation.UnsupportedAppUsage;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010027import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.net.Credentials;
29import android.net.LocalSocket;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010030import android.os.Parcel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.Process;
Narayan Kamathfbb32f62015-06-12 15:34:35 +010032import android.os.Trace;
Elliott Hughes860c5912014-04-28 19:19:13 -070033import android.system.ErrnoException;
34import android.system.Os;
Andreas Gampecbc42142017-07-12 19:17:52 -070035import android.system.StructPollfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.util.Log;
Andrei Onea6cd1b702019-01-25 16:29:44 +000037
Narayan Kamath37ad4b02015-01-19 16:05:24 +000038import dalvik.system.VMRuntime;
Sudheer Shankad81b1d72018-09-05 16:37:30 -070039
40import libcore.io.IoUtils;
41
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import java.io.BufferedReader;
Andreas Gampecbc42142017-07-12 19:17:52 -070043import java.io.ByteArrayInputStream;
Jeff Brownebed7d62011-05-16 17:08:42 -070044import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import java.io.DataOutputStream;
46import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import java.io.IOException;
48import java.io.InputStreamReader;
Narayan Kamathc41638c2014-04-07 13:56:15 +010049import java.nio.charset.StandardCharsets;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010050import java.util.Base64;
Chris Wailes49b79e52019-04-26 15:07:47 -070051import java.util.concurrent.TimeUnit;
Mathew Inwood8faeab82018-03-16 14:26:08 +000052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053/**
54 * A connection that can make spawn requests.
55 */
56class ZygoteConnection {
57 private static final String TAG = "Zygote";
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 * The command socket.
61 *
62 * mSocket is retained in the child process in "peer wait" mode, so
63 * that it closes when the child process terminates. In other cases,
64 * it is closed in the peer.
65 */
Andrei Onea15884392019-03-22 17:28:11 +000066 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 private final LocalSocket mSocket;
Andrei Onea15884392019-03-22 17:28:11 +000068 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 private final DataOutputStream mSocketOutStream;
70 private final BufferedReader mSocketReader;
Andrei Onea15884392019-03-22 17:28:11 +000071 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 private final Credentials peer;
Narayan Kamathc41638c2014-04-07 13:56:15 +010073 private final String abiList;
Narayan Kamathbf99d062017-07-05 14:45:38 +010074 private boolean isEof;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075
76 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 * Constructs instance from connected socket.
78 *
79 * @param socket non-null; connected socket
Narayan Kamathc41638c2014-04-07 13:56:15 +010080 * @param abiList non-null; a list of ABIs this zygote supports.
Chris Wailes49b79e52019-04-26 15:07:47 -070081 * @throws IOException If obtaining the peer credentials fails
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 */
Narayan Kamathc41638c2014-04-07 13:56:15 +010083 ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 mSocket = socket;
Narayan Kamathc41638c2014-04-07 13:56:15 +010085 this.abiList = abiList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
Chris Wailes49b79e52019-04-26 15:07:47 -070087 mSocketOutStream = new DataOutputStream(socket.getOutputStream());
88 mSocketReader =
89 new BufferedReader(
90 new InputStreamReader(socket.getInputStream()), Zygote.SOCKET_BUFFER_SIZE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
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 Wailes2be26262019-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) {
Chris Wailes49b79e52019-04-26 15:07:47 -0700122 String[] args;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
124 try {
Chris Wailes2be26262019-01-11 16:14:43 -0800125 args = Zygote.readArgumentList(mSocketReader);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100127 throw new IllegalStateException("IOException on command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 }
129
Narayan Kamathbf99d062017-07-05 14:45:38 +0100130 // readArgumentList returns null only when it has reached EOF with no available
131 // data to read. This will only happen when the remote socket has disconnected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 if (args == null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100133 isEof = true;
134 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 }
136
Chris Wailes49b79e52019-04-26 15:07:47 -0700137 int pid;
Jeff Brownebed7d62011-05-16 17:08:42 -0700138 FileDescriptor childPipeFd = null;
139 FileDescriptor serverPipeFd = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
Chris Wailes49b79e52019-04-26 15:07:47 -0700141 ZygoteArguments parsedArgs = new ZygoteArguments(args);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100142
David Srbecky6d0d7062019-08-05 15:43:34 +0100143 if (parsedArgs.mBootCompleted) {
144 handleBootCompleted();
145 return null;
146 }
147
Chris Wailes2be26262019-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 Wailes2be26262019-01-11 16:14:43 -0800153 if (parsedArgs.mPidQuery) {
Andreas Gampe8444dca2018-05-01 13:31:28 -0700154 handlePidQuery();
155 return null;
156 }
157
Chris Wailes7e797b62019-02-22 18:29:22 -0800158 if (parsedArgs.mUsapPoolStatusSpecified) {
159 return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
Chris Wailesdb132a32019-02-20 10:49:27 -0800160 }
161
Chris Wailes2be26262019-01-11 16:14:43 -0800162 if (parsedArgs.mPreloadDefault) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100163 handlePreload();
164 return null;
165 }
Narayan Kamath5a3d0c62016-11-09 15:35:18 +0000166
Chris Wailes2be26262019-01-11 16:14:43 -0800167 if (parsedArgs.mPreloadPackage != null) {
168 handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
169 parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100170 return null;
171 }
Robert Sesekded20982016-08-15 13:59:13 -0400172
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100173 if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
174 byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
175 Parcel appInfoParcel = Parcel.obtain();
176 appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
177 appInfoParcel.setDataPosition(0);
178 ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
179 appInfoParcel.recycle();
180 if (appInfo != null) {
181 handlePreloadApp(appInfo);
182 } else {
183 throw new IllegalArgumentException("Failed to deserialize --preload-app");
184 }
185 return null;
186 }
187
Chris Wailes2be26262019-01-11 16:14:43 -0800188 if (parsedArgs.mApiBlacklistExemptions != null) {
Chris Wailes01060e62019-02-21 13:46:52 -0800189 return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
Mathew Inwood8faeab82018-03-16 14:26:08 +0000190 }
191
Andrei Oneae8e150d2019-02-18 18:27:11 +0000192 if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
193 || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
Chris Wailes01060e62019-02-21 13:46:52 -0800194 return handleHiddenApiAccessLogSampleRate(zygoteServer,
Andrei Oneae8e150d2019-02-18 18:27:11 +0000195 parsedArgs.mHiddenApiAccessLogSampleRate,
196 parsedArgs.mHiddenApiAccessStatslogSampleRate);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100197 }
198
Chris Wailes2be26262019-01-11 16:14:43 -0800199 if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
200 throw new ZygoteSecurityException("Client may not specify capabilities: "
201 + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
202 + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
Narayan Kamathbf99d062017-07-05 14:45:38 +0100203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
Chris Wailes2be26262019-01-11 16:14:43 -0800205 Zygote.applyUidSecurityPolicy(parsedArgs, peer);
206 Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Jeff Brownebed7d62011-05-16 17:08:42 -0700207
Chris Wailes2be26262019-01-11 16:14:43 -0800208 Zygote.applyDebuggerSystemProperty(parsedArgs);
209 Zygote.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
Narayan Kamathbf99d062017-07-05 14:45:38 +0100211 int[][] rlimits = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212
Chris Wailes2be26262019-01-11 16:14:43 -0800213 if (parsedArgs.mRLimits != null) {
214 rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
Narayan Kamathbf99d062017-07-05 14:45:38 +0100217 int[] fdsToIgnore = null;
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800218
Chris Wailes2be26262019-01-11 16:14:43 -0800219 if (parsedArgs.mInvokeWith != null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100220 try {
Elliott Hughes3fe59512014-12-12 14:07:34 -0800221 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
Jeff Brownebed7d62011-05-16 17:08:42 -0700222 childPipeFd = pipeFds[1];
223 serverPipeFd = pipeFds[0];
Narayan Kamath6ac7e672015-01-16 16:26:54 +0000224 Os.fcntlInt(childPipeFd, F_SETFD, 0);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100225 fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
226 } catch (ErrnoException errnoEx) {
227 throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
Jeff Brownebed7d62011-05-16 17:08:42 -0700228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 }
230
Chris Wailes49b79e52019-04-26 15:07:47 -0700231 /*
Narayan Kamathbf99d062017-07-05 14:45:38 +0100232 * In order to avoid leaking descriptors to the Zygote child,
233 * the native code must close the two Zygote socket descriptors
234 * in the child process before it switches from Zygote-root to
235 * the UID and privileges of the application being launched.
236 *
237 * In order to avoid "bad file descriptor" errors when the
238 * two LocalSocket objects are closed, the Posix file
239 * descriptors are released via a dup2() call which closes
240 * the socket and substitutes an open descriptor to /dev/null.
241 */
242
243 int [] fdsToClose = { -1, -1 };
244
245 FileDescriptor fd = mSocket.getFileDescriptor();
246
247 if (fd != null) {
248 fdsToClose[0] = fd.getInt$();
249 }
250
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800251 fd = zygoteServer.getZygoteSocketFileDescriptor();
Narayan Kamathbf99d062017-07-05 14:45:38 +0100252
253 if (fd != null) {
254 fdsToClose[1] = fd.getInt$();
255 }
256
Chris Wailes2be26262019-01-11 16:14:43 -0800257 pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
258 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
259 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
Sudheer Shanka64501e52019-04-29 10:46:26 -0700260 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100261
Jeff Brownebed7d62011-05-16 17:08:42 -0700262 try {
263 if (pid == 0) {
264 // in child
Narayan Kamathbf99d062017-07-05 14:45:38 +0100265 zygoteServer.setForkChild();
266
Simon Baldwinba816e02016-01-19 16:34:54 +0000267 zygoteServer.closeServerSocket();
Jeff Brownebed7d62011-05-16 17:08:42 -0700268 IoUtils.closeQuietly(serverPipeFd);
269 serverPipeFd = null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700270
Chris Wailes72c3b222019-04-26 14:36:34 -0700271 return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
Jeff Brownebed7d62011-05-16 17:08:42 -0700272 } else {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100273 // In the parent. A pid < 0 indicates a failure and will be handled in
274 // handleParentProc.
Jeff Brownebed7d62011-05-16 17:08:42 -0700275 IoUtils.closeQuietly(childPipeFd);
276 childPipeFd = null;
Chris Wailes72c3b222019-04-26 14:36:34 -0700277 handleParentProc(pid, serverPipeFd);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100278 return null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700279 }
280 } finally {
281 IoUtils.closeQuietly(childPipeFd);
282 IoUtils.closeQuietly(serverPipeFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 }
284 }
285
Narayan Kamathbf99d062017-07-05 14:45:38 +0100286 private void handleAbiListQuery() {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100287 try {
288 final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
289 mSocketOutStream.writeInt(abiListBytes.length);
290 mSocketOutStream.write(abiListBytes);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100291 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100292 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100293 }
294 }
295
Andreas Gampe8444dca2018-05-01 13:31:28 -0700296 private void handlePidQuery() {
297 try {
298 String pidString = String.valueOf(Process.myPid());
299 final byte[] pidStringBytes = pidString.getBytes(StandardCharsets.US_ASCII);
300 mSocketOutStream.writeInt(pidStringBytes.length);
301 mSocketOutStream.write(pidStringBytes);
302 } catch (IOException ioe) {
303 throw new IllegalStateException("Error writing to command socket", ioe);
304 }
305 }
306
David Srbecky6d0d7062019-08-05 15:43:34 +0100307 private void handleBootCompleted() {
Josh Gao27361362019-10-02 16:01:51 -0700308 try {
309 mSocketOutStream.writeInt(0);
310 } catch (IOException ioe) {
311 throw new IllegalStateException("Error writing to command socket", ioe);
312 }
313
David Srbecky6d0d7062019-08-05 15:43:34 +0100314 VMRuntime.bootCompleted();
315 }
316
Narayan Kamath669afcc2017-02-06 20:24:08 +0000317 /**
318 * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
319 * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
320 * if no preload was initiated. The latter implies that the zygote is not configured to load
321 * resources lazy or that the zygote has already handled a previous request to handlePreload.
322 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100323 private void handlePreload() {
Narayan Kamath669afcc2017-02-06 20:24:08 +0000324 try {
325 if (isPreloadComplete()) {
326 mSocketOutStream.writeInt(1);
327 } else {
328 preload();
329 mSocketOutStream.writeInt(0);
330 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000331 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100332 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000333 }
334 }
335
Chris Wailes7e797b62019-02-22 18:29:22 -0800336 private Runnable stateChangeWithUsapPoolReset(ZygoteServer zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800337 Runnable stateChangeCode) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000338 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800339 if (zygoteServer.isUsapPoolEnabled()) {
Chris Wailesf68c4e22019-06-05 16:07:50 -0700340 Log.i(TAG, "Emptying USAP Pool due to state change.");
Chris Wailes7e797b62019-02-22 18:29:22 -0800341 Zygote.emptyUsapPool();
Chris Wailes01060e62019-02-21 13:46:52 -0800342 }
343
344 stateChangeCode.run();
345
Chris Wailes7e797b62019-02-22 18:29:22 -0800346 if (zygoteServer.isUsapPoolEnabled()) {
Chris Wailes01060e62019-02-21 13:46:52 -0800347 Runnable fpResult =
Chris Wailes7e797b62019-02-22 18:29:22 -0800348 zygoteServer.fillUsapPool(
Mathew Inwood51c53b42019-05-24 14:06:10 +0100349 new int[]{mSocket.getFileDescriptor().getInt$()});
Chris Wailes01060e62019-02-21 13:46:52 -0800350
351 if (fpResult != null) {
352 zygoteServer.setForkChild();
353 return fpResult;
Chris Wailesf68c4e22019-06-05 16:07:50 -0700354 } else {
355 Log.i(TAG, "Finished refilling USAP Pool after state change.");
Chris Wailes01060e62019-02-21 13:46:52 -0800356 }
357 }
358
Mathew Inwood8faeab82018-03-16 14:26:08 +0000359 mSocketOutStream.writeInt(0);
Chris Wailes01060e62019-02-21 13:46:52 -0800360
361 return null;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000362 } catch (IOException ioe) {
363 throw new IllegalStateException("Error writing to command socket", ioe);
364 }
365 }
366
Chris Wailes01060e62019-02-21 13:46:52 -0800367 /**
368 * Makes the necessary changes to implement a new API blacklist exemption policy, and then
369 * responds to the system server, letting it know that the task has been completed.
370 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800371 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
372 * pool is enabled all existing USAPs have an incorrect API blacklist exemption list. To
Chris Wailes01060e62019-02-21 13:46:52 -0800373 * properly handle this request the pool must be emptied and refilled. This process can return
374 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
375 *
376 * @param zygoteServer The server object that received the request
377 * @param exemptions The new exemption list.
Chris Wailes7e797b62019-02-22 18:29:22 -0800378 * @return A Runnable object representing a new app in any USAPs spawned from here; the
Chris Wailes01060e62019-02-21 13:46:52 -0800379 * zygote process will always receive a null value from this function.
380 */
381 private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800382 return stateChangeWithUsapPoolReset(zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800383 () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
384 }
385
Chris Wailes7e797b62019-02-22 18:29:22 -0800386 private Runnable handleUsapPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800387 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800388 Runnable fpResult = zygoteServer.setUsapPoolStatus(newStatus, mSocket);
Chris Wailesdb132a32019-02-20 10:49:27 -0800389
390 if (fpResult == null) {
391 mSocketOutStream.writeInt(0);
392 } else {
393 zygoteServer.setForkChild();
394 }
395
396 return fpResult;
Narayan Kamath669afcc2017-02-06 20:24:08 +0000397 } catch (IOException ioe) {
398 throw new IllegalStateException("Error writing to command socket", ioe);
399 }
400 }
401
Chris Wailes01060e62019-02-21 13:46:52 -0800402 /**
403 * Changes the API access log sample rate for the Zygote and processes spawned from it.
404 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800405 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
406 * pool is enabled all existing USAPs have an incorrect API access log sample rate. To
Chris Wailes01060e62019-02-21 13:46:52 -0800407 * properly handle this request the pool must be emptied and refilled. This process can return
408 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
409 *
410 * @param zygoteServer The server object that received the request
Andrei Oneae8e150d2019-02-18 18:27:11 +0000411 * @param samplingRate The new sample rate for regular logging
412 * @param statsdSamplingRate The new sample rate for statslog logging
Chris Wailes01060e62019-02-21 13:46:52 -0800413 * @return A Runnable object representing a new app in any blastulas spawned from here; the
414 * zygote process will always receive a null value from this function.
415 */
416 private Runnable handleHiddenApiAccessLogSampleRate(ZygoteServer zygoteServer,
Andrei Oneae8e150d2019-02-18 18:27:11 +0000417 int samplingRate, int statsdSamplingRate) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800418 return stateChangeWithUsapPoolReset(zygoteServer, () -> {
Andrei Oneae8e150d2019-02-18 18:27:11 +0000419 int maxSamplingRate = Math.max(samplingRate, statsdSamplingRate);
420 ZygoteInit.setHiddenApiAccessLogSampleRate(maxSamplingRate);
Chris Wailes49b79e52019-04-26 15:07:47 -0700421 StatsdHiddenApiUsageLogger.setHiddenApiAccessLogSampleRates(
422 samplingRate, statsdSamplingRate);
423 ZygoteInit.setHiddenApiUsageLogger(StatsdHiddenApiUsageLogger.getInstance());
Chris Wailes01060e62019-02-21 13:46:52 -0800424 });
Mathew Inwood04194fe2018-04-04 14:48:03 +0100425 }
426
Narayan Kamath669afcc2017-02-06 20:24:08 +0000427 protected void preload() {
428 ZygoteInit.lazyPreload();
429 }
430
431 protected boolean isPreloadComplete() {
432 return ZygoteInit.isPreloadComplete();
Torne (Richard Coles)bb658932017-01-05 16:11:06 +0000433 }
434
Narayan Kamath24a33062017-07-03 14:12:26 +0100435 protected DataOutputStream getSocketOutputStream() {
436 return mSocketOutStream;
437 }
438
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500439 protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
440 String cacheKey) {
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100441 throw new RuntimeException("Zygote does not support package preloading");
442 }
443
444 protected boolean canPreloadApp() {
445 return false;
446 }
447
448 protected void handlePreloadApp(ApplicationInfo aInfo) {
449 throw new RuntimeException("Zygote does not support app preloading");
Robert Sesekded20982016-08-15 13:59:13 -0400450 }
451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 /**
453 * Closes socket associated with this connection.
454 */
Andrei Onea15884392019-03-22 17:28:11 +0000455 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 void closeSocket() {
457 try {
458 mSocket.close();
459 } catch (IOException ex) {
460 Log.e(TAG, "Exception while closing command "
461 + "socket in parent", ex);
462 }
463 }
464
Narayan Kamathbf99d062017-07-05 14:45:38 +0100465 boolean isClosedByPeer() {
466 return isEof;
467 }
468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 * Handles post-fork setup of child proc, closing sockets as appropriate,
471 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
472 * if successful or returning if failed.
473 *
474 * @param parsedArgs non-null; zygote args
Jeff Brownebed7d62011-05-16 17:08:42 -0700475 * @param pipeFd null-ok; pipe for communication back to Zygote.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500476 * @param isZygote whether this new child process is itself a new Zygote.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 */
Chris Wailes72c3b222019-04-26 14:36:34 -0700478 private Runnable handleChildProc(ZygoteArguments parsedArgs,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500479 FileDescriptor pipeFd, boolean isZygote) {
Chris Wailes49b79e52019-04-26 15:07:47 -0700480 /*
Dave Platt89d4c892014-02-05 17:06:42 -0800481 * By the time we get here, the native code has closed the two actual Zygote
482 * socket connections, and substituted /dev/null in their place. The LocalSocket
483 * objects still need to be closed properly.
484 */
485
Nick Kralevich468f6c12013-01-30 08:45:03 -0800486 closeSocket();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100488 // End of the postFork event.
489 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Chris Wailes2be26262019-01-11 16:14:43 -0800490 if (parsedArgs.mInvokeWith != null) {
491 WrapperInit.execApplication(parsedArgs.mInvokeWith,
492 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000493 VMRuntime.getCurrentInstructionSet(),
Chris Wailes2be26262019-01-11 16:14:43 -0800494 pipeFd, parsedArgs.mRemainingArgs);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100495
496 // Should not get here.
497 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
Jeff Brownebed7d62011-05-16 17:08:42 -0700498 } else {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500499 if (!isZygote) {
Chris Wailes2be26262019-01-11 16:14:43 -0800500 return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
501 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500502 } else {
Chris Wailes2be26262019-01-11 16:14:43 -0800503 return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
504 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
507 }
508
509 /**
510 * Handles post-fork cleanup of parent proc
511 *
512 * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
513 * if &lt; 0;
Jeff Brownebed7d62011-05-16 17:08:42 -0700514 * @param pipeFd null-ok; pipe for communication with child.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 */
Chris Wailes72c3b222019-04-26 14:36:34 -0700516 private void handleParentProc(int pid, FileDescriptor pipeFd) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700517 if (pid > 0) {
518 setChildPgid(pid);
519 }
520
Jeff Brown3f9dd282011-07-08 20:02:19 -0700521 boolean usingWrapper = false;
Jeff Brownebed7d62011-05-16 17:08:42 -0700522 if (pipeFd != null && pid > 0) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700523 int innerPid = -1;
524 try {
Andreas Gampecbc42142017-07-12 19:17:52 -0700525 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
526 // bail) happens in a timely manner.
Andreas Gampecbc42142017-07-12 19:17:52 -0700527 final int BYTES_REQUIRED = 4; // Bytes in an int.
528
Chris Wailes49b79e52019-04-26 15:07:47 -0700529 StructPollfd[] fds = new StructPollfd[] {
Andreas Gampecbc42142017-07-12 19:17:52 -0700530 new StructPollfd()
531 };
532
Chris Wailes49b79e52019-04-26 15:07:47 -0700533 byte[] data = new byte[BYTES_REQUIRED];
Andreas Gampecbc42142017-07-12 19:17:52 -0700534
Andreas Gampe27497c62017-07-21 11:41:00 -0700535 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
Andreas Gampecbc42142017-07-12 19:17:52 -0700536 int dataIndex = 0;
537 long startTime = System.nanoTime();
538
539 while (dataIndex < data.length && remainingSleepTime > 0) {
540 fds[0].fd = pipeFd;
541 fds[0].events = (short) POLLIN;
542 fds[0].revents = 0;
543 fds[0].userData = null;
544
545 int res = android.system.Os.poll(fds, remainingSleepTime);
546 long endTime = System.nanoTime();
Chris Wailes49b79e52019-04-26 15:07:47 -0700547 int elapsedTimeMs =
548 (int) TimeUnit.MILLISECONDS.convert(
549 endTime - startTime,
550 TimeUnit.NANOSECONDS);
Andreas Gampe27497c62017-07-21 11:41:00 -0700551 remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
Andreas Gampecbc42142017-07-12 19:17:52 -0700552
553 if (res > 0) {
554 if ((fds[0].revents & POLLIN) != 0) {
555 // Only read one byte, so as not to block.
556 int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
557 if (readBytes < 0) {
558 throw new RuntimeException("Some error");
559 }
560 dataIndex += readBytes;
561 } else {
562 // Error case. revents should contain one of the error bits.
563 break;
564 }
565 } else if (res == 0) {
566 Log.w(TAG, "Timed out waiting for child.");
567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 }
Andreas Gampecbc42142017-07-12 19:17:52 -0700569
570 if (dataIndex == data.length) {
571 DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
572 innerPid = is.readInt();
573 }
574
575 if (innerPid == -1) {
576 Log.w(TAG, "Error reading pid from wrapped process, child may have died");
577 }
578 } catch (Exception ex) {
579 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700581
582 // Ensure that the pid reported by the wrapped process is either the
583 // child process that we forked, or a descendant of it.
584 if (innerPid > 0) {
585 int parentPid = innerPid;
586 while (parentPid > 0 && parentPid != pid) {
587 parentPid = Process.getParentPid(parentPid);
588 }
589 if (parentPid > 0) {
590 Log.i(TAG, "Wrapped process has pid " + innerPid);
591 pid = innerPid;
Jeff Brown3f9dd282011-07-08 20:02:19 -0700592 usingWrapper = true;
Jeff Brownebed7d62011-05-16 17:08:42 -0700593 } else {
594 Log.w(TAG, "Wrapped process reported a pid that is not a child of "
595 + "the process that we forked: childPid=" + pid
596 + " innerPid=" + innerPid);
597 }
598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 }
600
601 try {
602 mSocketOutStream.writeInt(pid);
Jeff Brown3f9dd282011-07-08 20:02:19 -0700603 mSocketOutStream.writeBoolean(usingWrapper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100605 throw new IllegalStateException("Error writing to command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 }
608
Jeff Brownebed7d62011-05-16 17:08:42 -0700609 private void setChildPgid(int pid) {
610 // Try to move the new child into the peer's process group.
611 try {
Elliott Hughes26b56e62014-12-17 12:28:29 -0800612 Os.setpgid(pid, Os.getpgid(peer.getPid()));
613 } catch (ErrnoException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700614 // This exception is expected in the case where
615 // the peer is not in our session
616 // TODO get rid of this log message in the case where
617 // getsid(0) != getsid(peer.getPid())
618 Log.i(TAG, "Zygote: setpgid failed. This is "
619 + "normal if peer is not in our session");
620 }
621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622}