blob: fdb44e7050e1f5b30f17f93d6df81fa95be016ba [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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 android.os;
Jeff Sharkey7407c942012-11-12 13:42:49 -080018
Elliott Hughes34385d32014-04-28 11:11:32 -070019import static android.system.OsConstants.AF_UNIX;
Nick Kralevich0c48b942018-12-17 14:24:22 -080020import static android.system.OsConstants.F_DUPFD;
21import static android.system.OsConstants.F_DUPFD_CLOEXEC;
22import static android.system.OsConstants.O_CLOEXEC;
Elliott Hughes34385d32014-04-28 11:11:32 -070023import static android.system.OsConstants.SEEK_SET;
Nick Kralevich0c48b942018-12-17 14:24:22 -080024import static android.system.OsConstants.SOCK_CLOEXEC;
Jeff Brown6fd9f9a2015-03-12 19:45:47 -070025import static android.system.OsConstants.SOCK_SEQPACKET;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -060026import static android.system.OsConstants.SOCK_STREAM;
27import static android.system.OsConstants.S_IROTH;
28import static android.system.OsConstants.S_IRWXG;
29import static android.system.OsConstants.S_IRWXU;
Elliott Hughes34385d32014-04-28 11:11:32 -070030import static android.system.OsConstants.S_ISLNK;
31import static android.system.OsConstants.S_ISREG;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -060032import static android.system.OsConstants.S_IWOTH;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070033
Jeff Sharkeycb269aac2019-01-25 11:15:38 -070034import android.annotation.TestApi;
Andrei Onea24ec3212019-03-15 17:35:05 +000035import android.annotation.UnsupportedAppUsage;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070036import android.content.BroadcastReceiver;
37import android.content.ContentProvider;
Jeff Sharkey588c15e2019-10-10 17:29:58 -060038import android.content.ContentResolver;
39import android.net.Uri;
Jeff Brown3f640522015-05-15 12:26:15 -070040import android.os.MessageQueue.OnFileDescriptorEventListener;
Elliott Hughes34385d32014-04-28 11:11:32 -070041import android.system.ErrnoException;
42import android.system.Os;
43import android.system.OsConstants;
44import android.system.StructStat;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070045import android.util.Log;
Jeff Sharkey588c15e2019-10-10 17:29:58 -060046import android.util.Size;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070047
Jeff Sharkey7407c942012-11-12 13:42:49 -080048import dalvik.system.CloseGuard;
Nick Kralevich0c48b942018-12-17 14:24:22 -080049import dalvik.system.VMRuntime;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -060050
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070051import libcore.io.IoUtils;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070052import libcore.io.Memory;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070053
Jeff Sharkeye861b422012-03-01 20:59:22 -080054import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.io.File;
56import java.io.FileDescriptor;
57import java.io.FileInputStream;
58import java.io.FileNotFoundException;
59import java.io.FileOutputStream;
60import java.io.IOException;
Neil Fuller43582df2014-04-11 17:29:54 +010061import java.io.InterruptedIOException;
Josh Gaoe3589b22018-09-28 10:59:16 -070062import java.io.UncheckedIOException;
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -070063import java.net.DatagramSocket;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import java.net.Socket;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070065import java.nio.ByteOrder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066
67/**
68 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
69 * you to close it when done with it.
70 */
Jeff Sharkeye861b422012-03-01 20:59:22 -080071public class ParcelFileDescriptor implements Parcelable, Closeable {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070072 private static final String TAG = "ParcelFileDescriptor";
73
74 private final FileDescriptor mFd;
75
76 /**
77 * Optional socket used to communicate close events, status at close, and
78 * detect remote process crashes.
79 */
80 private FileDescriptor mCommFd;
Jeff Sharkey7407c942012-11-12 13:42:49 -080081
82 /**
83 * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070084 * double-closing {@link #mFd}.
Hans Boehm339d4472019-05-30 15:48:17 -070085 * mClosed is always true if mWrapped is non-null.
Jeff Sharkey7407c942012-11-12 13:42:49 -080086 */
87 private final ParcelFileDescriptor mWrapped;
88
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070089 /**
90 * Maximum {@link #mStatusBuf} size; longer status messages will be
91 * truncated.
92 */
93 private static final int MAX_STATUS = 1024;
94
95 /**
96 * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
97 * allocated on-demand.
98 */
99 private byte[] mStatusBuf;
100
101 /**
Amith Yamasanib433bb82013-09-18 15:10:16 -0700102 * Status read by {@link #checkError()}, or null if not read yet.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700103 */
104 private Status mStatus;
105
Jeff Sharkey7407c942012-11-12 13:42:49 -0800106 private volatile boolean mClosed;
107
108 private final CloseGuard mGuard = CloseGuard.get();
Elliott Hughes43907582011-04-12 14:25:23 -0700109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700111 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
112 * this file doesn't already exist, then create the file with permissions
113 * such that any application can read it.
114 *
115 * @deprecated Creating world-readable files is very dangerous, and likely
116 * to cause security holes in applications. It is strongly
117 * discouraged; instead, applications should use more formal
118 * mechanism for interactions such as {@link ContentProvider},
119 * {@link BroadcastReceiver}, and {@link android.app.Service}.
120 * There are no guarantees that this access mode will remain on
121 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700123 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 public static final int MODE_WORLD_READABLE = 0x00000001;
Elliott Hughes43907582011-04-12 14:25:23 -0700125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700127 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
128 * this file doesn't already exist, then create the file with permissions
129 * such that any application can write it.
130 *
131 * @deprecated Creating world-writable files is very dangerous, and likely
132 * to cause security holes in applications. It is strongly
133 * discouraged; instead, applications should use more formal
134 * mechanism for interactions such as {@link ContentProvider},
135 * {@link BroadcastReceiver}, and {@link android.app.Service}.
136 * There are no guarantees that this access mode will remain on
137 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700139 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 public static final int MODE_WORLD_WRITEABLE = 0x00000002;
Elliott Hughes43907582011-04-12 14:25:23 -0700141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 /**
143 * For use with {@link #open}: open the file with read-only access.
144 */
145 public static final int MODE_READ_ONLY = 0x10000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 /**
148 * For use with {@link #open}: open the file with write-only access.
149 */
150 public static final int MODE_WRITE_ONLY = 0x20000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 /**
153 * For use with {@link #open}: open the file with read and write access.
154 */
155 public static final int MODE_READ_WRITE = 0x30000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 /**
158 * For use with {@link #open}: create the file if it doesn't already exist.
159 */
160 public static final int MODE_CREATE = 0x08000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 /**
163 * For use with {@link #open}: erase contents of file when opening.
164 */
165 public static final int MODE_TRUNCATE = 0x04000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 /**
168 * For use with {@link #open}: append to end of file while writing.
169 */
170 public static final int MODE_APPEND = 0x02000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700173 * Create a new ParcelFileDescriptor wrapped around another descriptor. By
174 * default all method calls are delegated to the wrapped descriptor.
175 */
176 public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
177 // We keep a strong reference to the wrapped PFD, and rely on its
178 // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
179 mWrapped = wrapped;
180 mFd = null;
181 mCommFd = null;
182 mClosed = true;
183 }
184
185 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000186 @UnsupportedAppUsage
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700187 public ParcelFileDescriptor(FileDescriptor fd) {
188 this(fd, null);
189 }
190
191 /** {@hide} */
192 public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
193 if (fd == null) {
194 throw new NullPointerException("FileDescriptor must not be null");
195 }
196 mWrapped = null;
197 mFd = fd;
Josh Gao5ada8732018-06-26 14:20:29 -0700198 IoUtils.setFdOwner(mFd, this);
199
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700200 mCommFd = commChannel;
Josh Gao5ada8732018-06-26 14:20:29 -0700201 if (mCommFd != null) {
202 IoUtils.setFdOwner(mCommFd, this);
203 }
204
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700205 mGuard.open("close");
206 }
207
208 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 * Create a new ParcelFileDescriptor accessing a given file.
Jeff Sharkey588c15e2019-10-10 17:29:58 -0600210 * <p>
211 * This method should only be used for files that you have direct access to;
212 * if you'd like to work with files hosted outside your app, use an API like
213 * {@link ContentResolver#openFile(Uri, String, CancellationSignal)}.
Elliott Hughes43907582011-04-12 14:25:23 -0700214 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 * @param file The file to be opened.
216 * @param mode The desired access mode, must be one of
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700217 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
218 * {@link #MODE_READ_WRITE}; may also be any combination of
219 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
220 * {@link #MODE_WORLD_READABLE}, and
221 * {@link #MODE_WORLD_WRITEABLE}.
222 * @return a new ParcelFileDescriptor pointing to the given file.
223 * @throws FileNotFoundException if the given file does not exist or can not
224 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700225 * @see #parseMode(String)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700227 public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
228 final FileDescriptor fd = openInternal(file, mode);
229 if (fd == null) return null;
Elliott Hughes43907582011-04-12 14:25:23 -0700230
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700231 return new ParcelFileDescriptor(fd);
232 }
233
234 /**
235 * Create a new ParcelFileDescriptor accessing a given file.
Jeff Sharkey588c15e2019-10-10 17:29:58 -0600236 * <p>
237 * This method should only be used for files that you have direct access to;
238 * if you'd like to work with files hosted outside your app, use an API like
239 * {@link ContentResolver#openFile(Uri, String, CancellationSignal)}.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700240 *
241 * @param file The file to be opened.
242 * @param mode The desired access mode, must be one of
243 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
244 * {@link #MODE_READ_WRITE}; may also be any combination of
245 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
246 * {@link #MODE_WORLD_READABLE}, and
247 * {@link #MODE_WORLD_WRITEABLE}.
248 * @param handler to call listener from; must not be null.
249 * @param listener to be invoked when the returned descriptor has been
250 * closed; must not be null.
251 * @return a new ParcelFileDescriptor pointing to the given file.
252 * @throws FileNotFoundException if the given file does not exist or can not
253 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700254 * @see #parseMode(String)
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700255 */
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700256 public static ParcelFileDescriptor open(File file, int mode, Handler handler,
257 final OnCloseListener listener) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700258 if (handler == null) {
259 throw new IllegalArgumentException("Handler must not be null");
260 }
261 if (listener == null) {
262 throw new IllegalArgumentException("Listener must not be null");
263 }
264
265 final FileDescriptor fd = openInternal(file, mode);
266 if (fd == null) return null;
267
Daichi Hirono91e3b502015-12-16 09:24:16 +0900268 return fromFd(fd, handler, listener);
269 }
270
271 /** {@hide} */
Jeff Sharkeycb394992018-12-01 18:26:43 -0700272 public static ParcelFileDescriptor fromPfd(ParcelFileDescriptor pfd, Handler handler,
273 final OnCloseListener listener) throws IOException {
274 final FileDescriptor original = new FileDescriptor();
275 original.setInt$(pfd.detachFd());
276 return fromFd(original, handler, listener);
277 }
278
279 /** {@hide} */
280 public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler,
281 final OnCloseListener listener) throws IOException {
Daichi Hirono91e3b502015-12-16 09:24:16 +0900282 if (handler == null) {
283 throw new IllegalArgumentException("Handler must not be null");
284 }
285 if (listener == null) {
286 throw new IllegalArgumentException("Listener must not be null");
287 }
288
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700289 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700290 final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
Jeff Brownb2a19852015-03-12 19:49:25 -0700291 final MessageQueue queue = handler.getLooper().getQueue();
Jeff Brown3f640522015-05-15 12:26:15 -0700292 queue.addOnFileDescriptorEventListener(comm[1],
293 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700294 @Override
295 public int onFileDescriptorEvents(FileDescriptor fd, int events) {
296 Status status = null;
Jeff Brown3f640522015-05-15 12:26:15 -0700297 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700298 final byte[] buf = new byte[MAX_STATUS];
299 status = readCommStatus(fd, buf);
Jeff Brown3f640522015-05-15 12:26:15 -0700300 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700301 status = new Status(Status.DEAD);
302 }
303 if (status != null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700304 queue.removeOnFileDescriptorEventListener(fd);
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700305 IoUtils.closeQuietly(fd);
306 listener.onClose(status.asIOException());
Jeff Brownb2a19852015-03-12 19:49:25 -0700307 return 0;
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700308 }
309 return EVENT_INPUT;
310 }
311 });
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700312
313 return pfd;
314 }
315
316 private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800317 final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC);
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600318
319 int realMode = S_IRWXU | S_IRWXG;
320 if ((mode & MODE_WORLD_READABLE) != 0) realMode |= S_IROTH;
321 if ((mode & MODE_WORLD_WRITEABLE) != 0) realMode |= S_IWOTH;
322
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700323 final String path = file.getPath();
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600324 try {
325 return Os.open(path, flags, realMode);
326 } catch (ErrnoException e) {
327 throw new FileNotFoundException(e.getMessage());
328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 }
330
331 /**
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700332 * Create a new ParcelFileDescriptor that is a dup of an existing
333 * FileDescriptor. This obeys standard POSIX semantics, where the
334 * new file descriptor shared state such as file position with the
335 * original file descriptor.
336 */
337 public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700338 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800339 final FileDescriptor fd = new FileDescriptor();
340 int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
341 fd.setInt$(intfd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700342 return new ParcelFileDescriptor(fd);
343 } catch (ErrnoException e) {
344 throw e.rethrowAsIOException();
345 }
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700346 }
347
348 /**
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700349 * Create a new ParcelFileDescriptor that is a dup of the existing
350 * FileDescriptor. This obeys standard POSIX semantics, where the
351 * new file descriptor shared state such as file position with the
352 * original file descriptor.
353 */
354 public ParcelFileDescriptor dup() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700355 if (mWrapped != null) {
356 return mWrapped.dup();
357 } else {
358 return dup(getFileDescriptor());
359 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700360 }
361
362 /**
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700363 * Create a new ParcelFileDescriptor from a raw native fd. The new
364 * ParcelFileDescriptor holds a dup of the original fd passed in here,
365 * so you must still close that fd as well as the new ParcelFileDescriptor.
366 *
367 * @param fd The native fd that the ParcelFileDescriptor should dup.
368 *
369 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
370 * for a dup of the given fd.
371 */
372 public static ParcelFileDescriptor fromFd(int fd) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700373 final FileDescriptor original = new FileDescriptor();
374 original.setInt$(fd);
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700375
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700376 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800377 final FileDescriptor dup = new FileDescriptor();
378 int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
379 dup.setInt$(intfd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700380 return new ParcelFileDescriptor(dup);
381 } catch (ErrnoException e) {
382 throw e.rethrowAsIOException();
383 }
384 }
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700385
386 /**
387 * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
388 * The returned ParcelFileDescriptor now owns the given fd, and will be
Josh Gao4a646632019-03-08 11:22:21 -0800389 * responsible for closing it.
390 * <p>
391 * <strong>WARNING:</strong> You must not close the fd yourself after
392 * this call, and ownership of the file descriptor must have been
393 * released prior to the call to this function.
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700394 *
395 * @param fd The native fd that the ParcelFileDescriptor should adopt.
396 *
397 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
398 * for the given fd.
399 */
400 public static ParcelFileDescriptor adoptFd(int fd) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700401 final FileDescriptor fdesc = new FileDescriptor();
402 fdesc.setInt$(fd);
403
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700404 return new ParcelFileDescriptor(fdesc);
405 }
406
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700407 /**
408 * Create a new ParcelFileDescriptor from the specified Socket. The new
409 * ParcelFileDescriptor holds a dup of the original FileDescriptor in
410 * the Socket, so you must still close the Socket as well as the new
411 * ParcelFileDescriptor.
Josh Gao4a646632019-03-08 11:22:21 -0800412 * <p>
413 * <strong>WARNING:</strong> Prior to API level 29, this function would not
414 * actually dup the Socket's FileDescriptor, and would take a
415 * reference to the its internal FileDescriptor instead. If the Socket
416 * gets garbage collected before the ParcelFileDescriptor, this may
417 * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
418 * this, the following pattern can be used:
419 * <pre>{@code
420 * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket).dup();
421 * }</pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 *
423 * @param socket The Socket whose FileDescriptor is used to create
424 * a new ParcelFileDescriptor.
425 *
Josh Gaoe3589b22018-09-28 10:59:16 -0700426 * @return A new ParcelFileDescriptor with a duped copy of the
427 * FileDescriptor of the specified Socket.
428 *
429 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 */
431 public static ParcelFileDescriptor fromSocket(Socket socket) {
Elliott Hughes43907582011-04-12 14:25:23 -0700432 FileDescriptor fd = socket.getFileDescriptor$();
Josh Gaoe3589b22018-09-28 10:59:16 -0700433 try {
434 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
435 } catch (IOException e) {
436 throw new UncheckedIOException(e);
437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 }
439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 /**
Josh Gaoe3589b22018-09-28 10:59:16 -0700441 * Create a new ParcelFileDescriptor from the specified DatagramSocket. The
442 * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
443 * the DatagramSocket, so you must still close the DatagramSocket as well
444 * as the new ParcelFileDescriptor.
Josh Gao4a646632019-03-08 11:22:21 -0800445 * <p>
446 * <strong>WARNING:</strong> Prior to API level 29, this function would not
447 * actually dup the DatagramSocket's FileDescriptor, and would take a
448 * reference to the its internal FileDescriptor instead. If the DatagramSocket
449 * gets garbage collected before the ParcelFileDescriptor, this may
450 * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
451 * this, the following pattern can be used:
452 * <pre>{@code
453 * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket).dup();
454 * }</pre>
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700455 *
456 * @param datagramSocket The DatagramSocket whose FileDescriptor is used
457 * to create a new ParcelFileDescriptor.
458 *
Josh Gaoe3589b22018-09-28 10:59:16 -0700459 * @return A new ParcelFileDescriptor with a duped copy of the
460 * FileDescriptor of the specified Socket.
461 *
462 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700463 */
464 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
465 FileDescriptor fd = datagramSocket.getFileDescriptor$();
Josh Gaoe3589b22018-09-28 10:59:16 -0700466 try {
467 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
468 } catch (IOException e) {
469 throw new UncheckedIOException(e);
470 }
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700471 }
472
473 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700474 * Create two ParcelFileDescriptors structured as a data pipe. The first
475 * ParcelFileDescriptor in the returned array is the read side; the second
476 * is the write side.
477 */
478 public static ParcelFileDescriptor[] createPipe() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700479 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800480 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700481 return new ParcelFileDescriptor[] {
482 new ParcelFileDescriptor(fds[0]),
483 new ParcelFileDescriptor(fds[1]) };
484 } catch (ErrnoException e) {
485 throw e.rethrowAsIOException();
486 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700487 }
488
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700489 /**
490 * Create two ParcelFileDescriptors structured as a data pipe. The first
491 * ParcelFileDescriptor in the returned array is the read side; the second
492 * is the write side.
493 * <p>
494 * The write end has the ability to deliver an error message through
495 * {@link #closeWithError(String)} which can be handled by the read end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700496 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700497 * This can also be used to detect remote crashes.
498 */
499 public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
500 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700501 final FileDescriptor[] comm = createCommSocketPair();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800502 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700503 return new ParcelFileDescriptor[] {
504 new ParcelFileDescriptor(fds[0], comm[0]),
505 new ParcelFileDescriptor(fds[1], comm[1]) };
506 } catch (ErrnoException e) {
507 throw e.rethrowAsIOException();
508 }
509 }
510
511 /**
512 * Create two ParcelFileDescriptors structured as a pair of sockets
513 * connected to each other. The two sockets are indistinguishable.
514 */
515 public static ParcelFileDescriptor[] createSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800516 return createSocketPair(SOCK_STREAM);
517 }
518
519 /**
520 * @hide
521 */
522 public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700523 try {
524 final FileDescriptor fd0 = new FileDescriptor();
525 final FileDescriptor fd1 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800526 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700527 return new ParcelFileDescriptor[] {
528 new ParcelFileDescriptor(fd0),
529 new ParcelFileDescriptor(fd1) };
530 } catch (ErrnoException e) {
531 throw e.rethrowAsIOException();
532 }
533 }
534
535 /**
536 * Create two ParcelFileDescriptors structured as a pair of sockets
537 * connected to each other. The two sockets are indistinguishable.
538 * <p>
539 * Both ends have the ability to deliver an error message through
540 * {@link #closeWithError(String)} which can be detected by the other end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700541 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700542 * This can also be used to detect remote crashes.
543 */
544 public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800545 return createReliableSocketPair(SOCK_STREAM);
546 }
547
548 /**
549 * @hide
550 */
551 public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700552 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700553 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700554 final FileDescriptor fd0 = new FileDescriptor();
555 final FileDescriptor fd1 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800556 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700557 return new ParcelFileDescriptor[] {
558 new ParcelFileDescriptor(fd0, comm[0]),
559 new ParcelFileDescriptor(fd1, comm[1]) };
560 } catch (ErrnoException e) {
561 throw e.rethrowAsIOException();
562 }
563 }
564
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700565 private static FileDescriptor[] createCommSocketPair() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700566 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700567 // Use SOCK_SEQPACKET so that we have a guarantee that the status
568 // is written and read atomically as one unit and is not split
569 // across multiple IO operations.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700570 final FileDescriptor comm1 = new FileDescriptor();
571 final FileDescriptor comm2 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800572 Os.socketpair(AF_UNIX, SOCK_SEQPACKET | ifAtLeastQ(SOCK_CLOEXEC), 0, comm1, comm2);
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700573 IoUtils.setBlocking(comm1, false);
574 IoUtils.setBlocking(comm2, false);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700575 return new FileDescriptor[] { comm1, comm2 };
576 } catch (ErrnoException e) {
577 throw e.rethrowAsIOException();
578 }
579 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700580
581 /**
Dianne Hackborn540f86a2011-01-11 17:52:22 -0800582 * @hide Please use createPipe() or ContentProvider.openPipeHelper().
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100583 * Gets a file descriptor for a read-only copy of the given data.
584 *
585 * @param data Data to copy.
586 * @param name Name for the shared memory area that may back the file descriptor.
587 * This is purely informative and may be {@code null}.
588 * @return A ParcelFileDescriptor.
589 * @throws IOException if there is an error while creating the shared memory area.
590 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000591 @UnsupportedAppUsage
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800592 @Deprecated
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100593 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
594 if (data == null) return null;
595 MemoryFile file = new MemoryFile(name, data.length);
John Reck12ea937f2019-07-26 12:19:56 -0700596 try {
597 if (data.length > 0) {
598 file.writeBytes(data, 0, 0, data.length);
599 }
600 file.deactivate();
601 FileDescriptor fd = file.getFileDescriptor();
602 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
603 } finally {
604 file.close();
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100605 }
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100606 }
607
608 /**
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700609 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
610 * with {@link #open}.
611 * <p>
Garfield Tanaf03e5a2017-05-15 14:19:11 -0700612 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw"
613 * or "rwt".
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700614 * @return A bitmask representing the given file mode.
615 * @throws IllegalArgumentException if the given string does not match a known file mode.
616 */
617 public static int parseMode(String mode) {
Jeff Sharkey63280e02018-09-12 11:47:07 -0600618 return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700619 }
620
621 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700622 * Return the filesystem path of the real file on disk that is represented
623 * by the given {@link FileDescriptor}.
624 *
625 * @hide
626 */
Jeff Sharkeycb269aac2019-01-25 11:15:38 -0700627 @TestApi
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700628 public static File getFile(FileDescriptor fd) throws IOException {
629 try {
630 final String path = Os.readlink("/proc/self/fd/" + fd.getInt$());
Zim42f1e9f2019-08-15 17:35:00 +0100631 if (OsConstants.S_ISREG(Os.stat(path).st_mode)
632 || OsConstants.S_ISCHR(Os.stat(path).st_mode)) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700633 return new File(path);
634 } else {
Zim42f1e9f2019-08-15 17:35:00 +0100635 throw new IOException("Not a regular file or character device: " + path);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700636 }
637 } catch (ErrnoException e) {
638 throw e.rethrowAsIOException();
639 }
640 }
641
642 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 * Retrieve the actual FileDescriptor associated with this object.
Elliott Hughes43907582011-04-12 14:25:23 -0700644 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 * @return Returns the FileDescriptor associated with this object.
646 */
647 public FileDescriptor getFileDescriptor() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700648 if (mWrapped != null) {
649 return mWrapped.getFileDescriptor();
650 } else {
651 return mFd;
652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
Elliott Hughes43907582011-04-12 14:25:23 -0700654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700656 * Return the total size of the file representing this fd, as determined by
657 * {@code stat()}. Returns -1 if the fd is not a file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700659 public long getStatSize() {
660 if (mWrapped != null) {
661 return mWrapped.getStatSize();
662 } else {
663 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700664 final StructStat st = Os.fstat(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700665 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
666 return st.st_size;
667 } else {
668 return -1;
669 }
670 } catch (ErrnoException e) {
671 Log.w(TAG, "fstat() failed: " + e);
672 return -1;
673 }
674 }
675 }
Elliott Hughes43907582011-04-12 14:25:23 -0700676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 /**
678 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
679 * and I really don't think we want it to be public.
680 * @hide
681 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000682 @UnsupportedAppUsage
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700683 public long seekTo(long pos) throws IOException {
684 if (mWrapped != null) {
685 return mWrapped.seekTo(pos);
686 } else {
687 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700688 return Os.lseek(mFd, pos, SEEK_SET);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700689 } catch (ErrnoException e) {
690 throw e.rethrowAsIOException();
691 }
692 }
693 }
Elliott Hughes43907582011-04-12 14:25:23 -0700694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 /**
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800696 * Return the native fd int for this ParcelFileDescriptor. The
697 * ParcelFileDescriptor still owns the fd, and it still must be closed
698 * through this API.
Josh Gao4a646632019-03-08 11:22:21 -0800699 * <p>
700 * <strong>WARNING:</strong> Do not call close on the return value of this
701 * function or pass it to a function that assumes ownership of the fd.
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800702 */
703 public int getFd() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700704 if (mWrapped != null) {
705 return mWrapped.getFd();
706 } else {
707 if (mClosed) {
708 throw new IllegalStateException("Already closed");
709 }
710 return mFd.getInt$();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800711 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800712 }
Elliott Hughes43907582011-04-12 14:25:23 -0700713
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800714 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700715 * Return the native fd int for this ParcelFileDescriptor and detach it from
716 * the object here. You are now responsible for closing the fd in native
717 * code.
718 * <p>
719 * You should not detach when the original creator of the descriptor is
720 * expecting a reliable signal through {@link #close()} or
721 * {@link #closeWithError(String)}.
722 *
723 * @see #canDetectErrors()
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800724 */
725 public int detachFd() {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800726 if (mWrapped != null) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700727 return mWrapped.detachFd();
728 } else {
729 if (mClosed) {
730 throw new IllegalStateException("Already closed");
731 }
Josh Gao5ada8732018-06-26 14:20:29 -0700732 int fd = IoUtils.acquireRawFd(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700733 writeCommStatusAndClose(Status.DETACHED, null);
Makoto Onukib30ad6f2015-06-11 12:34:22 -0700734 mClosed = true;
735 mGuard.close();
736 releaseResources();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800737 return fd;
738 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800739 }
Elliott Hughes43907582011-04-12 14:25:23 -0700740
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800741 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 * Close the ParcelFileDescriptor. This implementation closes the underlying
743 * OS resources allocated to represent this stream.
Elliott Hughes43907582011-04-12 14:25:23 -0700744 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 * @throws IOException
746 * If an error occurs attempting to close this ParcelFileDescriptor.
747 */
Jeff Sharkey7407c942012-11-12 13:42:49 -0800748 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 public void close() throws IOException {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800750 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700751 try {
752 mWrapped.close();
753 } finally {
754 releaseResources();
755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700757 closeWithStatus(Status.OK, null);
758 }
759 }
760
761 /**
762 * Close the ParcelFileDescriptor, informing any peer that an error occurred
763 * while processing. If the creator of this descriptor is not observing
764 * errors, it will close normally.
765 *
766 * @param msg describing the error; must not be null.
767 */
768 public void closeWithError(String msg) throws IOException {
769 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700770 try {
771 mWrapped.closeWithError(msg);
772 } finally {
773 releaseResources();
774 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700775 } else {
776 if (msg == null) {
777 throw new IllegalArgumentException("Message must not be null");
778 }
779 closeWithStatus(Status.ERROR, msg);
780 }
781 }
782
Amith Yamasani487c11a2013-09-18 09:16:15 -0700783 private void closeWithStatus(int status, String msg) {
784 if (mClosed) return;
785 mClosed = true;
Andreas Gampe009b8522017-10-10 08:01:38 -0700786 if (mGuard != null) {
787 mGuard.close();
788 }
Amith Yamasani487c11a2013-09-18 09:16:15 -0700789 // Status MUST be sent before closing actual descriptor
790 writeCommStatusAndClose(status, msg);
791 IoUtils.closeQuietly(mFd);
792 releaseResources();
793 }
794
795 /**
796 * Called when the fd is being closed, for subclasses to release any other resources
797 * associated with it, such as acquired providers.
798 * @hide
799 */
800 public void releaseResources() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700801 }
802
803 private byte[] getOrCreateStatusBuffer() {
804 if (mStatusBuf == null) {
805 mStatusBuf = new byte[MAX_STATUS];
806 }
807 return mStatusBuf;
808 }
809
810 private void writeCommStatusAndClose(int status, String msg) {
811 if (mCommFd == null) {
812 // Not reliable, or someone already sent status
813 if (msg != null) {
814 Log.w(TAG, "Unable to inform peer: " + msg);
815 }
816 return;
817 }
818
819 if (status == Status.DETACHED) {
820 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
821 }
822
823 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700824 if (status == Status.SILENCE) return;
825
826 // Since we're about to close, read off any remote status. It's
827 // okay to remember missing here.
828 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
829
830 // Skip writing status when other end has already gone away.
831 if (mStatus != null) return;
832
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700833 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700834 final byte[] buf = getOrCreateStatusBuffer();
835 int writePtr = 0;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700836
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700837 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
838 writePtr += 4;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700839
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700840 if (msg != null) {
841 final byte[] rawMsg = msg.getBytes();
842 final int len = Math.min(rawMsg.length, buf.length - writePtr);
843 System.arraycopy(rawMsg, 0, buf, writePtr, len);
844 writePtr += len;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700845 }
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700846
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700847 // Must write the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700848 Os.write(mCommFd, buf, 0, writePtr);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700849 } catch (ErrnoException e) {
850 // Reporting status is best-effort
851 Log.w(TAG, "Failed to report status: " + e);
Neil Fuller43582df2014-04-11 17:29:54 +0100852 } catch (InterruptedIOException e) {
853 // Reporting status is best-effort
854 Log.w(TAG, "Failed to report status: " + e);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700855 }
856
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700857 } finally {
858 IoUtils.closeQuietly(mCommFd);
859 mCommFd = null;
860 }
861 }
862
863 private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
864 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700865 // Must read the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700866 final int n = Os.read(comm, buf, 0, buf.length);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700867 if (n == 0) {
868 // EOF means they're dead
869 return new Status(Status.DEAD);
870 } else {
871 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
872 if (status == Status.ERROR) {
873 final String msg = new String(buf, 4, n - 4);
874 return new Status(status, msg);
875 }
876 return new Status(status);
877 }
878 } catch (ErrnoException e) {
879 if (e.errno == OsConstants.EAGAIN) {
880 // Remote is still alive, but no status written yet
881 return null;
882 } else {
883 Log.d(TAG, "Failed to read status; assuming dead: " + e);
884 return new Status(Status.DEAD);
885 }
Neil Fuller43582df2014-04-11 17:29:54 +0100886 } catch (InterruptedIOException e) {
887 Log.d(TAG, "Failed to read status; assuming dead: " + e);
888 return new Status(Status.DEAD);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700889 }
890 }
891
892 /**
893 * Indicates if this ParcelFileDescriptor can communicate and detect remote
894 * errors/crashes.
895 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700896 * @see #checkError()
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700897 */
898 public boolean canDetectErrors() {
899 if (mWrapped != null) {
900 return mWrapped.canDetectErrors();
901 } else {
902 return mCommFd != null;
903 }
904 }
905
906 /**
907 * Detect and throw if the other end of a pipe or socket pair encountered an
908 * error or crashed. This allows a reader to distinguish between a valid EOF
909 * and an error/crash.
910 * <p>
911 * If this ParcelFileDescriptor is unable to detect remote errors, it will
912 * return silently.
913 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700914 * @throws IOException for normal errors.
915 * @throws FileDescriptorDetachedException
916 * if the remote side called {@link #detachFd()}. Once detached, the remote
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700917 * side is unable to communicate any errors through
Amith Yamasanib433bb82013-09-18 15:10:16 -0700918 * {@link #closeWithError(String)}.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700919 * @see #canDetectErrors()
920 */
Amith Yamasanib433bb82013-09-18 15:10:16 -0700921 public void checkError() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700922 if (mWrapped != null) {
Amith Yamasanib433bb82013-09-18 15:10:16 -0700923 mWrapped.checkError();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700924 } else {
925 if (mStatus == null) {
926 if (mCommFd == null) {
927 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
928 return;
929 }
930
931 // Try reading status; it might be null if nothing written yet.
932 // Either way, we keep comm open to write our status later.
933 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
934 }
935
Amith Yamasanib433bb82013-09-18 15:10:16 -0700936 if (mStatus == null || mStatus.status == Status.OK) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700937 // No status yet, or everything is peachy!
938 return;
939 } else {
940 throw mStatus.asIOException();
941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 }
943 }
Elliott Hughes43907582011-04-12 14:25:23 -0700944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 /**
946 * An InputStream you can create on a ParcelFileDescriptor, which will
947 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700948 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 */
950 public static class AutoCloseInputStream extends FileInputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700951 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700952
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700953 public AutoCloseInputStream(ParcelFileDescriptor pfd) {
954 super(pfd.getFileDescriptor());
955 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
957
958 @Override
959 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700960 try {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700961 super.close();
Josh Gao401fb242018-11-09 13:40:53 -0800962 } finally {
963 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700964 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 }
Tomasz Mikolajewskiad3b6162016-05-30 10:17:08 +0900966
967 @Override
968 public int read() throws IOException {
969 final int result = super.read();
970 if (result == -1 && mPfd.canDetectErrors()) {
971 // Check for errors only on EOF, to minimize overhead.
972 mPfd.checkError();
973 }
974 return result;
975 }
976
977 @Override
978 public int read(byte[] b) throws IOException {
979 final int result = super.read(b);
980 if (result == -1 && mPfd.canDetectErrors()) {
981 mPfd.checkError();
982 }
983 return result;
984 }
985
986 @Override
987 public int read(byte[] b, int off, int len) throws IOException {
988 final int result = super.read(b, off, len);
989 if (result == -1 && mPfd.canDetectErrors()) {
990 mPfd.checkError();
991 }
992 return result;
993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 }
Elliott Hughes43907582011-04-12 14:25:23 -0700995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 /**
997 * An OutputStream you can create on a ParcelFileDescriptor, which will
998 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700999 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 */
1001 public static class AutoCloseOutputStream extends FileOutputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001002 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -07001003
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001004 public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
1005 super(pfd.getFileDescriptor());
1006 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
1008
1009 @Override
1010 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -07001011 try {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -07001012 super.close();
Josh Gao401fb242018-11-09 13:40:53 -08001013 } finally {
1014 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -07001015 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 }
1017 }
Elliott Hughes43907582011-04-12 14:25:23 -07001018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 @Override
1020 public String toString() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001021 if (mWrapped != null) {
1022 return mWrapped.toString();
1023 } else {
1024 return "{ParcelFileDescriptor: " + mFd + "}";
1025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
Elliott Hughes43907582011-04-12 14:25:23 -07001027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 @Override
1029 protected void finalize() throws Throwable {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001030 if (mWrapped != null) {
1031 releaseResources();
1032 }
Jeff Sharkey7407c942012-11-12 13:42:49 -08001033 if (mGuard != null) {
1034 mGuard.warnIfOpen();
1035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 try {
1037 if (!mClosed) {
Hans Boehm339d4472019-05-30 15:48:17 -07001038 // mWrapped was and is null.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001039 closeWithStatus(Status.LEAKED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 }
1041 } finally {
1042 super.finalize();
1043 }
1044 }
Elliott Hughes43907582011-04-12 14:25:23 -07001045
Jeff Sharkey7407c942012-11-12 13:42:49 -08001046 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 public int describeContents() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001048 if (mWrapped != null) {
1049 return mWrapped.describeContents();
1050 } else {
1051 return Parcelable.CONTENTS_FILE_DESCRIPTOR;
1052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 }
1054
Dan Egnorb3e4ef32010-07-20 09:03:35 -07001055 /**
1056 * {@inheritDoc}
1057 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
1058 * the file descriptor will be closed after a copy is written to the Parcel.
1059 */
Jeff Sharkey7407c942012-11-12 13:42:49 -08001060 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 public void writeToParcel(Parcel out, int flags) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001062 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001063 try {
1064 mWrapped.writeToParcel(out, flags);
1065 } finally {
1066 releaseResources();
1067 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001068 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001069 if (mCommFd != null) {
1070 out.writeInt(1);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001071 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001072 out.writeFileDescriptor(mCommFd);
1073 } else {
1074 out.writeInt(0);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001075 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001076 }
1077 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001078 // Not a real close, so emit no status
1079 closeWithStatus(Status.SILENCE, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 }
1081 }
1082 }
1083
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001084 public static final @android.annotation.NonNull Parcelable.Creator<ParcelFileDescriptor> CREATOR
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 = new Parcelable.Creator<ParcelFileDescriptor>() {
Jeff Sharkey7407c942012-11-12 13:42:49 -08001086 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 public ParcelFileDescriptor createFromParcel(Parcel in) {
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001088 int hasCommChannel = in.readInt();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001089 final FileDescriptor fd = in.readRawFileDescriptor();
1090 FileDescriptor commChannel = null;
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001091 if (hasCommChannel != 0) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001092 commChannel = in.readRawFileDescriptor();
1093 }
1094 return new ParcelFileDescriptor(fd, commChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 }
Jeff Sharkey7407c942012-11-12 13:42:49 -08001096
1097 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 public ParcelFileDescriptor[] newArray(int size) {
1099 return new ParcelFileDescriptor[size];
1100 }
1101 };
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001102
1103 /**
1104 * Callback indicating that a ParcelFileDescriptor has been closed.
1105 */
1106 public interface OnCloseListener {
1107 /**
1108 * Event indicating the ParcelFileDescriptor to which this listener was
1109 * attached has been closed.
1110 *
1111 * @param e error state, or {@code null} if closed cleanly.
Amith Yamasanib433bb82013-09-18 15:10:16 -07001112 * If the close event was the result of
1113 * {@link ParcelFileDescriptor#detachFd()}, this will be a
1114 * {@link FileDescriptorDetachedException}. After detach the
1115 * remote side may continue reading/writing to the underlying
1116 * {@link FileDescriptor}, but they can no longer deliver
1117 * reliable close/error events.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001118 */
Amith Yamasanib433bb82013-09-18 15:10:16 -07001119 public void onClose(IOException e);
1120 }
1121
1122 /**
1123 * Exception that indicates that the file descriptor was detached.
1124 */
1125 public static class FileDescriptorDetachedException extends IOException {
1126
1127 private static final long serialVersionUID = 0xDe7ac4edFdL;
1128
1129 public FileDescriptorDetachedException() {
1130 super("Remote side is detached");
1131 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001132 }
1133
1134 /**
1135 * Internal class representing a remote status read by
1136 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
Steven Moreland3de571e2018-11-12 19:44:23 -08001137 *
1138 * Warning: this must be kept in sync with ParcelFileDescriptorStatus at
1139 * frameworks/native/libs/binder/Parcel.cpp
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001140 */
1141 private static class Status {
1142 /** Special value indicating remote side died. */
1143 public static final int DEAD = -2;
1144 /** Special value indicating no status should be written. */
1145 public static final int SILENCE = -1;
1146
1147 /** Remote reported that everything went better than expected. */
1148 public static final int OK = 0;
1149 /** Remote reported error; length and message follow. */
1150 public static final int ERROR = 1;
1151 /** Remote reported {@link #detachFd()} and went rogue. */
1152 public static final int DETACHED = 2;
1153 /** Remote reported their object was finalized. */
1154 public static final int LEAKED = 3;
1155
1156 public final int status;
1157 public final String msg;
1158
1159 public Status(int status) {
1160 this(status, null);
1161 }
1162
1163 public Status(int status, String msg) {
1164 this.status = status;
1165 this.msg = msg;
1166 }
1167
1168 public IOException asIOException() {
1169 switch (status) {
1170 case DEAD:
1171 return new IOException("Remote side is dead");
1172 case OK:
1173 return null;
1174 case ERROR:
1175 return new IOException("Remote error: " + msg);
1176 case DETACHED:
Amith Yamasanib433bb82013-09-18 15:10:16 -07001177 return new FileDescriptorDetachedException();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001178 case LEAKED:
1179 return new IOException("Remote side was leaked");
1180 default:
1181 return new IOException("Unknown status: " + status);
1182 }
1183 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001184
1185 @Override
Jeff Brown6fd9f9a2015-03-12 19:45:47 -07001186 public String toString() {
1187 return "{" + status + ": " + msg + "}";
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001188 }
1189 }
Nick Kralevich0c48b942018-12-17 14:24:22 -08001190
1191 private static boolean isAtLeastQ() {
1192 return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q);
1193 }
1194
1195 private static int ifAtLeastQ(int value) {
1196 return isAtLeastQ() ? value : 0;
1197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198}