blob: 78f82ea100a4fc2ee74254087da3a840f485f451 [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
Chris Wailes2be26262019-01-11 16:14:43 -0800143 if (parsedArgs.mAbiListQuery) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100144 handleAbiListQuery();
145 return null;
146 }
Narayan Kamathc41638c2014-04-07 13:56:15 +0100147
Chris Wailes2be26262019-01-11 16:14:43 -0800148 if (parsedArgs.mPidQuery) {
Andreas Gampe8444dca2018-05-01 13:31:28 -0700149 handlePidQuery();
150 return null;
151 }
152
Chris Wailes7e797b62019-02-22 18:29:22 -0800153 if (parsedArgs.mUsapPoolStatusSpecified) {
154 return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
Chris Wailesdb132a32019-02-20 10:49:27 -0800155 }
156
Chris Wailes2be26262019-01-11 16:14:43 -0800157 if (parsedArgs.mPreloadDefault) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100158 handlePreload();
159 return null;
160 }
Narayan Kamath5a3d0c62016-11-09 15:35:18 +0000161
Chris Wailes2be26262019-01-11 16:14:43 -0800162 if (parsedArgs.mPreloadPackage != null) {
163 handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
164 parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100165 return null;
166 }
Robert Sesekded20982016-08-15 13:59:13 -0400167
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100168 if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
169 byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
170 Parcel appInfoParcel = Parcel.obtain();
171 appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
172 appInfoParcel.setDataPosition(0);
173 ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
174 appInfoParcel.recycle();
175 if (appInfo != null) {
176 handlePreloadApp(appInfo);
177 } else {
178 throw new IllegalArgumentException("Failed to deserialize --preload-app");
179 }
180 return null;
181 }
182
Chris Wailes2be26262019-01-11 16:14:43 -0800183 if (parsedArgs.mApiBlacklistExemptions != null) {
Chris Wailes01060e62019-02-21 13:46:52 -0800184 return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
Mathew Inwood8faeab82018-03-16 14:26:08 +0000185 }
186
Andrei Oneae8e150d2019-02-18 18:27:11 +0000187 if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
188 || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
Chris Wailes01060e62019-02-21 13:46:52 -0800189 return handleHiddenApiAccessLogSampleRate(zygoteServer,
Andrei Oneae8e150d2019-02-18 18:27:11 +0000190 parsedArgs.mHiddenApiAccessLogSampleRate,
191 parsedArgs.mHiddenApiAccessStatslogSampleRate);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100192 }
193
Chris Wailes2be26262019-01-11 16:14:43 -0800194 if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
195 throw new ZygoteSecurityException("Client may not specify capabilities: "
196 + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
197 + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
Narayan Kamathbf99d062017-07-05 14:45:38 +0100198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
Chris Wailes2be26262019-01-11 16:14:43 -0800200 Zygote.applyUidSecurityPolicy(parsedArgs, peer);
201 Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Jeff Brownebed7d62011-05-16 17:08:42 -0700202
Chris Wailes2be26262019-01-11 16:14:43 -0800203 Zygote.applyDebuggerSystemProperty(parsedArgs);
204 Zygote.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205
Narayan Kamathbf99d062017-07-05 14:45:38 +0100206 int[][] rlimits = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207
Chris Wailes2be26262019-01-11 16:14:43 -0800208 if (parsedArgs.mRLimits != null) {
209 rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100210 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211
Narayan Kamathbf99d062017-07-05 14:45:38 +0100212 int[] fdsToIgnore = null;
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800213
Chris Wailes2be26262019-01-11 16:14:43 -0800214 if (parsedArgs.mInvokeWith != null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100215 try {
Elliott Hughes3fe59512014-12-12 14:07:34 -0800216 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
Jeff Brownebed7d62011-05-16 17:08:42 -0700217 childPipeFd = pipeFds[1];
218 serverPipeFd = pipeFds[0];
Narayan Kamath6ac7e672015-01-16 16:26:54 +0000219 Os.fcntlInt(childPipeFd, F_SETFD, 0);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100220 fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
221 } catch (ErrnoException errnoEx) {
222 throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
Jeff Brownebed7d62011-05-16 17:08:42 -0700223 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 }
225
Chris Wailes49b79e52019-04-26 15:07:47 -0700226 /*
Narayan Kamathbf99d062017-07-05 14:45:38 +0100227 * In order to avoid leaking descriptors to the Zygote child,
228 * the native code must close the two Zygote socket descriptors
229 * in the child process before it switches from Zygote-root to
230 * the UID and privileges of the application being launched.
231 *
232 * In order to avoid "bad file descriptor" errors when the
233 * two LocalSocket objects are closed, the Posix file
234 * descriptors are released via a dup2() call which closes
235 * the socket and substitutes an open descriptor to /dev/null.
236 */
237
238 int [] fdsToClose = { -1, -1 };
239
240 FileDescriptor fd = mSocket.getFileDescriptor();
241
242 if (fd != null) {
243 fdsToClose[0] = fd.getInt$();
244 }
245
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800246 fd = zygoteServer.getZygoteSocketFileDescriptor();
Narayan Kamathbf99d062017-07-05 14:45:38 +0100247
248 if (fd != null) {
249 fdsToClose[1] = fd.getInt$();
250 }
251
Chris Wailes2be26262019-01-11 16:14:43 -0800252 pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
253 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
254 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
Sudheer Shanka64501e52019-04-29 10:46:26 -0700255 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100256
Jeff Brownebed7d62011-05-16 17:08:42 -0700257 try {
258 if (pid == 0) {
259 // in child
Narayan Kamathbf99d062017-07-05 14:45:38 +0100260 zygoteServer.setForkChild();
261
Simon Baldwinba816e02016-01-19 16:34:54 +0000262 zygoteServer.closeServerSocket();
Jeff Brownebed7d62011-05-16 17:08:42 -0700263 IoUtils.closeQuietly(serverPipeFd);
264 serverPipeFd = null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700265
Chris Wailes72c3b222019-04-26 14:36:34 -0700266 return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
Jeff Brownebed7d62011-05-16 17:08:42 -0700267 } else {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100268 // In the parent. A pid < 0 indicates a failure and will be handled in
269 // handleParentProc.
Jeff Brownebed7d62011-05-16 17:08:42 -0700270 IoUtils.closeQuietly(childPipeFd);
271 childPipeFd = null;
Chris Wailes72c3b222019-04-26 14:36:34 -0700272 handleParentProc(pid, serverPipeFd);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100273 return null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700274 }
275 } finally {
276 IoUtils.closeQuietly(childPipeFd);
277 IoUtils.closeQuietly(serverPipeFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 }
279 }
280
Narayan Kamathbf99d062017-07-05 14:45:38 +0100281 private void handleAbiListQuery() {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100282 try {
283 final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
284 mSocketOutStream.writeInt(abiListBytes.length);
285 mSocketOutStream.write(abiListBytes);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100286 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100287 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100288 }
289 }
290
Andreas Gampe8444dca2018-05-01 13:31:28 -0700291 private void handlePidQuery() {
292 try {
293 String pidString = String.valueOf(Process.myPid());
294 final byte[] pidStringBytes = pidString.getBytes(StandardCharsets.US_ASCII);
295 mSocketOutStream.writeInt(pidStringBytes.length);
296 mSocketOutStream.write(pidStringBytes);
297 } catch (IOException ioe) {
298 throw new IllegalStateException("Error writing to command socket", ioe);
299 }
300 }
301
Narayan Kamath669afcc2017-02-06 20:24:08 +0000302 /**
303 * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
304 * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
305 * if no preload was initiated. The latter implies that the zygote is not configured to load
306 * resources lazy or that the zygote has already handled a previous request to handlePreload.
307 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100308 private void handlePreload() {
Narayan Kamath669afcc2017-02-06 20:24:08 +0000309 try {
310 if (isPreloadComplete()) {
311 mSocketOutStream.writeInt(1);
312 } else {
313 preload();
314 mSocketOutStream.writeInt(0);
315 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000316 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100317 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000318 }
319 }
320
Chris Wailes7e797b62019-02-22 18:29:22 -0800321 private Runnable stateChangeWithUsapPoolReset(ZygoteServer zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800322 Runnable stateChangeCode) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000323 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800324 if (zygoteServer.isUsapPoolEnabled()) {
Chris Wailesf68c4e22019-06-05 16:07:50 -0700325 Log.i(TAG, "Emptying USAP Pool due to state change.");
Chris Wailes7e797b62019-02-22 18:29:22 -0800326 Zygote.emptyUsapPool();
Chris Wailes01060e62019-02-21 13:46:52 -0800327 }
328
329 stateChangeCode.run();
330
Chris Wailes7e797b62019-02-22 18:29:22 -0800331 if (zygoteServer.isUsapPoolEnabled()) {
Chris Wailes01060e62019-02-21 13:46:52 -0800332 Runnable fpResult =
Chris Wailes7e797b62019-02-22 18:29:22 -0800333 zygoteServer.fillUsapPool(
Mathew Inwood51c53b42019-05-24 14:06:10 +0100334 new int[]{mSocket.getFileDescriptor().getInt$()});
Chris Wailes01060e62019-02-21 13:46:52 -0800335
336 if (fpResult != null) {
337 zygoteServer.setForkChild();
338 return fpResult;
Chris Wailesf68c4e22019-06-05 16:07:50 -0700339 } else {
340 Log.i(TAG, "Finished refilling USAP Pool after state change.");
Chris Wailes01060e62019-02-21 13:46:52 -0800341 }
342 }
343
Mathew Inwood8faeab82018-03-16 14:26:08 +0000344 mSocketOutStream.writeInt(0);
Chris Wailes01060e62019-02-21 13:46:52 -0800345
346 return null;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000347 } catch (IOException ioe) {
348 throw new IllegalStateException("Error writing to command socket", ioe);
349 }
350 }
351
Chris Wailes01060e62019-02-21 13:46:52 -0800352 /**
353 * Makes the necessary changes to implement a new API blacklist exemption policy, and then
354 * responds to the system server, letting it know that the task has been completed.
355 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800356 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
357 * pool is enabled all existing USAPs have an incorrect API blacklist exemption list. To
Chris Wailes01060e62019-02-21 13:46:52 -0800358 * properly handle this request the pool must be emptied and refilled. This process can return
359 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
360 *
361 * @param zygoteServer The server object that received the request
362 * @param exemptions The new exemption list.
Chris Wailes7e797b62019-02-22 18:29:22 -0800363 * @return A Runnable object representing a new app in any USAPs spawned from here; the
Chris Wailes01060e62019-02-21 13:46:52 -0800364 * zygote process will always receive a null value from this function.
365 */
366 private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800367 return stateChangeWithUsapPoolReset(zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800368 () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
369 }
370
Chris Wailes7e797b62019-02-22 18:29:22 -0800371 private Runnable handleUsapPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800372 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800373 Runnable fpResult = zygoteServer.setUsapPoolStatus(newStatus, mSocket);
Chris Wailesdb132a32019-02-20 10:49:27 -0800374
375 if (fpResult == null) {
376 mSocketOutStream.writeInt(0);
377 } else {
378 zygoteServer.setForkChild();
379 }
380
381 return fpResult;
Narayan Kamath669afcc2017-02-06 20:24:08 +0000382 } catch (IOException ioe) {
383 throw new IllegalStateException("Error writing to command socket", ioe);
384 }
385 }
386
Chris Wailes01060e62019-02-21 13:46:52 -0800387 /**
388 * Changes the API access log sample rate for the Zygote and processes spawned from it.
389 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800390 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
391 * pool is enabled all existing USAPs have an incorrect API access log sample rate. To
Chris Wailes01060e62019-02-21 13:46:52 -0800392 * properly handle this request the pool must be emptied and refilled. This process can return
393 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
394 *
395 * @param zygoteServer The server object that received the request
Andrei Oneae8e150d2019-02-18 18:27:11 +0000396 * @param samplingRate The new sample rate for regular logging
397 * @param statsdSamplingRate The new sample rate for statslog logging
Chris Wailes01060e62019-02-21 13:46:52 -0800398 * @return A Runnable object representing a new app in any blastulas spawned from here; the
399 * zygote process will always receive a null value from this function.
400 */
401 private Runnable handleHiddenApiAccessLogSampleRate(ZygoteServer zygoteServer,
Andrei Oneae8e150d2019-02-18 18:27:11 +0000402 int samplingRate, int statsdSamplingRate) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800403 return stateChangeWithUsapPoolReset(zygoteServer, () -> {
Andrei Oneae8e150d2019-02-18 18:27:11 +0000404 int maxSamplingRate = Math.max(samplingRate, statsdSamplingRate);
405 ZygoteInit.setHiddenApiAccessLogSampleRate(maxSamplingRate);
Chris Wailes49b79e52019-04-26 15:07:47 -0700406 StatsdHiddenApiUsageLogger.setHiddenApiAccessLogSampleRates(
407 samplingRate, statsdSamplingRate);
408 ZygoteInit.setHiddenApiUsageLogger(StatsdHiddenApiUsageLogger.getInstance());
Chris Wailes01060e62019-02-21 13:46:52 -0800409 });
Mathew Inwood04194fe2018-04-04 14:48:03 +0100410 }
411
Narayan Kamath669afcc2017-02-06 20:24:08 +0000412 protected void preload() {
413 ZygoteInit.lazyPreload();
414 }
415
416 protected boolean isPreloadComplete() {
417 return ZygoteInit.isPreloadComplete();
Torne (Richard Coles)bb658932017-01-05 16:11:06 +0000418 }
419
Narayan Kamath24a33062017-07-03 14:12:26 +0100420 protected DataOutputStream getSocketOutputStream() {
421 return mSocketOutStream;
422 }
423
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500424 protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
425 String cacheKey) {
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100426 throw new RuntimeException("Zygote does not support package preloading");
427 }
428
429 protected boolean canPreloadApp() {
430 return false;
431 }
432
433 protected void handlePreloadApp(ApplicationInfo aInfo) {
434 throw new RuntimeException("Zygote does not support app preloading");
Robert Sesekded20982016-08-15 13:59:13 -0400435 }
436
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 /**
438 * Closes socket associated with this connection.
439 */
Andrei Onea15884392019-03-22 17:28:11 +0000440 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 void closeSocket() {
442 try {
443 mSocket.close();
444 } catch (IOException ex) {
445 Log.e(TAG, "Exception while closing command "
446 + "socket in parent", ex);
447 }
448 }
449
Narayan Kamathbf99d062017-07-05 14:45:38 +0100450 boolean isClosedByPeer() {
451 return isEof;
452 }
453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 * Handles post-fork setup of child proc, closing sockets as appropriate,
456 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
457 * if successful or returning if failed.
458 *
459 * @param parsedArgs non-null; zygote args
Jeff Brownebed7d62011-05-16 17:08:42 -0700460 * @param pipeFd null-ok; pipe for communication back to Zygote.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500461 * @param isZygote whether this new child process is itself a new Zygote.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 */
Chris Wailes72c3b222019-04-26 14:36:34 -0700463 private Runnable handleChildProc(ZygoteArguments parsedArgs,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500464 FileDescriptor pipeFd, boolean isZygote) {
Chris Wailes49b79e52019-04-26 15:07:47 -0700465 /*
Dave Platt89d4c892014-02-05 17:06:42 -0800466 * By the time we get here, the native code has closed the two actual Zygote
467 * socket connections, and substituted /dev/null in their place. The LocalSocket
468 * objects still need to be closed properly.
469 */
470
Nick Kralevich468f6c12013-01-30 08:45:03 -0800471 closeSocket();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100473 // End of the postFork event.
474 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Chris Wailes2be26262019-01-11 16:14:43 -0800475 if (parsedArgs.mInvokeWith != null) {
476 WrapperInit.execApplication(parsedArgs.mInvokeWith,
477 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000478 VMRuntime.getCurrentInstructionSet(),
Chris Wailes2be26262019-01-11 16:14:43 -0800479 pipeFd, parsedArgs.mRemainingArgs);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100480
481 // Should not get here.
482 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
Jeff Brownebed7d62011-05-16 17:08:42 -0700483 } else {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500484 if (!isZygote) {
Chris Wailes2be26262019-01-11 16:14:43 -0800485 return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
486 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500487 } else {
Chris Wailes2be26262019-01-11 16:14:43 -0800488 return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
489 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500490 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 }
492 }
493
494 /**
495 * Handles post-fork cleanup of parent proc
496 *
497 * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
498 * if &lt; 0;
Jeff Brownebed7d62011-05-16 17:08:42 -0700499 * @param pipeFd null-ok; pipe for communication with child.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 */
Chris Wailes72c3b222019-04-26 14:36:34 -0700501 private void handleParentProc(int pid, FileDescriptor pipeFd) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700502 if (pid > 0) {
503 setChildPgid(pid);
504 }
505
Jeff Brown3f9dd282011-07-08 20:02:19 -0700506 boolean usingWrapper = false;
Jeff Brownebed7d62011-05-16 17:08:42 -0700507 if (pipeFd != null && pid > 0) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700508 int innerPid = -1;
509 try {
Andreas Gampecbc42142017-07-12 19:17:52 -0700510 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
511 // bail) happens in a timely manner.
Andreas Gampecbc42142017-07-12 19:17:52 -0700512 final int BYTES_REQUIRED = 4; // Bytes in an int.
513
Chris Wailes49b79e52019-04-26 15:07:47 -0700514 StructPollfd[] fds = new StructPollfd[] {
Andreas Gampecbc42142017-07-12 19:17:52 -0700515 new StructPollfd()
516 };
517
Chris Wailes49b79e52019-04-26 15:07:47 -0700518 byte[] data = new byte[BYTES_REQUIRED];
Andreas Gampecbc42142017-07-12 19:17:52 -0700519
Andreas Gampe27497c62017-07-21 11:41:00 -0700520 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
Andreas Gampecbc42142017-07-12 19:17:52 -0700521 int dataIndex = 0;
522 long startTime = System.nanoTime();
523
524 while (dataIndex < data.length && remainingSleepTime > 0) {
525 fds[0].fd = pipeFd;
526 fds[0].events = (short) POLLIN;
527 fds[0].revents = 0;
528 fds[0].userData = null;
529
530 int res = android.system.Os.poll(fds, remainingSleepTime);
531 long endTime = System.nanoTime();
Chris Wailes49b79e52019-04-26 15:07:47 -0700532 int elapsedTimeMs =
533 (int) TimeUnit.MILLISECONDS.convert(
534 endTime - startTime,
535 TimeUnit.NANOSECONDS);
Andreas Gampe27497c62017-07-21 11:41:00 -0700536 remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
Andreas Gampecbc42142017-07-12 19:17:52 -0700537
538 if (res > 0) {
539 if ((fds[0].revents & POLLIN) != 0) {
540 // Only read one byte, so as not to block.
541 int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
542 if (readBytes < 0) {
543 throw new RuntimeException("Some error");
544 }
545 dataIndex += readBytes;
546 } else {
547 // Error case. revents should contain one of the error bits.
548 break;
549 }
550 } else if (res == 0) {
551 Log.w(TAG, "Timed out waiting for child.");
552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
Andreas Gampecbc42142017-07-12 19:17:52 -0700554
555 if (dataIndex == data.length) {
556 DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
557 innerPid = is.readInt();
558 }
559
560 if (innerPid == -1) {
561 Log.w(TAG, "Error reading pid from wrapped process, child may have died");
562 }
563 } catch (Exception ex) {
564 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700566
567 // Ensure that the pid reported by the wrapped process is either the
568 // child process that we forked, or a descendant of it.
569 if (innerPid > 0) {
570 int parentPid = innerPid;
571 while (parentPid > 0 && parentPid != pid) {
572 parentPid = Process.getParentPid(parentPid);
573 }
574 if (parentPid > 0) {
575 Log.i(TAG, "Wrapped process has pid " + innerPid);
576 pid = innerPid;
Jeff Brown3f9dd282011-07-08 20:02:19 -0700577 usingWrapper = true;
Jeff Brownebed7d62011-05-16 17:08:42 -0700578 } else {
579 Log.w(TAG, "Wrapped process reported a pid that is not a child of "
580 + "the process that we forked: childPid=" + pid
581 + " innerPid=" + innerPid);
582 }
583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 }
585
586 try {
587 mSocketOutStream.writeInt(pid);
Jeff Brown3f9dd282011-07-08 20:02:19 -0700588 mSocketOutStream.writeBoolean(usingWrapper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100590 throw new IllegalStateException("Error writing to command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 }
593
Jeff Brownebed7d62011-05-16 17:08:42 -0700594 private void setChildPgid(int pid) {
595 // Try to move the new child into the peer's process group.
596 try {
Elliott Hughes26b56e62014-12-17 12:28:29 -0800597 Os.setpgid(pid, Os.getpgid(peer.getPid()));
598 } catch (ErrnoException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700599 // This exception is expected in the case where
600 // the peer is not in our session
601 // TODO get rid of this log message in the case where
602 // getsid(0) != getsid(peer.getPid())
603 Log.i(TAG, "Zygote: setpgid failed. This is "
604 + "normal if peer is not in our session");
605 }
606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607}