blob: c7ba22df5700b55a479819139500bbc7e2c72287 [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;
Sudheer Shankad81b1d72018-09-05 16:37:30 -070040
Andrei Onea6cd1b702019-01-25 16:29:44 +000041import com.android.internal.logging.MetricsLogger;
42import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
43
Narayan Kamath37ad4b02015-01-19 16:05:24 +000044import dalvik.system.VMRuntime;
Sudheer Shankad81b1d72018-09-05 16:37:30 -070045
46import libcore.io.IoUtils;
47
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import java.io.BufferedReader;
Andreas Gampecbc42142017-07-12 19:17:52 -070049import java.io.ByteArrayInputStream;
Jeff Brownebed7d62011-05-16 17:08:42 -070050import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.io.DataOutputStream;
52import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import java.io.IOException;
54import java.io.InputStreamReader;
Narayan Kamathc41638c2014-04-07 13:56:15 +010055import java.nio.charset.StandardCharsets;
Martijn Coenen7e6fa672018-11-05 11:45:26 +010056import java.util.Base64;
Mathew Inwood8faeab82018-03-16 14:26:08 +000057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058/**
59 * A connection that can make spawn requests.
60 */
61class ZygoteConnection {
62 private static final String TAG = "Zygote";
63
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 * The command socket.
66 *
67 * mSocket is retained in the child process in "peer wait" mode, so
68 * that it closes when the child process terminates. In other cases,
69 * it is closed in the peer.
70 */
71 private final LocalSocket mSocket;
72 private final DataOutputStream mSocketOutStream;
73 private final BufferedReader mSocketReader;
74 private final Credentials peer;
Narayan Kamathc41638c2014-04-07 13:56:15 +010075 private final String abiList;
Narayan Kamathbf99d062017-07-05 14:45:38 +010076 private boolean isEof;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077
78 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 * Constructs instance from connected socket.
80 *
81 * @param socket non-null; connected socket
Narayan Kamathc41638c2014-04-07 13:56:15 +010082 * @param abiList non-null; a list of ABIs this zygote supports.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 * @throws IOException
84 */
Narayan Kamathc41638c2014-04-07 13:56:15 +010085 ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 mSocket = socket;
Narayan Kamathc41638c2014-04-07 13:56:15 +010087 this.abiList = abiList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
89 mSocketOutStream
90 = new DataOutputStream(socket.getOutputStream());
91
92 mSocketReader = new BufferedReader(
93 new InputStreamReader(socket.getInputStream()), 256);
94
95 mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
dcashmanfc4c0bf82015-03-05 17:17:47 -080096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 try {
98 peer = mSocket.getPeerCredentials();
99 } catch (IOException ex) {
100 Log.e(TAG, "Cannot read peer credentials", ex);
101 throw ex;
102 }
Narayan Kamathbf99d062017-07-05 14:45:38 +0100103
104 isEof = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 }
106
107 /**
108 * Returns the file descriptor of the associated socket.
109 *
110 * @return null-ok; file descriptor
111 */
Chris Wailes2be26262019-01-11 16:14:43 -0800112 FileDescriptor getFileDescriptor() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 return mSocket.getFileDescriptor();
114 }
115
116 /**
Narayan Kamathbf99d062017-07-05 14:45:38 +0100117 * Reads one start command from the command socket. If successful, a child is forked and a
118 * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
119 * process. {@code null} is always returned in the parent process (the zygote).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 *
Narayan Kamathbf99d062017-07-05 14:45:38 +0100121 * If the client closes the socket, an {@code EOF} condition is set, which callers can test
122 * for by calling {@code ZygoteConnection.isClosedByPeer}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100124 Runnable processOneCommand(ZygoteServer zygoteServer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 String args[];
Chris Wailes2be26262019-01-11 16:14:43 -0800126 ZygoteArguments parsedArgs = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 FileDescriptor[] descriptors;
128
129 try {
Chris Wailes2be26262019-01-11 16:14:43 -0800130 args = Zygote.readArgumentList(mSocketReader);
131
132 // TODO (chriswailes): Remove this and add an assert.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 descriptors = mSocket.getAncillaryFileDescriptors();
134 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100135 throw new IllegalStateException("IOException on command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 }
137
Narayan Kamathbf99d062017-07-05 14:45:38 +0100138 // readArgumentList returns null only when it has reached EOF with no available
139 // data to read. This will only happen when the remote socket has disconnected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 if (args == null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100141 isEof = true;
142 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 }
144
Jeff Brownebed7d62011-05-16 17:08:42 -0700145 int pid = -1;
146 FileDescriptor childPipeFd = null;
147 FileDescriptor serverPipeFd = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
Chris Wailes2be26262019-01-11 16:14:43 -0800149 parsedArgs = new ZygoteArguments(args);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100150
Chris Wailes2be26262019-01-11 16:14:43 -0800151 if (parsedArgs.mAbiListQuery) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100152 handleAbiListQuery();
153 return null;
154 }
Narayan Kamathc41638c2014-04-07 13:56:15 +0100155
Chris Wailes2be26262019-01-11 16:14:43 -0800156 if (parsedArgs.mPidQuery) {
Andreas Gampe8444dca2018-05-01 13:31:28 -0700157 handlePidQuery();
158 return null;
159 }
160
Chris Wailesdb132a32019-02-20 10:49:27 -0800161 if (parsedArgs.mBlastulaPoolStatusSpecified) {
162 return handleBlastulaPoolStatusChange(zygoteServer, parsedArgs.mBlastulaPoolEnabled);
163 }
164
Chris Wailes2be26262019-01-11 16:14:43 -0800165 if (parsedArgs.mPreloadDefault) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100166 handlePreload();
167 return null;
168 }
Narayan Kamath5a3d0c62016-11-09 15:35:18 +0000169
Chris Wailes2be26262019-01-11 16:14:43 -0800170 if (parsedArgs.mPreloadPackage != null) {
171 handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs,
172 parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100173 return null;
174 }
Robert Sesekded20982016-08-15 13:59:13 -0400175
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100176 if (canPreloadApp() && parsedArgs.mPreloadApp != null) {
177 byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp);
178 Parcel appInfoParcel = Parcel.obtain();
179 appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length);
180 appInfoParcel.setDataPosition(0);
181 ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel);
182 appInfoParcel.recycle();
183 if (appInfo != null) {
184 handlePreloadApp(appInfo);
185 } else {
186 throw new IllegalArgumentException("Failed to deserialize --preload-app");
187 }
188 return null;
189 }
190
Chris Wailes2be26262019-01-11 16:14:43 -0800191 if (parsedArgs.mApiBlacklistExemptions != null) {
Chris Wailes01060e62019-02-21 13:46:52 -0800192 return handleApiBlacklistExemptions(zygoteServer, parsedArgs.mApiBlacklistExemptions);
Mathew Inwood8faeab82018-03-16 14:26:08 +0000193 }
194
Chris Wailes2be26262019-01-11 16:14:43 -0800195 if (parsedArgs.mHiddenApiAccessLogSampleRate != -1) {
Chris Wailes01060e62019-02-21 13:46:52 -0800196 return handleHiddenApiAccessLogSampleRate(zygoteServer,
197 parsedArgs.mHiddenApiAccessLogSampleRate);
Mathew Inwood04194fe2018-04-04 14:48:03 +0100198 }
199
Chris Wailes2be26262019-01-11 16:14:43 -0800200 if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) {
201 throw new ZygoteSecurityException("Client may not specify capabilities: "
202 + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities)
203 + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities));
Narayan Kamathbf99d062017-07-05 14:45:38 +0100204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205
Chris Wailes2be26262019-01-11 16:14:43 -0800206 Zygote.applyUidSecurityPolicy(parsedArgs, peer);
207 Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer);
Jeff Brownebed7d62011-05-16 17:08:42 -0700208
Chris Wailes2be26262019-01-11 16:14:43 -0800209 Zygote.applyDebuggerSystemProperty(parsedArgs);
210 Zygote.applyInvokeWithSystemProperty(parsedArgs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211
Narayan Kamathbf99d062017-07-05 14:45:38 +0100212 int[][] rlimits = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Chris Wailes2be26262019-01-11 16:14:43 -0800214 if (parsedArgs.mRLimits != null) {
215 rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217
Narayan Kamathbf99d062017-07-05 14:45:38 +0100218 int[] fdsToIgnore = null;
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800219
Chris Wailes2be26262019-01-11 16:14:43 -0800220 if (parsedArgs.mInvokeWith != null) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100221 try {
Elliott Hughes3fe59512014-12-12 14:07:34 -0800222 FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC);
Jeff Brownebed7d62011-05-16 17:08:42 -0700223 childPipeFd = pipeFds[1];
224 serverPipeFd = pipeFds[0];
Narayan Kamath6ac7e672015-01-16 16:26:54 +0000225 Os.fcntlInt(childPipeFd, F_SETFD, 0);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100226 fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()};
227 } catch (ErrnoException errnoEx) {
228 throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx);
Jeff Brownebed7d62011-05-16 17:08:42 -0700229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 }
231
Narayan Kamathbf99d062017-07-05 14:45:38 +0100232 /**
233 * In order to avoid leaking descriptors to the Zygote child,
234 * the native code must close the two Zygote socket descriptors
235 * in the child process before it switches from Zygote-root to
236 * the UID and privileges of the application being launched.
237 *
238 * In order to avoid "bad file descriptor" errors when the
239 * two LocalSocket objects are closed, the Posix file
240 * descriptors are released via a dup2() call which closes
241 * the socket and substitutes an open descriptor to /dev/null.
242 */
243
244 int [] fdsToClose = { -1, -1 };
245
246 FileDescriptor fd = mSocket.getFileDescriptor();
247
248 if (fd != null) {
249 fdsToClose[0] = fd.getInt$();
250 }
251
Chris Wailesba4c2eb2019-01-11 17:13:00 -0800252 fd = zygoteServer.getZygoteSocketFileDescriptor();
Narayan Kamathbf99d062017-07-05 14:45:38 +0100253
254 if (fd != null) {
255 fdsToClose[1] = fd.getInt$();
256 }
257
258 fd = null;
259
Chris Wailes2be26262019-01-11 16:14:43 -0800260 pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
261 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
262 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
263 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mPackageName,
Sudheer Shankae51005d2019-02-24 10:24:09 -0800264 parsedArgs.mPackagesForUid, parsedArgs.mSandboxId);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100265
Jeff Brownebed7d62011-05-16 17:08:42 -0700266 try {
267 if (pid == 0) {
268 // in child
Narayan Kamathbf99d062017-07-05 14:45:38 +0100269 zygoteServer.setForkChild();
270
Simon Baldwinba816e02016-01-19 16:34:54 +0000271 zygoteServer.closeServerSocket();
Jeff Brownebed7d62011-05-16 17:08:42 -0700272 IoUtils.closeQuietly(serverPipeFd);
273 serverPipeFd = null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700274
Robert Sesekd0a190df2018-02-12 18:46:01 -0500275 return handleChildProc(parsedArgs, descriptors, childPipeFd,
Chris Wailes2be26262019-01-11 16:14:43 -0800276 parsedArgs.mStartChildZygote);
Jeff Brownebed7d62011-05-16 17:08:42 -0700277 } else {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100278 // In the parent. A pid < 0 indicates a failure and will be handled in
279 // handleParentProc.
Jeff Brownebed7d62011-05-16 17:08:42 -0700280 IoUtils.closeQuietly(childPipeFd);
281 childPipeFd = null;
Narayan Kamathbf99d062017-07-05 14:45:38 +0100282 handleParentProc(pid, descriptors, serverPipeFd);
283 return null;
Jeff Brownebed7d62011-05-16 17:08:42 -0700284 }
285 } finally {
286 IoUtils.closeQuietly(childPipeFd);
287 IoUtils.closeQuietly(serverPipeFd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 }
289 }
290
Narayan Kamathbf99d062017-07-05 14:45:38 +0100291 private void handleAbiListQuery() {
Narayan Kamathc41638c2014-04-07 13:56:15 +0100292 try {
293 final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
294 mSocketOutStream.writeInt(abiListBytes.length);
295 mSocketOutStream.write(abiListBytes);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100296 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100297 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamathc41638c2014-04-07 13:56:15 +0100298 }
299 }
300
Andreas Gampe8444dca2018-05-01 13:31:28 -0700301 private void handlePidQuery() {
302 try {
303 String pidString = String.valueOf(Process.myPid());
304 final byte[] pidStringBytes = pidString.getBytes(StandardCharsets.US_ASCII);
305 mSocketOutStream.writeInt(pidStringBytes.length);
306 mSocketOutStream.write(pidStringBytes);
307 } catch (IOException ioe) {
308 throw new IllegalStateException("Error writing to command socket", ioe);
309 }
310 }
311
Narayan Kamath669afcc2017-02-06 20:24:08 +0000312 /**
313 * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
314 * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
315 * if no preload was initiated. The latter implies that the zygote is not configured to load
316 * resources lazy or that the zygote has already handled a previous request to handlePreload.
317 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100318 private void handlePreload() {
Narayan Kamath669afcc2017-02-06 20:24:08 +0000319 try {
320 if (isPreloadComplete()) {
321 mSocketOutStream.writeInt(1);
322 } else {
323 preload();
324 mSocketOutStream.writeInt(0);
325 }
Narayan Kamath669afcc2017-02-06 20:24:08 +0000326 } catch (IOException ioe) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100327 throw new IllegalStateException("Error writing to command socket", ioe);
Narayan Kamath669afcc2017-02-06 20:24:08 +0000328 }
329 }
330
Chris Wailes01060e62019-02-21 13:46:52 -0800331 private Runnable stateChangeWithBlastulaPoolReset(ZygoteServer zygoteServer,
332 Runnable stateChangeCode) {
Mathew Inwood8faeab82018-03-16 14:26:08 +0000333 try {
Chris Wailes01060e62019-02-21 13:46:52 -0800334 if (zygoteServer.isBlastulaPoolEnabled()) {
335 Zygote.emptyBlastulaPool();
336 }
337
338 stateChangeCode.run();
339
340 if (zygoteServer.isBlastulaPoolEnabled()) {
341 Runnable fpResult =
342 zygoteServer.fillBlastulaPool(
343 new int[]{mSocket.getFileDescriptor().getInt$()});
344
345 if (fpResult != null) {
346 zygoteServer.setForkChild();
347 return fpResult;
348 }
349 }
350
Mathew Inwood8faeab82018-03-16 14:26:08 +0000351 mSocketOutStream.writeInt(0);
Chris Wailes01060e62019-02-21 13:46:52 -0800352
353 return null;
Mathew Inwood8faeab82018-03-16 14:26:08 +0000354 } catch (IOException ioe) {
355 throw new IllegalStateException("Error writing to command socket", ioe);
356 }
357 }
358
Chris Wailes01060e62019-02-21 13:46:52 -0800359 /**
360 * Makes the necessary changes to implement a new API blacklist exemption policy, and then
361 * responds to the system server, letting it know that the task has been completed.
362 *
363 * This necessitates a change to the internal state of the Zygote. As such, if the blastula
364 * pool is enabled all existing blastulas have an incorrect API blacklist exemption list. To
365 * properly handle this request the pool must be emptied and refilled. This process can return
366 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
367 *
368 * @param zygoteServer The server object that received the request
369 * @param exemptions The new exemption list.
370 * @return A Runnable object representing a new app in any blastulas spawned from here; the
371 * zygote process will always receive a null value from this function.
372 */
373 private Runnable handleApiBlacklistExemptions(ZygoteServer zygoteServer, String[] exemptions) {
374 return stateChangeWithBlastulaPoolReset(zygoteServer,
375 () -> ZygoteInit.setApiBlacklistExemptions(exemptions));
376 }
377
Chris Wailesdb132a32019-02-20 10:49:27 -0800378 private Runnable handleBlastulaPoolStatusChange(ZygoteServer zygoteServer, boolean newStatus) {
379 try {
380 Runnable fpResult = zygoteServer.setBlastulaPoolStatus(newStatus, mSocket);
381
382 if (fpResult == null) {
383 mSocketOutStream.writeInt(0);
384 } else {
385 zygoteServer.setForkChild();
386 }
387
388 return fpResult;
Narayan Kamath669afcc2017-02-06 20:24:08 +0000389 } catch (IOException ioe) {
390 throw new IllegalStateException("Error writing to command socket", ioe);
391 }
392 }
393
Andrei Onea07aab082019-02-06 14:44:22 +0000394 private static class HiddenApiUsageLogger implements VMRuntime.HiddenApiUsageLogger {
Andrei Onea6cd1b702019-01-25 16:29:44 +0000395
396 private final MetricsLogger mMetricsLogger = new MetricsLogger();
Andrei Onea07aab082019-02-06 14:44:22 +0000397 private static HiddenApiUsageLogger sInstance = new HiddenApiUsageLogger();
Andrei Onea31bde162019-02-15 13:50:47 +0000398 private int mHiddenApiAccessLogSampleRate = 0;
399
400 public static void setHiddenApiAccessLogSampleRate(int sampleRate) {
401 sInstance.mHiddenApiAccessLogSampleRate = sampleRate;
402 }
Andrei Onea07aab082019-02-06 14:44:22 +0000403
404 public static HiddenApiUsageLogger getInstance() {
405 return HiddenApiUsageLogger.sInstance;
406 }
Andrei Onea6cd1b702019-01-25 16:29:44 +0000407
Andrei Onea31bde162019-02-15 13:50:47 +0000408 public void hiddenApiUsed(int sampledValue, String packageName, String signature,
Andrei Onea6cd1b702019-01-25 16:29:44 +0000409 int accessMethod, boolean accessDenied) {
Andrei Onea31bde162019-02-15 13:50:47 +0000410 if (sampledValue < mHiddenApiAccessLogSampleRate) {
411 logUsage(packageName, signature, accessMethod, accessDenied);
412 }
413 }
414
415 private void logUsage(String packageName, String signature, int accessMethod,
416 boolean accessDenied) {
Andrei Onea6cd1b702019-01-25 16:29:44 +0000417 int accessMethodMetric = HiddenApiUsageLogger.ACCESS_METHOD_NONE;
418 switch(accessMethod) {
419 case HiddenApiUsageLogger.ACCESS_METHOD_NONE:
420 accessMethodMetric = MetricsEvent.ACCESS_METHOD_NONE;
421 break;
422 case HiddenApiUsageLogger.ACCESS_METHOD_REFLECTION:
423 accessMethodMetric = MetricsEvent.ACCESS_METHOD_REFLECTION;
424 break;
425 case HiddenApiUsageLogger.ACCESS_METHOD_JNI:
426 accessMethodMetric = MetricsEvent.ACCESS_METHOD_JNI;
427 break;
428 case HiddenApiUsageLogger.ACCESS_METHOD_LINKING:
429 accessMethodMetric = MetricsEvent.ACCESS_METHOD_LINKING;
430 break;
431 }
432 LogMaker logMaker = new LogMaker(MetricsEvent.ACTION_HIDDEN_API_ACCESSED)
433 .setPackageName(packageName)
434 .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_SIGNATURE, signature)
435 .addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_METHOD,
436 accessMethodMetric);
437 if (accessDenied) {
438 logMaker.addTaggedData(MetricsEvent.FIELD_HIDDEN_API_ACCESS_DENIED, 1);
439 }
440 mMetricsLogger.write(logMaker);
441 }
442 }
443
Chris Wailes01060e62019-02-21 13:46:52 -0800444 /**
445 * Changes the API access log sample rate for the Zygote and processes spawned from it.
446 *
447 * This necessitates a change to the internal state of the Zygote. As such, if the blastula
448 * pool is enabled all existing blastulas have an incorrect API access log sample rate. To
449 * properly handle this request the pool must be emptied and refilled. This process can return
450 * a Runnable object that must be returned to ZygoteServer.runSelectLoop to be invoked.
451 *
452 * @param zygoteServer The server object that received the request
453 * @param samplingRate The new sample rate
454 * @return A Runnable object representing a new app in any blastulas spawned from here; the
455 * zygote process will always receive a null value from this function.
456 */
457 private Runnable handleHiddenApiAccessLogSampleRate(ZygoteServer zygoteServer,
458 int samplingRate) {
459 return stateChangeWithBlastulaPoolReset(zygoteServer, () -> {
Andrei Onea6cd1b702019-01-25 16:29:44 +0000460 ZygoteInit.setHiddenApiAccessLogSampleRate(samplingRate);
Andrei Onea31bde162019-02-15 13:50:47 +0000461 HiddenApiUsageLogger.setHiddenApiAccessLogSampleRate(samplingRate);
Andrei Onea07aab082019-02-06 14:44:22 +0000462 ZygoteInit.setHiddenApiUsageLogger(HiddenApiUsageLogger.getInstance());
Chris Wailes01060e62019-02-21 13:46:52 -0800463 });
Mathew Inwood04194fe2018-04-04 14:48:03 +0100464 }
465
Narayan Kamath669afcc2017-02-06 20:24:08 +0000466 protected void preload() {
467 ZygoteInit.lazyPreload();
468 }
469
470 protected boolean isPreloadComplete() {
471 return ZygoteInit.isPreloadComplete();
Torne (Richard Coles)bb658932017-01-05 16:11:06 +0000472 }
473
Narayan Kamath24a33062017-07-03 14:12:26 +0100474 protected DataOutputStream getSocketOutputStream() {
475 return mSocketOutStream;
476 }
477
Torne (Richard Coles)f4f647e2018-02-21 16:12:36 -0500478 protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
479 String cacheKey) {
Martijn Coenen7e6fa672018-11-05 11:45:26 +0100480 throw new RuntimeException("Zygote does not support package preloading");
481 }
482
483 protected boolean canPreloadApp() {
484 return false;
485 }
486
487 protected void handlePreloadApp(ApplicationInfo aInfo) {
488 throw new RuntimeException("Zygote does not support app preloading");
Robert Sesekded20982016-08-15 13:59:13 -0400489 }
490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 /**
492 * Closes socket associated with this connection.
493 */
494 void closeSocket() {
495 try {
496 mSocket.close();
497 } catch (IOException ex) {
498 Log.e(TAG, "Exception while closing command "
499 + "socket in parent", ex);
500 }
501 }
502
Narayan Kamathbf99d062017-07-05 14:45:38 +0100503 boolean isClosedByPeer() {
504 return isEof;
505 }
506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 * Handles post-fork setup of child proc, closing sockets as appropriate,
509 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
510 * if successful or returning if failed.
511 *
512 * @param parsedArgs non-null; zygote args
513 * @param descriptors null-ok; new file descriptors for stdio if available.
Jeff Brownebed7d62011-05-16 17:08:42 -0700514 * @param pipeFd null-ok; pipe for communication back to Zygote.
Robert Sesekd0a190df2018-02-12 18:46:01 -0500515 * @param isZygote whether this new child process is itself a new Zygote.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 */
Chris Wailes2be26262019-01-11 16:14:43 -0800517 private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
Robert Sesekd0a190df2018-02-12 18:46:01 -0500518 FileDescriptor pipeFd, boolean isZygote) {
Dave Platt89d4c892014-02-05 17:06:42 -0800519 /**
520 * By the time we get here, the native code has closed the two actual Zygote
521 * socket connections, and substituted /dev/null in their place. The LocalSocket
522 * objects still need to be closed properly.
523 */
524
Nick Kralevich468f6c12013-01-30 08:45:03 -0800525 closeSocket();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 if (descriptors != null) {
527 try {
Elliott Hughesdac83f52014-12-15 11:00:25 -0800528 Os.dup2(descriptors[0], STDIN_FILENO);
529 Os.dup2(descriptors[1], STDOUT_FILENO);
530 Os.dup2(descriptors[2], STDERR_FILENO);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531
532 for (FileDescriptor fd: descriptors) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700533 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 }
Elliott Hughesdac83f52014-12-15 11:00:25 -0800535 } catch (ErrnoException ex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 Log.e(TAG, "Error reopening stdio", ex);
537 }
538 }
539
Chris Wailes2be26262019-01-11 16:14:43 -0800540 if (parsedArgs.mNiceName != null) {
541 Process.setArgV0(parsedArgs.mNiceName);
Jeff Brownebed7d62011-05-16 17:08:42 -0700542 }
543
Narayan Kamathfbb32f62015-06-12 15:34:35 +0100544 // End of the postFork event.
545 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Chris Wailes2be26262019-01-11 16:14:43 -0800546 if (parsedArgs.mInvokeWith != null) {
547 WrapperInit.execApplication(parsedArgs.mInvokeWith,
548 parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
Narayan Kamath37ad4b02015-01-19 16:05:24 +0000549 VMRuntime.getCurrentInstructionSet(),
Chris Wailes2be26262019-01-11 16:14:43 -0800550 pipeFd, parsedArgs.mRemainingArgs);
Narayan Kamathbf99d062017-07-05 14:45:38 +0100551
552 // Should not get here.
553 throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
Jeff Brownebed7d62011-05-16 17:08:42 -0700554 } else {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500555 if (!isZygote) {
Chris Wailes2be26262019-01-11 16:14:43 -0800556 return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
557 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500558 } else {
Chris Wailes2be26262019-01-11 16:14:43 -0800559 return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
560 parsedArgs.mRemainingArgs, null /* classLoader */);
Robert Sesekd0a190df2018-02-12 18:46:01 -0500561 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563 }
564
565 /**
566 * Handles post-fork cleanup of parent proc
567 *
568 * @param pid != 0; pid of child if &gt; 0 or indication of failed fork
569 * if &lt; 0;
570 * @param descriptors null-ok; file descriptors for child's new stdio if
571 * specified.
Jeff Brownebed7d62011-05-16 17:08:42 -0700572 * @param pipeFd null-ok; pipe for communication with child.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 */
Narayan Kamathbf99d062017-07-05 14:45:38 +0100574 private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700575 if (pid > 0) {
576 setChildPgid(pid);
577 }
578
579 if (descriptors != null) {
580 for (FileDescriptor fd: descriptors) {
581 IoUtils.closeQuietly(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583 }
584
Jeff Brown3f9dd282011-07-08 20:02:19 -0700585 boolean usingWrapper = false;
Jeff Brownebed7d62011-05-16 17:08:42 -0700586 if (pipeFd != null && pid > 0) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700587 int innerPid = -1;
588 try {
Andreas Gampecbc42142017-07-12 19:17:52 -0700589 // Do a busy loop here. We can't guarantee that a failure (and thus an exception
590 // bail) happens in a timely manner.
Andreas Gampecbc42142017-07-12 19:17:52 -0700591 final int BYTES_REQUIRED = 4; // Bytes in an int.
592
593 StructPollfd fds[] = new StructPollfd[] {
594 new StructPollfd()
595 };
596
597 byte data[] = new byte[BYTES_REQUIRED];
598
Andreas Gampe27497c62017-07-21 11:41:00 -0700599 int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
Andreas Gampecbc42142017-07-12 19:17:52 -0700600 int dataIndex = 0;
601 long startTime = System.nanoTime();
602
603 while (dataIndex < data.length && remainingSleepTime > 0) {
604 fds[0].fd = pipeFd;
605 fds[0].events = (short) POLLIN;
606 fds[0].revents = 0;
607 fds[0].userData = null;
608
609 int res = android.system.Os.poll(fds, remainingSleepTime);
610 long endTime = System.nanoTime();
Andreas Gampe27497c62017-07-21 11:41:00 -0700611 int elapsedTimeMs = (int)((endTime - startTime) / 1000000l);
612 remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
Andreas Gampecbc42142017-07-12 19:17:52 -0700613
614 if (res > 0) {
615 if ((fds[0].revents & POLLIN) != 0) {
616 // Only read one byte, so as not to block.
617 int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1);
618 if (readBytes < 0) {
619 throw new RuntimeException("Some error");
620 }
621 dataIndex += readBytes;
622 } else {
623 // Error case. revents should contain one of the error bits.
624 break;
625 }
626 } else if (res == 0) {
627 Log.w(TAG, "Timed out waiting for child.");
628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 }
Andreas Gampecbc42142017-07-12 19:17:52 -0700630
631 if (dataIndex == data.length) {
632 DataInputStream is = new DataInputStream(new ByteArrayInputStream(data));
633 innerPid = is.readInt();
634 }
635
636 if (innerPid == -1) {
637 Log.w(TAG, "Error reading pid from wrapped process, child may have died");
638 }
639 } catch (Exception ex) {
640 Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 }
Jeff Brownebed7d62011-05-16 17:08:42 -0700642
643 // Ensure that the pid reported by the wrapped process is either the
644 // child process that we forked, or a descendant of it.
645 if (innerPid > 0) {
646 int parentPid = innerPid;
647 while (parentPid > 0 && parentPid != pid) {
648 parentPid = Process.getParentPid(parentPid);
649 }
650 if (parentPid > 0) {
651 Log.i(TAG, "Wrapped process has pid " + innerPid);
652 pid = innerPid;
Jeff Brown3f9dd282011-07-08 20:02:19 -0700653 usingWrapper = true;
Jeff Brownebed7d62011-05-16 17:08:42 -0700654 } else {
655 Log.w(TAG, "Wrapped process reported a pid that is not a child of "
656 + "the process that we forked: childPid=" + pid
657 + " innerPid=" + innerPid);
658 }
659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 }
661
662 try {
663 mSocketOutStream.writeInt(pid);
Jeff Brown3f9dd282011-07-08 20:02:19 -0700664 mSocketOutStream.writeBoolean(usingWrapper);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 } catch (IOException ex) {
Narayan Kamathbf99d062017-07-05 14:45:38 +0100666 throw new IllegalStateException("Error writing to command socket", ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 }
669
Jeff Brownebed7d62011-05-16 17:08:42 -0700670 private void setChildPgid(int pid) {
671 // Try to move the new child into the peer's process group.
672 try {
Elliott Hughes26b56e62014-12-17 12:28:29 -0800673 Os.setpgid(pid, Os.getpgid(peer.getPid()));
674 } catch (ErrnoException ex) {
Jeff Brownebed7d62011-05-16 17:08:42 -0700675 // This exception is expected in the case where
676 // the peer is not in our session
677 // TODO get rid of this log message in the case where
678 // getsid(0) != getsid(peer.getPid())
679 Log.i(TAG, "Zygote: setpgid failed. This is "
680 + "normal if peer is not in our session");
681 }
682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683}