blob: 9c6a288372c6b89b757a797c69295204095c7848 [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 Wailes1f263312019-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 Wailes1f263312019-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 Wailes1f263312019-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 Wailes1f263312019-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 Wailes1f263312019-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 Wailes1f263312019-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 Wailes1f263312019-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,
Riddle Hsu32dbdca2019-05-17 23:10:16 -0600260 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion,
Ricky Wai5a8fe7a2019-12-13 15:20:47 +0000261 parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100262
Jeff Brownebed7d62011-05-16 17:08:42 -0700263 try {
264 if (pid == 0) {
265 // in child
Narayan Kamathbf99d062017-07-05 14:45:38 +0100266 zygoteServer.setForkChild();
267
Simon Baldwinba816e02016-01-19 16:34:54 +0000268 zygoteServer.closeServerSocket();
Jeff Brownebed7d62011-05-16 17:08:42 -0700269 IoUtils.closeQuietly(serverPipeFd);
270 serverPipeFd = null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700271
Chris Wailesca848c42019-04-26 14:36:34 -0700272 return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
Jeff Brownebed7d62011-05-16 17:08:42 -0700273 } else {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100274 // In the parent. A pid < 0 indicates a failure and will be handled in
275 // handleParentProc.
Jeff Brownebed7d62011-05-16 17:08:42 -0700276 IoUtils.closeQuietly(childPipeFd);
277 childPipeFd = null;
Chris Wailesca848c42019-04-26 14:36:34 -0700278 handleParentProc(pid, serverPipeFd);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100279 return null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700280 }
281 } finally {
282 IoUtils.closeQuietly(childPipeFd);
283 IoUtils.closeQuietly(serverPipeFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
285 }
286
Narayan Kamathbf99d062017-07-05 14:45:38 +0100287 private void handleAbiListQuery() {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100288 try {
289 final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
290 mSocketOutStream.writeInt(abiListBytes.length);
291 mSocketOutStream.write(abiListBytes);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100292 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100293 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100294 }
295 }
296
Andreas Gampe8444dca2018-05-01 13:31:28 -0700297 private void handlePidQuery() {
298 try {
299 String pidString = String.valueOf(Process.myPid());
300 final byte[] pidStringBytes = pidString.getBytes(StandardCharsets.US_ASCII);
301 mSocketOutStream.writeInt(pidStringBytes.length);
302 mSocketOutStream.write(pidStringBytes);
303 } catch (IOException ioe) {
304 throw new IllegalStateException("Error writing to command socket", ioe);
305 }
306 }
307
David Srbecky6d0d7062019-08-05 15:43:34 +0100308 private void handleBootCompleted() {
Josh Gao27361362019-10-02 16:01:51 -0700309 try {
310 mSocketOutStream.writeInt(0);
311 } catch (IOException ioe) {
312 throw new IllegalStateException("Error writing to command socket", ioe);
313 }
314
David Srbecky6d0d7062019-08-05 15:43:34 +0100315 VMRuntime.bootCompleted();
316 }
317
Narayan Kamath669afcc2017-02-06 20:24:08 +0000318 /**
319 * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
320 * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
321 * if no preload was initiated. The latter implies that the zygote is not configured to load
322 * resources lazy or that the zygote has already handled a previous request to handlePreload.
323 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100324 private void handlePreload() {
Narayan Kamath669afcc2017-02-06 20:24:08 +0000325 try {
326 if (isPreloadComplete()) {
327 mSocketOutStream.writeInt(1);
328 } else {
329 preload();
330 mSocketOutStream.writeInt(0);
331 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000332 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100333 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000334 }
335 }
336
Chris Wailes7e797b62019-02-22 18:29:22 -0800337 private Runnable stateChangeWithUsapPoolReset(ZygoteServer zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800338 Runnable stateChangeCode) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000339 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800340 if (zygoteServer.isUsapPoolEnabled()) {
Chris Wailesfb329ba2019-06-05 16:07:50 -0700341 Log.i(TAG, "Emptying USAP Pool due to state change.");
Chris Wailes7e797b62019-02-22 18:29:22 -0800342 Zygote.emptyUsapPool();
Chris Wailes01060e62019-02-21 13:46:52 -0800343 }
344
345 stateChangeCode.run();
346
Chris Wailes7e797b62019-02-22 18:29:22 -0800347 if (zygoteServer.isUsapPoolEnabled()) {
Chris Wailes01060e62019-02-21 13:46:52 -0800348 Runnable fpResult =
Chris Wailes7e797b62019-02-22 18:29:22 -0800349 zygoteServer.fillUsapPool(
Chris Wailes3d748212019-05-09 17:11:00 -0700350 new int[]{mSocket.getFileDescriptor().getInt$()}, false);
Chris Wailes01060e62019-02-21 13:46:52 -0800351
352 if (fpResult != null) {
353 zygoteServer.setForkChild();
354 return fpResult;
Chris Wailesfb329ba2019-06-05 16:07:50 -0700355 } else {
356 Log.i(TAG, "Finished refilling USAP Pool after state change.");
Chris Wailes01060e62019-02-21 13:46:52 -0800357 }
358 }
359
Mathew Inwood8faeab82018-03-16 14:26:08 +0000360 mSocketOutStream.writeInt(0);
Chris Wailes01060e62019-02-21 13:46:52 -0800361
362 return null;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000363 } catch (IOException ioe) {
364 throw new IllegalStateException("Error writing to command socket", ioe);
365 }
366 }
367
Chris Wailes01060e62019-02-21 13:46:52 -0800368 /**
369 * Makes the necessary changes to implement a new API blacklist exemption policy, and then
370 * responds to the system server, letting it know that the task has been completed.
371 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800372 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
373 * pool is enabled all existing USAPs have an incorrect API blacklist exemption list. To
Chris Wailes01060e62019-02-21 13:46:52 -0800374 * properly handle this request the pool must be emptied and refilled. This process can return
375 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
376 *
377 * @param zygoteServer The server object that received the request
378 * @param exemptions The new exemption list.
Chris Wailes7e797b62019-02-22 18:29:22 -0800379 * @return A Runnable object representing a new app in any USAPs spawned from here; the
Chris Wailes01060e62019-02-21 13:46:52 -0800380 * zygote process will always receive a null value from this function.
381 */
382 private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800383 return stateChangeWithUsapPoolReset(zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800384 () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
385 }
386
Chris Wailes7e797b62019-02-22 18:29:22 -0800387 private Runnable handleUsapPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800388 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800389 Runnable fpResult = zygoteServer.setUsapPoolStatus(newStatus, mSocket);
Chris Wailesdb132a32019-02-20 10:49:27 -0800390
391 if (fpResult == null) {
392 mSocketOutStream.writeInt(0);
393 } else {
394 zygoteServer.setForkChild();
395 }
396
397 return fpResult;
Narayan Kamath669afcc2017-02-06 20:24:08 +0000398 } catch (IOException ioe) {
399 throw new IllegalStateException("Error writing to command socket", ioe);
400 }
401 }
402
Chris Wailes01060e62019-02-21 13:46:52 -0800403 /**
404 * Changes the API access log sample rate for the Zygote and processes spawned from it.
405 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800406 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
407 * pool is enabled all existing USAPs have an incorrect API access log sample rate. To
Chris Wailes01060e62019-02-21 13:46:52 -0800408 * properly handle this request the pool must be emptied and refilled. This process can return
409 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
410 *
411 * @param zygoteServer The server object that received the request
Andrei Oneae8e150d2019-02-18 18:27:11 +0000412 * @param samplingRate The new sample rate for regular logging
413 * @param statsdSamplingRate The new sample rate for statslog logging
Chris Wailes01060e62019-02-21 13:46:52 -0800414 * @return A Runnable object representing a new app in any blastulas spawned from here; the
415 * zygote process will always receive a null value from this function.
416 */
417 private Runnable handleHiddenApiAccessLogSampleRate(ZygoteServer zygoteServer,
Andrei Oneae8e150d2019-02-18 18:27:11 +0000418 int samplingRate, int statsdSamplingRate) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800419 return stateChangeWithUsapPoolReset(zygoteServer, () -> {
Andrei Oneae8e150d2019-02-18 18:27:11 +0000420 int maxSamplingRate = Math.max(samplingRate, statsdSamplingRate);
421 ZygoteInit.setHiddenApiAccessLogSampleRate(maxSamplingRate);
Chris Wailes1f263312019-04-26 15:07:47 -0700422 StatsdHiddenApiUsageLogger.setHiddenApiAccessLogSampleRates(
423 samplingRate, statsdSamplingRate);
424 ZygoteInit.setHiddenApiUsageLogger(StatsdHiddenApiUsageLogger.getInstance());
Chris Wailes01060e62019-02-21 13:46:52 -0800425 });
Mathew Inwood04194fe2018-04-04 14:48:03 +0100426 }
427
Narayan Kamath669afcc2017-02-06 20:24:08 +0000428 protected void preload() {
429 ZygoteInit.lazyPreload();
430 }
431
432 protected boolean isPreloadComplete() {
433 return ZygoteInit.isPreloadComplete();
Torne (Richard Coles)bb658932017-01-05 16:11:06 +0000434 }
435
Narayan Kamath24a33062017-07-03 14:12:26 +0100436 protected DataOutputStream getSocketOutputStream() {
437 return mSocketOutStream;
438 }
439
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500440 protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
441 String cacheKey) {
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100442 throw new RuntimeException("Zygote does not support package preloading");
443 }
444
445 protected boolean canPreloadApp() {
446 return false;
447 }
448
449 protected void handlePreloadApp(ApplicationInfo aInfo) {
450 throw new RuntimeException("Zygote does not support app preloading");
Robert Sesekded20982016-08-15 13:59:13 -0400451 }
452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 /**
454 * Closes socket associated with this connection.
455 */
Andrei Onea15884392019-03-22 17:28:11 +0000456 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 void closeSocket() {
458 try {
459 mSocket.close();
460 } catch (IOException ex) {
461 Log.e(TAG, "Exception while closing command "
462 + "socket in parent", ex);
463 }
464 }
465
Narayan Kamathbf99d062017-07-05 14:45:38 +0100466 boolean isClosedByPeer() {
467 return isEof;
468 }
469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 * Handles post-fork setup of child proc, closing sockets as appropriate,
472 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
473 * if successful or returning if failed.
474 *
475 * @param parsedArgs non-null; zygote args
Jeff Brownebed7d62011-05-16 17:08:42 -0700476 * @param pipeFd null-ok; pipe for communication back to Zygote.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500477 * @param isZygote whether this new child process is itself a new Zygote.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 */
Chris Wailesca848c42019-04-26 14:36:34 -0700479 private Runnable handleChildProc(ZygoteArguments parsedArgs,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500480 FileDescriptor pipeFd, boolean isZygote) {
Chris Wailes1f263312019-04-26 15:07:47 -0700481 /*
Dave Platt89d4c892014-02-05 17:06:42 -0800482 * By the time we get here, the native code has closed the two actual Zygote
483 * socket connections, and substituted /dev/null in their place. The LocalSocket
484 * objects still need to be closed properly.
485 */
486
Nick Kralevich468f6c12013-01-30 08:45:03 -0800487 closeSocket();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488
Chris Wailes6d00c1a2019-04-23 14:26:13 -0700489 Zygote.setAppProcessName(parsedArgs, TAG);
Jeff Brownebed7d62011-05-16 17:08:42 -0700490
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100491 // End of the postFork event.
492 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Chris Wailes2be26262019-01-11 16:14:43 -0800493 if (parsedArgs.mInvokeWith != null) {
494 WrapperInit.execApplication(parsedArgs.mInvokeWith,
495 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000496 VMRuntime.getCurrentInstructionSet(),
Chris Wailes2be26262019-01-11 16:14:43 -0800497 pipeFd, parsedArgs.mRemainingArgs);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100498
499 // Should not get here.
500 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
Jeff Brownebed7d62011-05-16 17:08:42 -0700501 } else {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500502 if (!isZygote) {
Chris Wailes2be26262019-01-11 16:14:43 -0800503 return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
atrost5ae996f2019-12-11 18:32:48 +0000504 parsedArgs.mDisabledCompatChanges,
Chris Wailes2be26262019-01-11 16:14:43 -0800505 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500506 } else {
Chris Wailes2be26262019-01-11 16:14:43 -0800507 return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
508 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500509 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 }
511 }
512
513 /**
514 * Handles post-fork cleanup of parent proc
515 *
516 * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
517 * if &lt; 0;
Jeff Brownebed7d62011-05-16 17:08:42 -0700518 * @param pipeFd null-ok; pipe for communication with child.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 */
Chris Wailesca848c42019-04-26 14:36:34 -0700520 private void handleParentProc(int pid, FileDescriptor pipeFd) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700521 if (pid > 0) {
522 setChildPgid(pid);
523 }
524
Jeff Brown3f9dd282011-07-08 20:02:19 -0700525 boolean usingWrapper = false;
Jeff Brownebed7d62011-05-16 17:08:42 -0700526 if (pipeFd != null && pid > 0) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700527 int innerPid = -1;
528 try {
Andreas Gampecbc42142017-07-12 19:17:52 -0700529 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
530 // bail) happens in a timely manner.
Andreas Gampecbc42142017-07-12 19:17:52 -0700531 final int BYTES_REQUIRED = 4; // Bytes in an int.
532
Chris Wailes1f263312019-04-26 15:07:47 -0700533 StructPollfd[] fds = new StructPollfd[] {
Andreas Gampecbc42142017-07-12 19:17:52 -0700534 new StructPollfd()
535 };
536
Chris Wailes1f263312019-04-26 15:07:47 -0700537 byte[] data = new byte[BYTES_REQUIRED];
Andreas Gampecbc42142017-07-12 19:17:52 -0700538
Andreas Gampe27497c62017-07-21 11:41:00 -0700539 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
Andreas Gampecbc42142017-07-12 19:17:52 -0700540 int dataIndex = 0;
541 long startTime = System.nanoTime();
542
543 while (dataIndex < data.length && remainingSleepTime > 0) {
544 fds[0].fd = pipeFd;
545 fds[0].events = (short) POLLIN;
546 fds[0].revents = 0;
547 fds[0].userData = null;
548
549 int res = android.system.Os.poll(fds, remainingSleepTime);
550 long endTime = System.nanoTime();
Chris Wailes1f263312019-04-26 15:07:47 -0700551 int elapsedTimeMs =
552 (int) TimeUnit.MILLISECONDS.convert(
553 endTime - startTime,
554 TimeUnit.NANOSECONDS);
Andreas Gampe27497c62017-07-21 11:41:00 -0700555 remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
Andreas Gampecbc42142017-07-12 19:17:52 -0700556
557 if (res > 0) {
558 if ((fds[0].revents & POLLIN) != 0) {
559 // Only read one byte, so as not to block.
560 int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
561 if (readBytes < 0) {
562 throw new RuntimeException("Some error");
563 }
564 dataIndex += readBytes;
565 } else {
566 // Error case. revents should contain one of the error bits.
567 break;
568 }
569 } else if (res == 0) {
570 Log.w(TAG, "Timed out waiting for child.");
571 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 }
Andreas Gampecbc42142017-07-12 19:17:52 -0700573
574 if (dataIndex == data.length) {
575 DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
576 innerPid = is.readInt();
577 }
578
579 if (innerPid == -1) {
580 Log.w(TAG, "Error reading pid from wrapped process, child may have died");
581 }
582 } catch (Exception ex) {
583 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700585
586 // Ensure that the pid reported by the wrapped process is either the
587 // child process that we forked, or a descendant of it.
588 if (innerPid > 0) {
589 int parentPid = innerPid;
590 while (parentPid > 0 && parentPid != pid) {
591 parentPid = Process.getParentPid(parentPid);
592 }
593 if (parentPid > 0) {
594 Log.i(TAG, "Wrapped process has pid " + innerPid);
595 pid = innerPid;
Jeff Brown3f9dd282011-07-08 20:02:19 -0700596 usingWrapper = true;
Jeff Brownebed7d62011-05-16 17:08:42 -0700597 } else {
598 Log.w(TAG, "Wrapped process reported a pid that is not a child of "
599 + "the process that we forked: childPid=" + pid
600 + " innerPid=" + innerPid);
601 }
602 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
604
605 try {
606 mSocketOutStream.writeInt(pid);
Jeff Brown3f9dd282011-07-08 20:02:19 -0700607 mSocketOutStream.writeBoolean(usingWrapper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100609 throw new IllegalStateException("Error writing to command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 }
612
Jeff Brownebed7d62011-05-16 17:08:42 -0700613 private void setChildPgid(int pid) {
614 // Try to move the new child into the peer's process group.
615 try {
Elliott Hughes26b56e62014-12-17 12:28:29 -0800616 Os.setpgid(pid, Os.getpgid(peer.getPid()));
617 } catch (ErrnoException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700618 // This exception is expected in the case where
619 // the peer is not in our session
620 // TODO get rid of this log message in the case where
621 // getsid(0) != getsid(peer.getPid())
622 Log.i(TAG, "Zygote: setpgid failed. This is "
623 + "normal if peer is not in our session");
624 }
625 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626}