blob: d68eeeda2eb9d2ef5af12e9579372932e94a7233 [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;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070035import android.content.BroadcastReceiver;
36import android.content.ContentProvider;
Jeff Brown3f640522015-05-15 12:26:15 -070037import android.os.MessageQueue.OnFileDescriptorEventListener;
Elliott Hughes34385d32014-04-28 11:11:32 -070038import android.system.ErrnoException;
39import android.system.Os;
40import android.system.OsConstants;
41import android.system.StructStat;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070042import android.util.Log;
43
Jeff Sharkey7407c942012-11-12 13:42:49 -080044import dalvik.system.CloseGuard;
Nick Kralevich0c48b942018-12-17 14:24:22 -080045import dalvik.system.VMRuntime;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -060046
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070047import libcore.io.IoUtils;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070048import libcore.io.Memory;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070049
Jeff Sharkeye861b422012-03-01 20:59:22 -080050import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.io.File;
52import java.io.FileDescriptor;
53import java.io.FileInputStream;
54import java.io.FileNotFoundException;
55import java.io.FileOutputStream;
56import java.io.IOException;
Neil Fuller43582df2014-04-11 17:29:54 +010057import java.io.InterruptedIOException;
Josh Gaoe3589b22018-09-28 10:59:16 -070058import java.io.UncheckedIOException;
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -070059import java.net.DatagramSocket;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import java.net.Socket;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070061import java.nio.ByteOrder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63/**
64 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
65 * you to close it when done with it.
66 */
Jeff Sharkeye861b422012-03-01 20:59:22 -080067public class ParcelFileDescriptor implements Parcelable, Closeable {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070068 private static final String TAG = "ParcelFileDescriptor";
69
70 private final FileDescriptor mFd;
71
72 /**
73 * Optional socket used to communicate close events, status at close, and
74 * detect remote process crashes.
75 */
76 private FileDescriptor mCommFd;
Jeff Sharkey7407c942012-11-12 13:42:49 -080077
78 /**
79 * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070080 * double-closing {@link #mFd}.
Jeff Sharkey7407c942012-11-12 13:42:49 -080081 */
82 private final ParcelFileDescriptor mWrapped;
83
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070084 /**
85 * Maximum {@link #mStatusBuf} size; longer status messages will be
86 * truncated.
87 */
88 private static final int MAX_STATUS = 1024;
89
90 /**
91 * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
92 * allocated on-demand.
93 */
94 private byte[] mStatusBuf;
95
96 /**
Amith Yamasanib433bb82013-09-18 15:10:16 -070097 * Status read by {@link #checkError()}, or null if not read yet.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070098 */
99 private Status mStatus;
100
Jeff Sharkey7407c942012-11-12 13:42:49 -0800101 private volatile boolean mClosed;
102
103 private final CloseGuard mGuard = CloseGuard.get();
Elliott Hughes43907582011-04-12 14:25:23 -0700104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700106 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
107 * this file doesn't already exist, then create the file with permissions
108 * such that any application can read it.
109 *
110 * @deprecated Creating world-readable files is very dangerous, and likely
111 * to cause security holes in applications. It is strongly
112 * discouraged; instead, applications should use more formal
113 * mechanism for interactions such as {@link ContentProvider},
114 * {@link BroadcastReceiver}, and {@link android.app.Service}.
115 * There are no guarantees that this access mode will remain on
116 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700118 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 public static final int MODE_WORLD_READABLE = 0x00000001;
Elliott Hughes43907582011-04-12 14:25:23 -0700120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700122 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
123 * this file doesn't already exist, then create the file with permissions
124 * such that any application can write it.
125 *
126 * @deprecated Creating world-writable files is very dangerous, and likely
127 * to cause security holes in applications. It is strongly
128 * discouraged; instead, applications should use more formal
129 * mechanism for interactions such as {@link ContentProvider},
130 * {@link BroadcastReceiver}, and {@link android.app.Service}.
131 * There are no guarantees that this access mode will remain on
132 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700134 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 public static final int MODE_WORLD_WRITEABLE = 0x00000002;
Elliott Hughes43907582011-04-12 14:25:23 -0700136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 /**
138 * For use with {@link #open}: open the file with read-only access.
139 */
140 public static final int MODE_READ_ONLY = 0x10000000;
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 write-only access.
144 */
145 public static final int MODE_WRITE_ONLY = 0x20000000;
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 read and write access.
149 */
150 public static final int MODE_READ_WRITE = 0x30000000;
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}: create the file if it doesn't already exist.
154 */
155 public static final int MODE_CREATE = 0x08000000;
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}: erase contents of file when opening.
159 */
160 public static final int MODE_TRUNCATE = 0x04000000;
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}: append to end of file while writing.
164 */
165 public static final int MODE_APPEND = 0x02000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700168 * Create a new ParcelFileDescriptor wrapped around another descriptor. By
169 * default all method calls are delegated to the wrapped descriptor.
170 */
171 public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
172 // We keep a strong reference to the wrapped PFD, and rely on its
173 // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
174 mWrapped = wrapped;
175 mFd = null;
176 mCommFd = null;
177 mClosed = true;
178 }
179
180 /** {@hide} */
181 public ParcelFileDescriptor(FileDescriptor fd) {
182 this(fd, null);
183 }
184
185 /** {@hide} */
186 public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
187 if (fd == null) {
188 throw new NullPointerException("FileDescriptor must not be null");
189 }
190 mWrapped = null;
191 mFd = fd;
Josh Gao5ada8732018-06-26 14:20:29 -0700192 IoUtils.setFdOwner(mFd, this);
193
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700194 mCommFd = commChannel;
Josh Gao5ada8732018-06-26 14:20:29 -0700195 if (mCommFd != null) {
196 IoUtils.setFdOwner(mCommFd, this);
197 }
198
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700199 mGuard.open("close");
200 }
201
202 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 * Create a new ParcelFileDescriptor accessing a given file.
Elliott Hughes43907582011-04-12 14:25:23 -0700204 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 * @param file The file to be opened.
206 * @param mode The desired access mode, must be one of
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700207 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
208 * {@link #MODE_READ_WRITE}; may also be any combination of
209 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
210 * {@link #MODE_WORLD_READABLE}, and
211 * {@link #MODE_WORLD_WRITEABLE}.
212 * @return a new ParcelFileDescriptor pointing to the given file.
213 * @throws FileNotFoundException if the given file does not exist or can not
214 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700215 * @see #parseMode(String)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700217 public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
218 final FileDescriptor fd = openInternal(file, mode);
219 if (fd == null) return null;
Elliott Hughes43907582011-04-12 14:25:23 -0700220
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700221 return new ParcelFileDescriptor(fd);
222 }
223
224 /**
225 * Create a new ParcelFileDescriptor accessing a given file.
226 *
227 * @param file The file to be opened.
228 * @param mode The desired access mode, must be one of
229 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
230 * {@link #MODE_READ_WRITE}; may also be any combination of
231 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
232 * {@link #MODE_WORLD_READABLE}, and
233 * {@link #MODE_WORLD_WRITEABLE}.
234 * @param handler to call listener from; must not be null.
235 * @param listener to be invoked when the returned descriptor has been
236 * closed; must not be null.
237 * @return a new ParcelFileDescriptor pointing to the given file.
238 * @throws FileNotFoundException if the given file does not exist or can not
239 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700240 * @see #parseMode(String)
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700241 */
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700242 public static ParcelFileDescriptor open(File file, int mode, Handler handler,
243 final OnCloseListener listener) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700244 if (handler == null) {
245 throw new IllegalArgumentException("Handler must not be null");
246 }
247 if (listener == null) {
248 throw new IllegalArgumentException("Listener must not be null");
249 }
250
251 final FileDescriptor fd = openInternal(file, mode);
252 if (fd == null) return null;
253
Daichi Hirono91e3b502015-12-16 09:24:16 +0900254 return fromFd(fd, handler, listener);
255 }
256
257 /** {@hide} */
Jeff Sharkeycb394992018-12-01 18:26:43 -0700258 public static ParcelFileDescriptor fromPfd(ParcelFileDescriptor pfd, Handler handler,
259 final OnCloseListener listener) throws IOException {
260 final FileDescriptor original = new FileDescriptor();
261 original.setInt$(pfd.detachFd());
262 return fromFd(original, handler, listener);
263 }
264
265 /** {@hide} */
266 public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler,
267 final OnCloseListener listener) throws IOException {
Daichi Hirono91e3b502015-12-16 09:24:16 +0900268 if (handler == null) {
269 throw new IllegalArgumentException("Handler must not be null");
270 }
271 if (listener == null) {
272 throw new IllegalArgumentException("Listener must not be null");
273 }
274
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700275 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700276 final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
Jeff Brownb2a19852015-03-12 19:49:25 -0700277 final MessageQueue queue = handler.getLooper().getQueue();
Jeff Brown3f640522015-05-15 12:26:15 -0700278 queue.addOnFileDescriptorEventListener(comm[1],
279 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700280 @Override
281 public int onFileDescriptorEvents(FileDescriptor fd, int events) {
282 Status status = null;
Jeff Brown3f640522015-05-15 12:26:15 -0700283 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700284 final byte[] buf = new byte[MAX_STATUS];
285 status = readCommStatus(fd, buf);
Jeff Brown3f640522015-05-15 12:26:15 -0700286 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700287 status = new Status(Status.DEAD);
288 }
289 if (status != null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700290 queue.removeOnFileDescriptorEventListener(fd);
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700291 IoUtils.closeQuietly(fd);
292 listener.onClose(status.asIOException());
Jeff Brownb2a19852015-03-12 19:49:25 -0700293 return 0;
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700294 }
295 return EVENT_INPUT;
296 }
297 });
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700298
299 return pfd;
300 }
301
302 private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800303 final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC);
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600304
305 int realMode = S_IRWXU | S_IRWXG;
306 if ((mode & MODE_WORLD_READABLE) != 0) realMode |= S_IROTH;
307 if ((mode & MODE_WORLD_WRITEABLE) != 0) realMode |= S_IWOTH;
308
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700309 final String path = file.getPath();
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600310 try {
311 return Os.open(path, flags, realMode);
312 } catch (ErrnoException e) {
313 throw new FileNotFoundException(e.getMessage());
314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
317 /**
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700318 * Create a new ParcelFileDescriptor that is a dup of an existing
319 * FileDescriptor. This obeys standard POSIX semantics, where the
320 * new file descriptor shared state such as file position with the
321 * original file descriptor.
322 */
323 public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700324 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800325 final FileDescriptor fd = new FileDescriptor();
326 int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
327 fd.setInt$(intfd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700328 return new ParcelFileDescriptor(fd);
329 } catch (ErrnoException e) {
330 throw e.rethrowAsIOException();
331 }
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700332 }
333
334 /**
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700335 * Create a new ParcelFileDescriptor that is a dup of the existing
336 * FileDescriptor. This obeys standard POSIX semantics, where the
337 * new file descriptor shared state such as file position with the
338 * original file descriptor.
339 */
340 public ParcelFileDescriptor dup() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700341 if (mWrapped != null) {
342 return mWrapped.dup();
343 } else {
344 return dup(getFileDescriptor());
345 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700346 }
347
348 /**
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700349 * Create a new ParcelFileDescriptor from a raw native fd. The new
350 * ParcelFileDescriptor holds a dup of the original fd passed in here,
351 * so you must still close that fd as well as the new ParcelFileDescriptor.
352 *
353 * @param fd The native fd that the ParcelFileDescriptor should dup.
354 *
355 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
356 * for a dup of the given fd.
357 */
358 public static ParcelFileDescriptor fromFd(int fd) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700359 final FileDescriptor original = new FileDescriptor();
360 original.setInt$(fd);
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700361
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700362 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800363 final FileDescriptor dup = new FileDescriptor();
364 int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
365 dup.setInt$(intfd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700366 return new ParcelFileDescriptor(dup);
367 } catch (ErrnoException e) {
368 throw e.rethrowAsIOException();
369 }
370 }
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700371
372 /**
373 * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
374 * The returned ParcelFileDescriptor now owns the given fd, and will be
375 * responsible for closing it. You must not close the fd yourself.
376 *
377 * @param fd The native fd that the ParcelFileDescriptor should adopt.
378 *
379 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
380 * for the given fd.
381 */
382 public static ParcelFileDescriptor adoptFd(int fd) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700383 final FileDescriptor fdesc = new FileDescriptor();
384 fdesc.setInt$(fd);
385
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700386 return new ParcelFileDescriptor(fdesc);
387 }
388
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700389 /**
390 * Create a new ParcelFileDescriptor from the specified Socket. The new
391 * ParcelFileDescriptor holds a dup of the original FileDescriptor in
392 * the Socket, so you must still close the Socket as well as the new
393 * ParcelFileDescriptor.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 *
395 * @param socket The Socket whose FileDescriptor is used to create
396 * a new ParcelFileDescriptor.
397 *
Josh Gaoe3589b22018-09-28 10:59:16 -0700398 * @return A new ParcelFileDescriptor with a duped copy of the
399 * FileDescriptor of the specified Socket.
400 *
401 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 */
403 public static ParcelFileDescriptor fromSocket(Socket socket) {
Elliott Hughes43907582011-04-12 14:25:23 -0700404 FileDescriptor fd = socket.getFileDescriptor$();
Josh Gaoe3589b22018-09-28 10:59:16 -0700405 try {
406 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
407 } catch (IOException e) {
408 throw new UncheckedIOException(e);
409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 }
411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 /**
Josh Gaoe3589b22018-09-28 10:59:16 -0700413 * Create a new ParcelFileDescriptor from the specified DatagramSocket. The
414 * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
415 * the DatagramSocket, so you must still close the DatagramSocket as well
416 * as the new ParcelFileDescriptor.
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700417 *
418 * @param datagramSocket The DatagramSocket whose FileDescriptor is used
419 * to create a new ParcelFileDescriptor.
420 *
Josh Gaoe3589b22018-09-28 10:59:16 -0700421 * @return A new ParcelFileDescriptor with a duped copy of the
422 * FileDescriptor of the specified Socket.
423 *
424 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700425 */
426 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
427 FileDescriptor fd = datagramSocket.getFileDescriptor$();
Josh Gaoe3589b22018-09-28 10:59:16 -0700428 try {
429 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
430 } catch (IOException e) {
431 throw new UncheckedIOException(e);
432 }
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700433 }
434
435 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700436 * Create two ParcelFileDescriptors structured as a data pipe. The first
437 * ParcelFileDescriptor in the returned array is the read side; the second
438 * is the write side.
439 */
440 public static ParcelFileDescriptor[] createPipe() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700441 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800442 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700443 return new ParcelFileDescriptor[] {
444 new ParcelFileDescriptor(fds[0]),
445 new ParcelFileDescriptor(fds[1]) };
446 } catch (ErrnoException e) {
447 throw e.rethrowAsIOException();
448 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700449 }
450
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700451 /**
452 * Create two ParcelFileDescriptors structured as a data pipe. The first
453 * ParcelFileDescriptor in the returned array is the read side; the second
454 * is the write side.
455 * <p>
456 * The write end has the ability to deliver an error message through
457 * {@link #closeWithError(String)} which can be handled by the read end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700458 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700459 * This can also be used to detect remote crashes.
460 */
461 public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
462 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700463 final FileDescriptor[] comm = createCommSocketPair();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800464 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700465 return new ParcelFileDescriptor[] {
466 new ParcelFileDescriptor(fds[0], comm[0]),
467 new ParcelFileDescriptor(fds[1], comm[1]) };
468 } catch (ErrnoException e) {
469 throw e.rethrowAsIOException();
470 }
471 }
472
473 /**
474 * Create two ParcelFileDescriptors structured as a pair of sockets
475 * connected to each other. The two sockets are indistinguishable.
476 */
477 public static ParcelFileDescriptor[] createSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800478 return createSocketPair(SOCK_STREAM);
479 }
480
481 /**
482 * @hide
483 */
484 public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700485 try {
486 final FileDescriptor fd0 = new FileDescriptor();
487 final FileDescriptor fd1 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800488 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700489 return new ParcelFileDescriptor[] {
490 new ParcelFileDescriptor(fd0),
491 new ParcelFileDescriptor(fd1) };
492 } catch (ErrnoException e) {
493 throw e.rethrowAsIOException();
494 }
495 }
496
497 /**
498 * Create two ParcelFileDescriptors structured as a pair of sockets
499 * connected to each other. The two sockets are indistinguishable.
500 * <p>
501 * Both ends have the ability to deliver an error message through
502 * {@link #closeWithError(String)} which can be detected by the other end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700503 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700504 * This can also be used to detect remote crashes.
505 */
506 public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800507 return createReliableSocketPair(SOCK_STREAM);
508 }
509
510 /**
511 * @hide
512 */
513 public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700514 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700515 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700516 final FileDescriptor fd0 = new FileDescriptor();
517 final FileDescriptor fd1 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800518 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700519 return new ParcelFileDescriptor[] {
520 new ParcelFileDescriptor(fd0, comm[0]),
521 new ParcelFileDescriptor(fd1, comm[1]) };
522 } catch (ErrnoException e) {
523 throw e.rethrowAsIOException();
524 }
525 }
526
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700527 private static FileDescriptor[] createCommSocketPair() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700528 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700529 // Use SOCK_SEQPACKET so that we have a guarantee that the status
530 // is written and read atomically as one unit and is not split
531 // across multiple IO operations.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700532 final FileDescriptor comm1 = new FileDescriptor();
533 final FileDescriptor comm2 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800534 Os.socketpair(AF_UNIX, SOCK_SEQPACKET | ifAtLeastQ(SOCK_CLOEXEC), 0, comm1, comm2);
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700535 IoUtils.setBlocking(comm1, false);
536 IoUtils.setBlocking(comm2, false);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700537 return new FileDescriptor[] { comm1, comm2 };
538 } catch (ErrnoException e) {
539 throw e.rethrowAsIOException();
540 }
541 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700542
543 /**
Dianne Hackborn540f86a2011-01-11 17:52:22 -0800544 * @hide Please use createPipe() or ContentProvider.openPipeHelper().
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100545 * Gets a file descriptor for a read-only copy of the given data.
546 *
547 * @param data Data to copy.
548 * @param name Name for the shared memory area that may back the file descriptor.
549 * This is purely informative and may be {@code null}.
550 * @return A ParcelFileDescriptor.
551 * @throws IOException if there is an error while creating the shared memory area.
552 */
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800553 @Deprecated
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100554 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
555 if (data == null) return null;
556 MemoryFile file = new MemoryFile(name, data.length);
557 if (data.length > 0) {
558 file.writeBytes(data, 0, 0, data.length);
559 }
560 file.deactivate();
561 FileDescriptor fd = file.getFileDescriptor();
Josh Gaoe3589b22018-09-28 10:59:16 -0700562 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100563 }
564
565 /**
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700566 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
567 * with {@link #open}.
568 * <p>
Garfield Tanaf03e5a2017-05-15 14:19:11 -0700569 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw"
570 * or "rwt".
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700571 * @return A bitmask representing the given file mode.
572 * @throws IllegalArgumentException if the given string does not match a known file mode.
573 */
574 public static int parseMode(String mode) {
Jeff Sharkey63280e02018-09-12 11:47:07 -0600575 return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700576 }
577
578 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700579 * Return the filesystem path of the real file on disk that is represented
580 * by the given {@link FileDescriptor}.
581 *
582 * @hide
583 */
Jeff Sharkeycb269aac2019-01-25 11:15:38 -0700584 @TestApi
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700585 public static File getFile(FileDescriptor fd) throws IOException {
586 try {
587 final String path = Os.readlink("/proc/self/fd/" + fd.getInt$());
588 if (OsConstants.S_ISREG(Os.stat(path).st_mode)) {
589 return new File(path);
590 } else {
591 throw new IOException("Not a regular file: " + path);
592 }
593 } catch (ErrnoException e) {
594 throw e.rethrowAsIOException();
595 }
596 }
597
598 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 * Retrieve the actual FileDescriptor associated with this object.
Elliott Hughes43907582011-04-12 14:25:23 -0700600 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 * @return Returns the FileDescriptor associated with this object.
602 */
603 public FileDescriptor getFileDescriptor() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700604 if (mWrapped != null) {
605 return mWrapped.getFileDescriptor();
606 } else {
607 return mFd;
608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 }
Elliott Hughes43907582011-04-12 14:25:23 -0700610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700612 * Return the total size of the file representing this fd, as determined by
613 * {@code stat()}. Returns -1 if the fd is not a file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700615 public long getStatSize() {
616 if (mWrapped != null) {
617 return mWrapped.getStatSize();
618 } else {
619 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700620 final StructStat st = Os.fstat(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700621 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
622 return st.st_size;
623 } else {
624 return -1;
625 }
626 } catch (ErrnoException e) {
627 Log.w(TAG, "fstat() failed: " + e);
628 return -1;
629 }
630 }
631 }
Elliott Hughes43907582011-04-12 14:25:23 -0700632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 /**
634 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
635 * and I really don't think we want it to be public.
636 * @hide
637 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700638 public long seekTo(long pos) throws IOException {
639 if (mWrapped != null) {
640 return mWrapped.seekTo(pos);
641 } else {
642 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700643 return Os.lseek(mFd, pos, SEEK_SET);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700644 } catch (ErrnoException e) {
645 throw e.rethrowAsIOException();
646 }
647 }
648 }
Elliott Hughes43907582011-04-12 14:25:23 -0700649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 /**
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800651 * Return the native fd int for this ParcelFileDescriptor. The
652 * ParcelFileDescriptor still owns the fd, and it still must be closed
653 * through this API.
654 */
655 public int getFd() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700656 if (mWrapped != null) {
657 return mWrapped.getFd();
658 } else {
659 if (mClosed) {
660 throw new IllegalStateException("Already closed");
661 }
662 return mFd.getInt$();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800663 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800664 }
Elliott Hughes43907582011-04-12 14:25:23 -0700665
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800666 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700667 * Return the native fd int for this ParcelFileDescriptor and detach it from
668 * the object here. You are now responsible for closing the fd in native
669 * code.
670 * <p>
671 * You should not detach when the original creator of the descriptor is
672 * expecting a reliable signal through {@link #close()} or
673 * {@link #closeWithError(String)}.
674 *
675 * @see #canDetectErrors()
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800676 */
677 public int detachFd() {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800678 if (mWrapped != null) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700679 return mWrapped.detachFd();
680 } else {
681 if (mClosed) {
682 throw new IllegalStateException("Already closed");
683 }
Josh Gao5ada8732018-06-26 14:20:29 -0700684 int fd = IoUtils.acquireRawFd(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700685 writeCommStatusAndClose(Status.DETACHED, null);
Makoto Onukib30ad6f2015-06-11 12:34:22 -0700686 mClosed = true;
687 mGuard.close();
688 releaseResources();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800689 return fd;
690 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800691 }
Elliott Hughes43907582011-04-12 14:25:23 -0700692
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800693 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 * Close the ParcelFileDescriptor. This implementation closes the underlying
695 * OS resources allocated to represent this stream.
Elliott Hughes43907582011-04-12 14:25:23 -0700696 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 * @throws IOException
698 * If an error occurs attempting to close this ParcelFileDescriptor.
699 */
Jeff Sharkey7407c942012-11-12 13:42:49 -0800700 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 public void close() throws IOException {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800702 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700703 try {
704 mWrapped.close();
705 } finally {
706 releaseResources();
707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700709 closeWithStatus(Status.OK, null);
710 }
711 }
712
713 /**
714 * Close the ParcelFileDescriptor, informing any peer that an error occurred
715 * while processing. If the creator of this descriptor is not observing
716 * errors, it will close normally.
717 *
718 * @param msg describing the error; must not be null.
719 */
720 public void closeWithError(String msg) throws IOException {
721 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700722 try {
723 mWrapped.closeWithError(msg);
724 } finally {
725 releaseResources();
726 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700727 } else {
728 if (msg == null) {
729 throw new IllegalArgumentException("Message must not be null");
730 }
731 closeWithStatus(Status.ERROR, msg);
732 }
733 }
734
Amith Yamasani487c11a2013-09-18 09:16:15 -0700735 private void closeWithStatus(int status, String msg) {
736 if (mClosed) return;
737 mClosed = true;
Andreas Gampe009b8522017-10-10 08:01:38 -0700738 if (mGuard != null) {
739 mGuard.close();
740 }
Amith Yamasani487c11a2013-09-18 09:16:15 -0700741 // Status MUST be sent before closing actual descriptor
742 writeCommStatusAndClose(status, msg);
743 IoUtils.closeQuietly(mFd);
744 releaseResources();
745 }
746
747 /**
748 * Called when the fd is being closed, for subclasses to release any other resources
749 * associated with it, such as acquired providers.
750 * @hide
751 */
752 public void releaseResources() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700753 }
754
755 private byte[] getOrCreateStatusBuffer() {
756 if (mStatusBuf == null) {
757 mStatusBuf = new byte[MAX_STATUS];
758 }
759 return mStatusBuf;
760 }
761
762 private void writeCommStatusAndClose(int status, String msg) {
763 if (mCommFd == null) {
764 // Not reliable, or someone already sent status
765 if (msg != null) {
766 Log.w(TAG, "Unable to inform peer: " + msg);
767 }
768 return;
769 }
770
771 if (status == Status.DETACHED) {
772 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
773 }
774
775 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700776 if (status == Status.SILENCE) return;
777
778 // Since we're about to close, read off any remote status. It's
779 // okay to remember missing here.
780 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
781
782 // Skip writing status when other end has already gone away.
783 if (mStatus != null) return;
784
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700785 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700786 final byte[] buf = getOrCreateStatusBuffer();
787 int writePtr = 0;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700788
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700789 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
790 writePtr += 4;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700791
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700792 if (msg != null) {
793 final byte[] rawMsg = msg.getBytes();
794 final int len = Math.min(rawMsg.length, buf.length - writePtr);
795 System.arraycopy(rawMsg, 0, buf, writePtr, len);
796 writePtr += len;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700797 }
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700798
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700799 // Must write the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700800 Os.write(mCommFd, buf, 0, writePtr);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700801 } catch (ErrnoException e) {
802 // Reporting status is best-effort
803 Log.w(TAG, "Failed to report status: " + e);
Neil Fuller43582df2014-04-11 17:29:54 +0100804 } catch (InterruptedIOException e) {
805 // Reporting status is best-effort
806 Log.w(TAG, "Failed to report status: " + e);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700807 }
808
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700809 } finally {
810 IoUtils.closeQuietly(mCommFd);
811 mCommFd = null;
812 }
813 }
814
815 private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
816 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700817 // Must read the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700818 final int n = Os.read(comm, buf, 0, buf.length);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700819 if (n == 0) {
820 // EOF means they're dead
821 return new Status(Status.DEAD);
822 } else {
823 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
824 if (status == Status.ERROR) {
825 final String msg = new String(buf, 4, n - 4);
826 return new Status(status, msg);
827 }
828 return new Status(status);
829 }
830 } catch (ErrnoException e) {
831 if (e.errno == OsConstants.EAGAIN) {
832 // Remote is still alive, but no status written yet
833 return null;
834 } else {
835 Log.d(TAG, "Failed to read status; assuming dead: " + e);
836 return new Status(Status.DEAD);
837 }
Neil Fuller43582df2014-04-11 17:29:54 +0100838 } catch (InterruptedIOException e) {
839 Log.d(TAG, "Failed to read status; assuming dead: " + e);
840 return new Status(Status.DEAD);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700841 }
842 }
843
844 /**
845 * Indicates if this ParcelFileDescriptor can communicate and detect remote
846 * errors/crashes.
847 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700848 * @see #checkError()
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700849 */
850 public boolean canDetectErrors() {
851 if (mWrapped != null) {
852 return mWrapped.canDetectErrors();
853 } else {
854 return mCommFd != null;
855 }
856 }
857
858 /**
859 * Detect and throw if the other end of a pipe or socket pair encountered an
860 * error or crashed. This allows a reader to distinguish between a valid EOF
861 * and an error/crash.
862 * <p>
863 * If this ParcelFileDescriptor is unable to detect remote errors, it will
864 * return silently.
865 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700866 * @throws IOException for normal errors.
867 * @throws FileDescriptorDetachedException
868 * if the remote side called {@link #detachFd()}. Once detached, the remote
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700869 * side is unable to communicate any errors through
Amith Yamasanib433bb82013-09-18 15:10:16 -0700870 * {@link #closeWithError(String)}.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700871 * @see #canDetectErrors()
872 */
Amith Yamasanib433bb82013-09-18 15:10:16 -0700873 public void checkError() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700874 if (mWrapped != null) {
Amith Yamasanib433bb82013-09-18 15:10:16 -0700875 mWrapped.checkError();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700876 } else {
877 if (mStatus == null) {
878 if (mCommFd == null) {
879 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
880 return;
881 }
882
883 // Try reading status; it might be null if nothing written yet.
884 // Either way, we keep comm open to write our status later.
885 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
886 }
887
Amith Yamasanib433bb82013-09-18 15:10:16 -0700888 if (mStatus == null || mStatus.status == Status.OK) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700889 // No status yet, or everything is peachy!
890 return;
891 } else {
892 throw mStatus.asIOException();
893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
895 }
Elliott Hughes43907582011-04-12 14:25:23 -0700896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 /**
898 * An InputStream you can create on a ParcelFileDescriptor, which will
899 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700900 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 */
902 public static class AutoCloseInputStream extends FileInputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700903 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700904
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700905 public AutoCloseInputStream(ParcelFileDescriptor pfd) {
906 super(pfd.getFileDescriptor());
907 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 }
909
910 @Override
911 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700912 try {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700913 super.close();
Josh Gao401fb242018-11-09 13:40:53 -0800914 } finally {
915 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
Tomasz Mikolajewskiad3b6162016-05-30 10:17:08 +0900918
919 @Override
920 public int read() throws IOException {
921 final int result = super.read();
922 if (result == -1 && mPfd.canDetectErrors()) {
923 // Check for errors only on EOF, to minimize overhead.
924 mPfd.checkError();
925 }
926 return result;
927 }
928
929 @Override
930 public int read(byte[] b) throws IOException {
931 final int result = super.read(b);
932 if (result == -1 && mPfd.canDetectErrors()) {
933 mPfd.checkError();
934 }
935 return result;
936 }
937
938 @Override
939 public int read(byte[] b, int off, int len) throws IOException {
940 final int result = super.read(b, off, len);
941 if (result == -1 && mPfd.canDetectErrors()) {
942 mPfd.checkError();
943 }
944 return result;
945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 }
Elliott Hughes43907582011-04-12 14:25:23 -0700947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 /**
949 * An OutputStream you can create on a ParcelFileDescriptor, which will
950 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700951 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 */
953 public static class AutoCloseOutputStream extends FileOutputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700954 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700955
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700956 public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
957 super(pfd.getFileDescriptor());
958 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
960
961 @Override
962 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700963 try {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700964 super.close();
Josh Gao401fb242018-11-09 13:40:53 -0800965 } finally {
966 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 }
969 }
Elliott Hughes43907582011-04-12 14:25:23 -0700970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 @Override
972 public String toString() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700973 if (mWrapped != null) {
974 return mWrapped.toString();
975 } else {
976 return "{ParcelFileDescriptor: " + mFd + "}";
977 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 }
Elliott Hughes43907582011-04-12 14:25:23 -0700979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 @Override
981 protected void finalize() throws Throwable {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700982 if (mWrapped != null) {
983 releaseResources();
984 }
Jeff Sharkey7407c942012-11-12 13:42:49 -0800985 if (mGuard != null) {
986 mGuard.warnIfOpen();
987 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 try {
989 if (!mClosed) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700990 closeWithStatus(Status.LEAKED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 }
992 } finally {
993 super.finalize();
994 }
995 }
Elliott Hughes43907582011-04-12 14:25:23 -0700996
Jeff Sharkey7407c942012-11-12 13:42:49 -0800997 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 public int describeContents() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700999 if (mWrapped != null) {
1000 return mWrapped.describeContents();
1001 } else {
1002 return Parcelable.CONTENTS_FILE_DESCRIPTOR;
1003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 }
1005
Dan Egnorb3e4ef32010-07-20 09:03:35 -07001006 /**
1007 * {@inheritDoc}
1008 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
1009 * the file descriptor will be closed after a copy is written to the Parcel.
1010 */
Jeff Sharkey7407c942012-11-12 13:42:49 -08001011 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 public void writeToParcel(Parcel out, int flags) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001013 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001014 try {
1015 mWrapped.writeToParcel(out, flags);
1016 } finally {
1017 releaseResources();
1018 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001019 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001020 if (mCommFd != null) {
1021 out.writeInt(1);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001022 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001023 out.writeFileDescriptor(mCommFd);
1024 } else {
1025 out.writeInt(0);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001026 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001027 }
1028 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001029 // Not a real close, so emit no status
1030 closeWithStatus(Status.SILENCE, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 }
1032 }
1033 }
1034
1035 public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
1036 = new Parcelable.Creator<ParcelFileDescriptor>() {
Jeff Sharkey7407c942012-11-12 13:42:49 -08001037 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 public ParcelFileDescriptor createFromParcel(Parcel in) {
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001039 int hasCommChannel = in.readInt();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001040 final FileDescriptor fd = in.readRawFileDescriptor();
1041 FileDescriptor commChannel = null;
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001042 if (hasCommChannel != 0) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001043 commChannel = in.readRawFileDescriptor();
1044 }
1045 return new ParcelFileDescriptor(fd, commChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 }
Jeff Sharkey7407c942012-11-12 13:42:49 -08001047
1048 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 public ParcelFileDescriptor[] newArray(int size) {
1050 return new ParcelFileDescriptor[size];
1051 }
1052 };
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001053
1054 /**
1055 * Callback indicating that a ParcelFileDescriptor has been closed.
1056 */
1057 public interface OnCloseListener {
1058 /**
1059 * Event indicating the ParcelFileDescriptor to which this listener was
1060 * attached has been closed.
1061 *
1062 * @param e error state, or {@code null} if closed cleanly.
Amith Yamasanib433bb82013-09-18 15:10:16 -07001063 * If the close event was the result of
1064 * {@link ParcelFileDescriptor#detachFd()}, this will be a
1065 * {@link FileDescriptorDetachedException}. After detach the
1066 * remote side may continue reading/writing to the underlying
1067 * {@link FileDescriptor}, but they can no longer deliver
1068 * reliable close/error events.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001069 */
Amith Yamasanib433bb82013-09-18 15:10:16 -07001070 public void onClose(IOException e);
1071 }
1072
1073 /**
1074 * Exception that indicates that the file descriptor was detached.
1075 */
1076 public static class FileDescriptorDetachedException extends IOException {
1077
1078 private static final long serialVersionUID = 0xDe7ac4edFdL;
1079
1080 public FileDescriptorDetachedException() {
1081 super("Remote side is detached");
1082 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001083 }
1084
1085 /**
1086 * Internal class representing a remote status read by
1087 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
Steven Moreland3de571e2018-11-12 19:44:23 -08001088 *
1089 * Warning: this must be kept in sync with ParcelFileDescriptorStatus at
1090 * frameworks/native/libs/binder/Parcel.cpp
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001091 */
1092 private static class Status {
1093 /** Special value indicating remote side died. */
1094 public static final int DEAD = -2;
1095 /** Special value indicating no status should be written. */
1096 public static final int SILENCE = -1;
1097
1098 /** Remote reported that everything went better than expected. */
1099 public static final int OK = 0;
1100 /** Remote reported error; length and message follow. */
1101 public static final int ERROR = 1;
1102 /** Remote reported {@link #detachFd()} and went rogue. */
1103 public static final int DETACHED = 2;
1104 /** Remote reported their object was finalized. */
1105 public static final int LEAKED = 3;
1106
1107 public final int status;
1108 public final String msg;
1109
1110 public Status(int status) {
1111 this(status, null);
1112 }
1113
1114 public Status(int status, String msg) {
1115 this.status = status;
1116 this.msg = msg;
1117 }
1118
1119 public IOException asIOException() {
1120 switch (status) {
1121 case DEAD:
1122 return new IOException("Remote side is dead");
1123 case OK:
1124 return null;
1125 case ERROR:
1126 return new IOException("Remote error: " + msg);
1127 case DETACHED:
Amith Yamasanib433bb82013-09-18 15:10:16 -07001128 return new FileDescriptorDetachedException();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001129 case LEAKED:
1130 return new IOException("Remote side was leaked");
1131 default:
1132 return new IOException("Unknown status: " + status);
1133 }
1134 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001135
1136 @Override
Jeff Brown6fd9f9a2015-03-12 19:45:47 -07001137 public String toString() {
1138 return "{" + status + ": " + msg + "}";
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001139 }
1140 }
Nick Kralevich0c48b942018-12-17 14:24:22 -08001141
1142 private static boolean isAtLeastQ() {
1143 return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q);
1144 }
1145
1146 private static int ifAtLeastQ(int value) {
1147 return isAtLeastQ() ? value : 0;
1148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149}