blob: 87adce7c3a625cdde693712470dd11935563c1c1 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.os;
18
Narayan Kamath6ac7e672015-01-16 16:26:54 +000019import static android.system.OsConstants.F_SETFD;
Elliott Hughes3fe59512014-12-12 14:07:34 -080020import static android.system.OsConstants.O_CLOEXEC;
Andreas Gampecbc42142017-07-12 19:17:52 -070021import static android.system.OsConstants.POLLIN;
Elliott Hughesdac83f52014-12-15 11:00:25 -080022import static android.system.OsConstants.STDERR_FILENO;
23import static android.system.OsConstants.STDIN_FILENO;
24import static android.system.OsConstants.STDOUT_FILENO;
Sudheer Shankad81b1d72018-09-05 16:37:30 -070025
Andreas Gampe27497c62017-07-21 11:41:00 -070026import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
Andreas Gampe27497c62017-07-21 11:41:00 -070027import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
Elliott Hughes3fe59512014-12-12 14:07:34 -080028
Martijn Coenen7e6fa672018-11-05 11:45:26 +010029import android.content.pm.ApplicationInfo;
Andrei Onea6cd1b702019-01-25 16:29:44 +000030import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.net.Credentials;
32import android.net.LocalSocket;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010033import android.os.Parcel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.Process;
Narayan Kamathfbb32f62015-06-12 15:34:35 +010035import android.os.Trace;
Elliott Hughes860c5912014-04-28 19:19:13 -070036import android.system.ErrnoException;
37import android.system.Os;
Andreas Gampecbc42142017-07-12 19:17:52 -070038import android.system.StructPollfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.util.Log;
Andrei Oneae8e150d2019-02-18 18:27:11 +000040import android.util.StatsLog;
Sudheer Shankad81b1d72018-09-05 16:37:30 -070041
Andrei Onea6cd1b702019-01-25 16:29:44 +000042import com.android.internal.logging.MetricsLogger;
43import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
44
Narayan Kamath37ad4b02015-01-19 16:05:24 +000045import dalvik.system.VMRuntime;
Sudheer Shankad81b1d72018-09-05 16:37:30 -070046
47import libcore.io.IoUtils;
48
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import java.io.BufferedReader;
Andreas Gampecbc42142017-07-12 19:17:52 -070050import java.io.ByteArrayInputStream;
Jeff Brownebed7d62011-05-16 17:08:42 -070051import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import java.io.DataOutputStream;
53import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import java.io.IOException;
55import java.io.InputStreamReader;
Narayan Kamathc41638c2014-04-07 13:56:15 +010056import java.nio.charset.StandardCharsets;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010057import java.util.Base64;
Mathew Inwood8faeab82018-03-16 14:26:08 +000058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059/**
60 * A connection that can make spawn requests.
61 */
62class ZygoteConnection {
63 private static final String TAG = "Zygote";
64
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066 * The command socket.
67 *
68 * mSocket is retained in the child process in "peer wait" mode, so
69 * that it closes when the child process terminates. In other cases,
70 * it is closed in the peer.
71 */
72 private final LocalSocket mSocket;
73 private final DataOutputStream mSocketOutStream;
74 private final BufferedReader mSocketReader;
75 private final Credentials peer;
Narayan Kamathc41638c2014-04-07 13:56:15 +010076 private final String abiList;
Narayan Kamathbf99d062017-07-05 14:45:38 +010077 private boolean isEof;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
79 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 * Constructs instance from connected socket.
81 *
82 * @param socket non-null; connected socket
Narayan Kamathc41638c2014-04-07 13:56:15 +010083 * @param abiList non-null; a list of ABIs this zygote supports.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 * @throws IOException
85 */
Narayan Kamathc41638c2014-04-07 13:56:15 +010086 ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 mSocket = socket;
Narayan Kamathc41638c2014-04-07 13:56:15 +010088 this.abiList = abiList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
90 mSocketOutStream
91 = new DataOutputStream(socket.getOutputStream());
92
93 mSocketReader = new BufferedReader(
94 new InputStreamReader(socket.getInputStream()), 256);
95
96 mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
dcashmanfc4c0bf82015-03-05 17:17:47 -080097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 try {
99 peer = mSocket.getPeerCredentials();
100 } catch (IOException ex) {
101 Log.e(TAG, "Cannot read peer credentials", ex);
102 throw ex;
103 }
Narayan Kamathbf99d062017-07-05 14:45:38 +0100104
105 isEof = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 }
107
108 /**
109 * Returns the file descriptor of the associated socket.
110 *
111 * @return null-ok; file descriptor
112 */
Chris Wailes2be26262019-01-11 16:14:43 -0800113 FileDescriptor getFileDescriptor() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 return mSocket.getFileDescriptor();
115 }
116
117 /**
Narayan Kamathbf99d062017-07-05 14:45:38 +0100118 * Reads one start command from the command socket. If successful, a child is forked and a
119 * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
120 * process. {@code null} is always returned in the parent process (the zygote).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 *
Narayan Kamathbf99d062017-07-05 14:45:38 +0100122 * If the client closes the socket, an {@code EOF} condition is set, which callers can test
123 * for by calling {@code ZygoteConnection.isClosedByPeer}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100125 Runnable processOneCommand(ZygoteServer zygoteServer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 String args[];
Chris Wailes2be26262019-01-11 16:14:43 -0800127 ZygoteArguments parsedArgs = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 FileDescriptor[] descriptors;
129
130 try {
Chris Wailes2be26262019-01-11 16:14:43 -0800131 args = Zygote.readArgumentList(mSocketReader);
132
133 // TODO (chriswailes): Remove this and add an assert.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 descriptors = mSocket.getAncillaryFileDescriptors();
135 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100136 throw new IllegalStateException("IOException on command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 }
138
Narayan Kamathbf99d062017-07-05 14:45:38 +0100139 // readArgumentList returns null only when it has reached EOF with no available
140 // data to read. This will only happen when the remote socket has disconnected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 if (args == null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100142 isEof = true;
143 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 }
145
Jeff Brownebed7d62011-05-16 17:08:42 -0700146 int pid = -1;
147 FileDescriptor childPipeFd = null;
148 FileDescriptor serverPipeFd = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149
Chris Wailes2be26262019-01-11 16:14:43 -0800150 parsedArgs = new ZygoteArguments(args);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100151
Chris Wailes2be26262019-01-11 16:14:43 -0800152 if (parsedArgs.mAbiListQuery) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100153 handleAbiListQuery();
154 return null;
155 }
Narayan Kamathc41638c2014-04-07 13:56:15 +0100156
Chris Wailes2be26262019-01-11 16:14:43 -0800157 if (parsedArgs.mPidQuery) {
Andreas Gampe8444dca2018-05-01 13:31:28 -0700158 handlePidQuery();
159 return null;
160 }
161
Chris Wailes7e797b62019-02-22 18:29:22 -0800162 if (parsedArgs.mUsapPoolStatusSpecified) {
163 return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
Chris Wailesdb132a32019-02-20 10:49:27 -0800164 }
165
Chris Wailes2be26262019-01-11 16:14:43 -0800166 if (parsedArgs.mPreloadDefault) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100167 handlePreload();
168 return null;
169 }
Narayan Kamath5a3d0c62016-11-09 15:35:18 +0000170
Chris Wailes2be26262019-01-11 16:14:43 -0800171 if (parsedArgs.mPreloadPackage != null) {
172 handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
173 parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100174 return null;
175 }
Robert Sesekded20982016-08-15 13:59:13 -0400176
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100177 if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
178 byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
179 Parcel appInfoParcel = Parcel.obtain();
180 appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
181 appInfoParcel.setDataPosition(0);
182 ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
183 appInfoParcel.recycle();
184 if (appInfo != null) {
185 handlePreloadApp(appInfo);
186 } else {
187 throw new IllegalArgumentException("Failed to deserialize --preload-app");
188 }
189 return null;
190 }
191
Chris Wailes2be26262019-01-11 16:14:43 -0800192 if (parsedArgs.mApiBlacklistExemptions != null) {
Chris Wailes01060e62019-02-21 13:46:52 -0800193 return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
Mathew Inwood8faeab82018-03-16 14:26:08 +0000194 }
195
Andrei Oneae8e150d2019-02-18 18:27:11 +0000196 if (parsedArgs.mHiddenApiAccessLogSampleRate != -1
197 || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) {
Chris Wailes01060e62019-02-21 13:46:52 -0800198 return handleHiddenApiAccessLogSampleRate(zygoteServer,
Andrei Oneae8e150d2019-02-18 18:27:11 +0000199 parsedArgs.mHiddenApiAccessLogSampleRate,
200 parsedArgs.mHiddenApiAccessStatslogSampleRate);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100201 }
202
Chris Wailes2be26262019-01-11 16:14:43 -0800203 if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
204 throw new ZygoteSecurityException("Client may not specify capabilities: "
205 + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
206 + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
Narayan Kamathbf99d062017-07-05 14:45:38 +0100207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
Chris Wailes2be26262019-01-11 16:14:43 -0800209 Zygote.applyUidSecurityPolicy(parsedArgs, peer);
210 Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Jeff Brownebed7d62011-05-16 17:08:42 -0700211
Chris Wailes2be26262019-01-11 16:14:43 -0800212 Zygote.applyDebuggerSystemProperty(parsedArgs);
213 Zygote.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
Narayan Kamathbf99d062017-07-05 14:45:38 +0100215 int[][] rlimits = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
Chris Wailes2be26262019-01-11 16:14:43 -0800217 if (parsedArgs.mRLimits != null) {
218 rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220
Narayan Kamathbf99d062017-07-05 14:45:38 +0100221 int[] fdsToIgnore = null;
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800222
Chris Wailes2be26262019-01-11 16:14:43 -0800223 if (parsedArgs.mInvokeWith != null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100224 try {
Elliott Hughes3fe59512014-12-12 14:07:34 -0800225 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
Jeff Brownebed7d62011-05-16 17:08:42 -0700226 childPipeFd = pipeFds[1];
227 serverPipeFd = pipeFds[0];
Narayan Kamath6ac7e672015-01-16 16:26:54 +0000228 Os.fcntlInt(childPipeFd, F_SETFD, 0);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100229 fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
230 } catch (ErrnoException errnoEx) {
231 throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
Jeff Brownebed7d62011-05-16 17:08:42 -0700232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
234
Narayan Kamathbf99d062017-07-05 14:45:38 +0100235 /**
236 * In order to avoid leaking descriptors to the Zygote child,
237 * the native code must close the two Zygote socket descriptors
238 * in the child process before it switches from Zygote-root to
239 * the UID and privileges of the application being launched.
240 *
241 * In order to avoid "bad file descriptor" errors when the
242 * two LocalSocket objects are closed, the Posix file
243 * descriptors are released via a dup2() call which closes
244 * the socket and substitutes an open descriptor to /dev/null.
245 */
246
247 int [] fdsToClose = { -1, -1 };
248
249 FileDescriptor fd = mSocket.getFileDescriptor();
250
251 if (fd != null) {
252 fdsToClose[0] = fd.getInt$();
253 }
254
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800255 fd = zygoteServer.getZygoteSocketFileDescriptor();
Narayan Kamathbf99d062017-07-05 14:45:38 +0100256
257 if (fd != null) {
258 fdsToClose[1] = fd.getInt$();
259 }
260
261 fd = null;
262
Chris Wailes2be26262019-01-11 16:14:43 -0800263 pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
264 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
265 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
266 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mPackageName,
Sudheer Shankae51005d2019-02-24 10:24:09 -0800267 parsedArgs.mPackagesForUid, parsedArgs.mSandboxId);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100268
Jeff Brownebed7d62011-05-16 17:08:42 -0700269 try {
270 if (pid == 0) {
271 // in child
Narayan Kamathbf99d062017-07-05 14:45:38 +0100272 zygoteServer.setForkChild();
273
Simon Baldwinba816e02016-01-19 16:34:54 +0000274 zygoteServer.closeServerSocket();
Jeff Brownebed7d62011-05-16 17:08:42 -0700275 IoUtils.closeQuietly(serverPipeFd);
276 serverPipeFd = null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700277
Robert Sesekd0a190df2018-02-12 18:46:01 -0500278 return handleChildProc(parsedArgs, descriptors, childPipeFd,
Chris Wailes2be26262019-01-11 16:14:43 -0800279 parsedArgs.mStartChildZygote);
Jeff Brownebed7d62011-05-16 17:08:42 -0700280 } else {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100281 // In the parent. A pid < 0 indicates a failure and will be handled in
282 // handleParentProc.
Jeff Brownebed7d62011-05-16 17:08:42 -0700283 IoUtils.closeQuietly(childPipeFd);
284 childPipeFd = null;
Narayan Kamathbf99d062017-07-05 14:45:38 +0100285 handleParentProc(pid, descriptors, serverPipeFd);
286 return null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700287 }
288 } finally {
289 IoUtils.closeQuietly(childPipeFd);
290 IoUtils.closeQuietly(serverPipeFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 }
292 }
293
Narayan Kamathbf99d062017-07-05 14:45:38 +0100294 private void handleAbiListQuery() {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100295 try {
296 final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
297 mSocketOutStream.writeInt(abiListBytes.length);
298 mSocketOutStream.write(abiListBytes);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100299 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100300 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100301 }
302 }
303
Andreas Gampe8444dca2018-05-01 13:31:28 -0700304 private void handlePidQuery() {
305 try {
306 String pidString = String.valueOf(Process.myPid());
307 final byte[] pidStringBytes = pidString.getBytes(StandardCharsets.US_ASCII);
308 mSocketOutStream.writeInt(pidStringBytes.length);
309 mSocketOutStream.write(pidStringBytes);
310 } catch (IOException ioe) {
311 throw new IllegalStateException("Error writing to command socket", ioe);
312 }
313 }
314
Narayan Kamath669afcc2017-02-06 20:24:08 +0000315 /**
316 * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
317 * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
318 * if no preload was initiated. The latter implies that the zygote is not configured to load
319 * resources lazy or that the zygote has already handled a previous request to handlePreload.
320 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100321 private void handlePreload() {
Narayan Kamath669afcc2017-02-06 20:24:08 +0000322 try {
323 if (isPreloadComplete()) {
324 mSocketOutStream.writeInt(1);
325 } else {
326 preload();
327 mSocketOutStream.writeInt(0);
328 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000329 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100330 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000331 }
332 }
333
Chris Wailes7e797b62019-02-22 18:29:22 -0800334 private Runnable stateChangeWithUsapPoolReset(ZygoteServer zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800335 Runnable stateChangeCode) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000336 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800337 if (zygoteServer.isUsapPoolEnabled()) {
338 Zygote.emptyUsapPool();
Chris Wailes01060e62019-02-21 13:46:52 -0800339 }
340
341 stateChangeCode.run();
342
Chris Wailes7e797b62019-02-22 18:29:22 -0800343 if (zygoteServer.isUsapPoolEnabled()) {
Chris Wailes01060e62019-02-21 13:46:52 -0800344 Runnable fpResult =
Chris Wailes7e797b62019-02-22 18:29:22 -0800345 zygoteServer.fillUsapPool(
Chris Wailes01060e62019-02-21 13:46:52 -0800346 new int[]{mSocket.getFileDescriptor().getInt$()});
347
348 if (fpResult != null) {
349 zygoteServer.setForkChild();
350 return fpResult;
351 }
352 }
353
Mathew Inwood8faeab82018-03-16 14:26:08 +0000354 mSocketOutStream.writeInt(0);
Chris Wailes01060e62019-02-21 13:46:52 -0800355
356 return null;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000357 } catch (IOException ioe) {
358 throw new IllegalStateException("Error writing to command socket", ioe);
359 }
360 }
361
Chris Wailes01060e62019-02-21 13:46:52 -0800362 /**
363 * Makes the necessary changes to implement a new API blacklist exemption policy, and then
364 * responds to the system server, letting it know that the task has been completed.
365 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800366 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
367 * pool is enabled all existing USAPs have an incorrect API blacklist exemption list. To
Chris Wailes01060e62019-02-21 13:46:52 -0800368 * properly handle this request the pool must be emptied and refilled. This process can return
369 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
370 *
371 * @param zygoteServer The server object that received the request
372 * @param exemptions The new exemption list.
Chris Wailes7e797b62019-02-22 18:29:22 -0800373 * @return A Runnable object representing a new app in any USAPs spawned from here; the
Chris Wailes01060e62019-02-21 13:46:52 -0800374 * zygote process will always receive a null value from this function.
375 */
376 private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800377 return stateChangeWithUsapPoolReset(zygoteServer,
Chris Wailes01060e62019-02-21 13:46:52 -0800378 () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
379 }
380
Chris Wailes7e797b62019-02-22 18:29:22 -0800381 private Runnable handleUsapPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
Chris Wailesdb132a32019-02-20 10:49:27 -0800382 try {
Chris Wailes7e797b62019-02-22 18:29:22 -0800383 Runnable fpResult = zygoteServer.setUsapPoolStatus(newStatus, mSocket);
Chris Wailesdb132a32019-02-20 10:49:27 -0800384
385 if (fpResult == null) {
386 mSocketOutStream.writeInt(0);
387 } else {
388 zygoteServer.setForkChild();
389 }
390
391 return fpResult;
Narayan Kamath669afcc2017-02-06 20:24:08 +0000392 } catch (IOException ioe) {
393 throw new IllegalStateException("Error writing to command socket", ioe);
394 }
395 }
396
Andrei Onea07aab082019-02-06 14:44:22 +0000397 private static class HiddenApiUsageLogger implements VMRuntime.HiddenApiUsageLogger {
Andrei Onea6cd1b702019-01-25 16:29:44 +0000398
399 private final MetricsLogger mMetricsLogger = new MetricsLogger();
Andrei Onea07aab082019-02-06 14:44:22 +0000400 private static HiddenApiUsageLogger sInstance = new HiddenApiUsageLogger();
Andrei Onea31bde162019-02-15 13:50:47 +0000401 private int mHiddenApiAccessLogSampleRate = 0;
Andrei Oneae8e150d2019-02-18 18:27:11 +0000402 private int mHiddenApiAccessStatslogSampleRate = 0;
Andrei Onea31bde162019-02-15 13:50:47 +0000403
Andrei Oneae8e150d2019-02-18 18:27:11 +0000404 public static void setHiddenApiAccessLogSampleRates(int sampleRate, int newSampleRate) {
Andrei Onea31bde162019-02-15 13:50:47 +0000405 sInstance.mHiddenApiAccessLogSampleRate = sampleRate;
Andrei Oneae8e150d2019-02-18 18:27:11 +0000406 sInstance.mHiddenApiAccessStatslogSampleRate = newSampleRate;
Andrei Onea31bde162019-02-15 13:50:47 +0000407 }
Andrei Onea07aab082019-02-06 14:44:22 +0000408
409 public static HiddenApiUsageLogger getInstance() {
410 return HiddenApiUsageLogger.sInstance;
411 }
Andrei Onea6cd1b702019-01-25 16:29:44 +0000412
Andrei Onea31bde162019-02-15 13:50:47 +0000413 public void hiddenApiUsed(int sampledValue, String packageName, String signature,
Andrei Onea6cd1b702019-01-25 16:29:44 +0000414 int accessMethod, boolean accessDenied) {
Andrei Onea31bde162019-02-15 13:50:47 +0000415 if (sampledValue < mHiddenApiAccessLogSampleRate) {
416 logUsage(packageName, signature, accessMethod, accessDenied);
417 }
Andrei Oneae8e150d2019-02-18 18:27:11 +0000418 if (sampledValue < mHiddenApiAccessStatslogSampleRate) {
419 newLogUsage(signature, accessMethod, accessDenied);
420 }
Andrei Onea31bde162019-02-15 13:50:47 +0000421 }
422
423 private void logUsage(String packageName, String signature, int accessMethod,
424 boolean accessDenied) {
Andrei Onea6cd1b702019-01-25 16:29:44 +0000425 int accessMethodMetric = HiddenApiUsageLogger.ACCESS_METHOD_NONE;
426 switch(accessMethod) {
427 case HiddenApiUsageLogger.ACCESS_METHOD_NONE:
428 accessMethodMetric = MetricsEvent.ACCESS_METHOD_NONE;
429 break;
430 case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION:
431 accessMethodMetric = MetricsEvent.ACCESS_METHOD_REFLECTION;
432 break;
433 case HiddenApiUsageLogger.ACCESS_METHOD_JNI:
434 accessMethodMetric = MetricsEvent.ACCESS_METHOD_JNI;
435 break;
436 case HiddenApiUsageLogger.ACCESS_METHOD_LINKING:
437 accessMethodMetric = MetricsEvent.ACCESS_METHOD_LINKING;
438 break;
439 }
440 LogMaker logMaker = new LogMaker(MetricsEvent.ACTION_HIDDEN_API_ACCESSED)
441 .setPackageName(packageName)
442 .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_SIGNATURE, signature)
443 .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_METHOD,
444 accessMethodMetric);
445 if (accessDenied) {
446 logMaker.addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_DENIED, 1);
447 }
448 mMetricsLogger.write(logMaker);
449 }
Andrei Oneae8e150d2019-02-18 18:27:11 +0000450
451 private void newLogUsage(String signature, int accessMethod, boolean accessDenied) {
452 int accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE;
453 switch(accessMethod) {
454 case HiddenApiUsageLogger.ACCESS_METHOD_NONE:
455 accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__NONE;
456 break;
457 case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION:
458 accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__REFLECTION;
459 break;
460 case HiddenApiUsageLogger.ACCESS_METHOD_JNI:
461 accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__JNI;
462 break;
463 case HiddenApiUsageLogger.ACCESS_METHOD_LINKING:
464 accessMethodProto = StatsLog.HIDDEN_API_USED__ACCESS_METHOD__LINKING;
465 break;
466 }
467 int uid = Process.myUid();
468 StatsLog.write(StatsLog.HIDDEN_API_USED, uid, signature,
469 accessMethodProto, accessDenied);
470 }
Andrei Onea6cd1b702019-01-25 16:29:44 +0000471 }
472
Chris Wailes01060e62019-02-21 13:46:52 -0800473 /**
474 * Changes the API access log sample rate for the Zygote and processes spawned from it.
475 *
Chris Wailes7e797b62019-02-22 18:29:22 -0800476 * This necessitates a change to the internal state of the Zygote. As such, if the USAP
477 * pool is enabled all existing USAPs have an incorrect API access log sample rate. To
Chris Wailes01060e62019-02-21 13:46:52 -0800478 * properly handle this request the pool must be emptied and refilled. This process can return
479 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
480 *
481 * @param zygoteServer The server object that received the request
Andrei Oneae8e150d2019-02-18 18:27:11 +0000482 * @param samplingRate The new sample rate for regular logging
483 * @param statsdSamplingRate The new sample rate for statslog logging
Chris Wailes01060e62019-02-21 13:46:52 -0800484 * @return A Runnable object representing a new app in any blastulas spawned from here; the
485 * zygote process will always receive a null value from this function.
486 */
487 private Runnable handleHiddenApiAccessLogSampleRate(ZygoteServer zygoteServer,
Andrei Oneae8e150d2019-02-18 18:27:11 +0000488 int samplingRate, int statsdSamplingRate) {
Chris Wailes7e797b62019-02-22 18:29:22 -0800489 return stateChangeWithUsapPoolReset(zygoteServer, () -> {
Andrei Oneae8e150d2019-02-18 18:27:11 +0000490 int maxSamplingRate = Math.max(samplingRate, statsdSamplingRate);
491 ZygoteInit.setHiddenApiAccessLogSampleRate(maxSamplingRate);
Chris Wailes7e797b62019-02-22 18:29:22 -0800492 HiddenApiUsageLogger.setHiddenApiAccessLogSampleRates(samplingRate, statsdSamplingRate);
Andrei Onea07aab082019-02-06 14:44:22 +0000493 ZygoteInit.setHiddenApiUsageLogger(HiddenApiUsageLogger.getInstance());
Chris Wailes01060e62019-02-21 13:46:52 -0800494 });
Mathew Inwood04194fe2018-04-04 14:48:03 +0100495 }
496
Narayan Kamath669afcc2017-02-06 20:24:08 +0000497 protected void preload() {
498 ZygoteInit.lazyPreload();
499 }
500
501 protected boolean isPreloadComplete() {
502 return ZygoteInit.isPreloadComplete();
Torne (Richard Coles)bb658932017-01-05 16:11:06 +0000503 }
504
Narayan Kamath24a33062017-07-03 14:12:26 +0100505 protected DataOutputStream getSocketOutputStream() {
506 return mSocketOutStream;
507 }
508
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500509 protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
510 String cacheKey) {
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100511 throw new RuntimeException("Zygote does not support package preloading");
512 }
513
514 protected boolean canPreloadApp() {
515 return false;
516 }
517
518 protected void handlePreloadApp(ApplicationInfo aInfo) {
519 throw new RuntimeException("Zygote does not support app preloading");
Robert Sesekded20982016-08-15 13:59:13 -0400520 }
521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 /**
523 * Closes socket associated with this connection.
524 */
525 void closeSocket() {
526 try {
527 mSocket.close();
528 } catch (IOException ex) {
529 Log.e(TAG, "Exception while closing command "
530 + "socket in parent", ex);
531 }
532 }
533
Narayan Kamathbf99d062017-07-05 14:45:38 +0100534 boolean isClosedByPeer() {
535 return isEof;
536 }
537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 * Handles post-fork setup of child proc, closing sockets as appropriate,
540 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
541 * if successful or returning if failed.
542 *
543 * @param parsedArgs non-null; zygote args
544 * @param descriptors null-ok; new file descriptors for stdio if available.
Jeff Brownebed7d62011-05-16 17:08:42 -0700545 * @param pipeFd null-ok; pipe for communication back to Zygote.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500546 * @param isZygote whether this new child process is itself a new Zygote.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 */
Chris Wailes2be26262019-01-11 16:14:43 -0800548 private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500549 FileDescriptor pipeFd, boolean isZygote) {
Dave Platt89d4c892014-02-05 17:06:42 -0800550 /**
551 * By the time we get here, the native code has closed the two actual Zygote
552 * socket connections, and substituted /dev/null in their place. The LocalSocket
553 * objects still need to be closed properly.
554 */
555
Nick Kralevich468f6c12013-01-30 08:45:03 -0800556 closeSocket();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 if (descriptors != null) {
558 try {
Elliott Hughesdac83f52014-12-15 11:00:25 -0800559 Os.dup2(descriptors[0], STDIN_FILENO);
560 Os.dup2(descriptors[1], STDOUT_FILENO);
561 Os.dup2(descriptors[2], STDERR_FILENO);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562
563 for (FileDescriptor fd: descriptors) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700564 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 }
Elliott Hughesdac83f52014-12-15 11:00:25 -0800566 } catch (ErrnoException ex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 Log.e(TAG, "Error reopening stdio", ex);
568 }
569 }
570
Chris Wailes2be26262019-01-11 16:14:43 -0800571 if (parsedArgs.mNiceName != null) {
572 Process.setArgV0(parsedArgs.mNiceName);
Jeff Brownebed7d62011-05-16 17:08:42 -0700573 }
574
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100575 // End of the postFork event.
576 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Chris Wailes2be26262019-01-11 16:14:43 -0800577 if (parsedArgs.mInvokeWith != null) {
578 WrapperInit.execApplication(parsedArgs.mInvokeWith,
579 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000580 VMRuntime.getCurrentInstructionSet(),
Chris Wailes2be26262019-01-11 16:14:43 -0800581 pipeFd, parsedArgs.mRemainingArgs);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100582
583 // Should not get here.
584 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
Jeff Brownebed7d62011-05-16 17:08:42 -0700585 } else {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500586 if (!isZygote) {
Chris Wailes2be26262019-01-11 16:14:43 -0800587 return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
588 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500589 } else {
Chris Wailes2be26262019-01-11 16:14:43 -0800590 return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
591 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 }
594 }
595
596 /**
597 * Handles post-fork cleanup of parent proc
598 *
599 * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
600 * if &lt; 0;
601 * @param descriptors null-ok; file descriptors for child's new stdio if
602 * specified.
Jeff Brownebed7d62011-05-16 17:08:42 -0700603 * @param pipeFd null-ok; pipe for communication with child.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100605 private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700606 if (pid > 0) {
607 setChildPgid(pid);
608 }
609
610 if (descriptors != null) {
611 for (FileDescriptor fd: descriptors) {
612 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 }
614 }
615
Jeff Brown3f9dd282011-07-08 20:02:19 -0700616 boolean usingWrapper = false;
Jeff Brownebed7d62011-05-16 17:08:42 -0700617 if (pipeFd != null && pid > 0) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700618 int innerPid = -1;
619 try {
Andreas Gampecbc42142017-07-12 19:17:52 -0700620 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
621 // bail) happens in a timely manner.
Andreas Gampecbc42142017-07-12 19:17:52 -0700622 final int BYTES_REQUIRED = 4; // Bytes in an int.
623
624 StructPollfd fds[] = new StructPollfd[] {
625 new StructPollfd()
626 };
627
628 byte data[] = new byte[BYTES_REQUIRED];
629
Andreas Gampe27497c62017-07-21 11:41:00 -0700630 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
Andreas Gampecbc42142017-07-12 19:17:52 -0700631 int dataIndex = 0;
632 long startTime = System.nanoTime();
633
634 while (dataIndex < data.length && remainingSleepTime > 0) {
635 fds[0].fd = pipeFd;
636 fds[0].events = (short) POLLIN;
637 fds[0].revents = 0;
638 fds[0].userData = null;
639
640 int res = android.system.Os.poll(fds, remainingSleepTime);
641 long endTime = System.nanoTime();
Andreas Gampe27497c62017-07-21 11:41:00 -0700642 int elapsedTimeMs = (int)((endTime - startTime) / 1000000l);
643 remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
Andreas Gampecbc42142017-07-12 19:17:52 -0700644
645 if (res > 0) {
646 if ((fds[0].revents & POLLIN) != 0) {
647 // Only read one byte, so as not to block.
648 int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
649 if (readBytes < 0) {
650 throw new RuntimeException("Some error");
651 }
652 dataIndex += readBytes;
653 } else {
654 // Error case. revents should contain one of the error bits.
655 break;
656 }
657 } else if (res == 0) {
658 Log.w(TAG, "Timed out waiting for child.");
659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 }
Andreas Gampecbc42142017-07-12 19:17:52 -0700661
662 if (dataIndex == data.length) {
663 DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
664 innerPid = is.readInt();
665 }
666
667 if (innerPid == -1) {
668 Log.w(TAG, "Error reading pid from wrapped process, child may have died");
669 }
670 } catch (Exception ex) {
671 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700673
674 // Ensure that the pid reported by the wrapped process is either the
675 // child process that we forked, or a descendant of it.
676 if (innerPid > 0) {
677 int parentPid = innerPid;
678 while (parentPid > 0 && parentPid != pid) {
679 parentPid = Process.getParentPid(parentPid);
680 }
681 if (parentPid > 0) {
682 Log.i(TAG, "Wrapped process has pid " + innerPid);
683 pid = innerPid;
Jeff Brown3f9dd282011-07-08 20:02:19 -0700684 usingWrapper = true;
Jeff Brownebed7d62011-05-16 17:08:42 -0700685 } else {
686 Log.w(TAG, "Wrapped process reported a pid that is not a child of "
687 + "the process that we forked: childPid=" + pid
688 + " innerPid=" + innerPid);
689 }
690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 }
692
693 try {
694 mSocketOutStream.writeInt(pid);
Jeff Brown3f9dd282011-07-08 20:02:19 -0700695 mSocketOutStream.writeBoolean(usingWrapper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100697 throw new IllegalStateException("Error writing to command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 }
700
Jeff Brownebed7d62011-05-16 17:08:42 -0700701 private void setChildPgid(int pid) {
702 // Try to move the new child into the peer's process group.
703 try {
Elliott Hughes26b56e62014-12-17 12:28:29 -0800704 Os.setpgid(pid, Os.getpgid(peer.getPid()));
705 } catch (ErrnoException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700706 // This exception is expected in the case where
707 // the peer is not in our session
708 // TODO get rid of this log message in the case where
709 // getsid(0) != getsid(peer.getPid())
710 Log.i(TAG, "Zygote: setpgid failed. This is "
711 + "normal if peer is not in our session");
712 }
713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714}