blob: c0847872a45a09c29041076c41e85f751379f784 [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 Sharkey197fe1f2020-01-07 22:06:37 -070034import android.annotation.NonNull;
35import android.annotation.SuppressLint;
36import android.annotation.SystemApi;
Jeff Sharkeycb269aac2019-01-25 11:15:38 -070037import android.annotation.TestApi;
Artur Satayevafdb23a2019-12-10 17:47:53 +000038import android.compat.annotation.UnsupportedAppUsage;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070039import android.content.BroadcastReceiver;
40import android.content.ContentProvider;
Jeff Sharkey588c15e2019-10-10 17:29:58 -060041import android.content.ContentResolver;
42import android.net.Uri;
Jeff Brown3f640522015-05-15 12:26:15 -070043import android.os.MessageQueue.OnFileDescriptorEventListener;
Elliott Hughes34385d32014-04-28 11:11:32 -070044import android.system.ErrnoException;
45import android.system.Os;
46import android.system.OsConstants;
47import android.system.StructStat;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070048import android.util.Log;
Jeff Sharkey588c15e2019-10-10 17:29:58 -060049import android.util.Size;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070050
Jeff Sharkey7407c942012-11-12 13:42:49 -080051import dalvik.system.CloseGuard;
Nick Kralevich0c48b942018-12-17 14:24:22 -080052import dalvik.system.VMRuntime;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -060053
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070054import libcore.io.IoUtils;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070055import libcore.io.Memory;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070056
Jeff Sharkeye861b422012-03-01 20:59:22 -080057import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import java.io.File;
59import java.io.FileDescriptor;
60import java.io.FileInputStream;
61import java.io.FileNotFoundException;
62import java.io.FileOutputStream;
63import java.io.IOException;
Neil Fuller43582df2014-04-11 17:29:54 +010064import java.io.InterruptedIOException;
Josh Gaoe3589b22018-09-28 10:59:16 -070065import java.io.UncheckedIOException;
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -070066import java.net.DatagramSocket;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import java.net.Socket;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070068import java.nio.ByteOrder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
70/**
71 * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
72 * you to close it when done with it.
73 */
Jeff Sharkeye861b422012-03-01 20:59:22 -080074public class ParcelFileDescriptor implements Parcelable, Closeable {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070075 private static final String TAG = "ParcelFileDescriptor";
76
77 private final FileDescriptor mFd;
78
79 /**
80 * Optional socket used to communicate close events, status at close, and
81 * detect remote process crashes.
82 */
83 private FileDescriptor mCommFd;
Jeff Sharkey7407c942012-11-12 13:42:49 -080084
85 /**
86 * Wrapped {@link ParcelFileDescriptor}, if any. Used to avoid
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070087 * double-closing {@link #mFd}.
Hans Boehm339d4472019-05-30 15:48:17 -070088 * mClosed is always true if mWrapped is non-null.
Jeff Sharkey7407c942012-11-12 13:42:49 -080089 */
90 private final ParcelFileDescriptor mWrapped;
91
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -070092 /**
93 * Maximum {@link #mStatusBuf} size; longer status messages will be
94 * truncated.
95 */
96 private static final int MAX_STATUS = 1024;
97
98 /**
99 * Temporary buffer used by {@link #readCommStatus(FileDescriptor, byte[])},
100 * allocated on-demand.
101 */
102 private byte[] mStatusBuf;
103
104 /**
Amith Yamasanib433bb82013-09-18 15:10:16 -0700105 * Status read by {@link #checkError()}, or null if not read yet.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700106 */
107 private Status mStatus;
108
Jeff Sharkey7407c942012-11-12 13:42:49 -0800109 private volatile boolean mClosed;
110
111 private final CloseGuard mGuard = CloseGuard.get();
Elliott Hughes43907582011-04-12 14:25:23 -0700112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700114 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
115 * this file doesn't already exist, then create the file with permissions
116 * such that any application can read it.
117 *
118 * @deprecated Creating world-readable files is very dangerous, and likely
119 * to cause security holes in applications. It is strongly
120 * discouraged; instead, applications should use more formal
121 * mechanism for interactions such as {@link ContentProvider},
122 * {@link BroadcastReceiver}, and {@link android.app.Service}.
123 * There are no guarantees that this access mode will remain on
124 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700126 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 public static final int MODE_WORLD_READABLE = 0x00000001;
Elliott Hughes43907582011-04-12 14:25:23 -0700128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700130 * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied and
131 * this file doesn't already exist, then create the file with permissions
132 * such that any application can write it.
133 *
134 * @deprecated Creating world-writable files is very dangerous, and likely
135 * to cause security holes in applications. It is strongly
136 * discouraged; instead, applications should use more formal
137 * mechanism for interactions such as {@link ContentProvider},
138 * {@link BroadcastReceiver}, and {@link android.app.Service}.
139 * There are no guarantees that this access mode will remain on
140 * a file, such as when it goes through a backup and restore.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700142 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 public static final int MODE_WORLD_WRITEABLE = 0x00000002;
Elliott Hughes43907582011-04-12 14:25:23 -0700144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 /**
146 * For use with {@link #open}: open the file with read-only access.
147 */
148 public static final int MODE_READ_ONLY = 0x10000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 /**
151 * For use with {@link #open}: open the file with write-only access.
152 */
153 public static final int MODE_WRITE_ONLY = 0x20000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 /**
156 * For use with {@link #open}: open the file with read and write access.
157 */
158 public static final int MODE_READ_WRITE = 0x30000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 /**
161 * For use with {@link #open}: create the file if it doesn't already exist.
162 */
163 public static final int MODE_CREATE = 0x08000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 /**
166 * For use with {@link #open}: erase contents of file when opening.
167 */
168 public static final int MODE_TRUNCATE = 0x04000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 /**
171 * For use with {@link #open}: append to end of file while writing.
172 */
173 public static final int MODE_APPEND = 0x02000000;
Elliott Hughes43907582011-04-12 14:25:23 -0700174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700176 * Create a new ParcelFileDescriptor wrapped around another descriptor. By
177 * default all method calls are delegated to the wrapped descriptor.
178 */
179 public ParcelFileDescriptor(ParcelFileDescriptor wrapped) {
180 // We keep a strong reference to the wrapped PFD, and rely on its
181 // finalizer to trigger CloseGuard. All calls are delegated to wrapper.
182 mWrapped = wrapped;
183 mFd = null;
184 mCommFd = null;
185 mClosed = true;
186 }
187
188 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000189 @UnsupportedAppUsage
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700190 public ParcelFileDescriptor(FileDescriptor fd) {
191 this(fd, null);
192 }
193
194 /** {@hide} */
195 public ParcelFileDescriptor(FileDescriptor fd, FileDescriptor commChannel) {
196 if (fd == null) {
197 throw new NullPointerException("FileDescriptor must not be null");
198 }
199 mWrapped = null;
200 mFd = fd;
Josh Gao5ada8732018-06-26 14:20:29 -0700201 IoUtils.setFdOwner(mFd, this);
202
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700203 mCommFd = commChannel;
Josh Gao5ada8732018-06-26 14:20:29 -0700204 if (mCommFd != null) {
205 IoUtils.setFdOwner(mCommFd, this);
206 }
207
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700208 mGuard.open("close");
209 }
210
211 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 * Create a new ParcelFileDescriptor accessing a given file.
Jeff Sharkey588c15e2019-10-10 17:29:58 -0600213 * <p>
214 * This method should only be used for files that you have direct access to;
215 * if you'd like to work with files hosted outside your app, use an API like
216 * {@link ContentResolver#openFile(Uri, String, CancellationSignal)}.
Elliott Hughes43907582011-04-12 14:25:23 -0700217 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 * @param file The file to be opened.
219 * @param mode The desired access mode, must be one of
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700220 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
221 * {@link #MODE_READ_WRITE}; may also be any combination of
222 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
223 * {@link #MODE_WORLD_READABLE}, and
224 * {@link #MODE_WORLD_WRITEABLE}.
225 * @return a new ParcelFileDescriptor pointing to the given file.
226 * @throws FileNotFoundException if the given file does not exist or can not
227 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700228 * @see #parseMode(String)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700230 public static ParcelFileDescriptor open(File file, int mode) throws FileNotFoundException {
231 final FileDescriptor fd = openInternal(file, mode);
232 if (fd == null) return null;
Elliott Hughes43907582011-04-12 14:25:23 -0700233
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700234 return new ParcelFileDescriptor(fd);
235 }
236
237 /**
238 * Create a new ParcelFileDescriptor accessing a given file.
Jeff Sharkey588c15e2019-10-10 17:29:58 -0600239 * <p>
240 * This method should only be used for files that you have direct access to;
241 * if you'd like to work with files hosted outside your app, use an API like
242 * {@link ContentResolver#openFile(Uri, String, CancellationSignal)}.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700243 *
244 * @param file The file to be opened.
245 * @param mode The desired access mode, must be one of
246 * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
247 * {@link #MODE_READ_WRITE}; may also be any combination of
248 * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
249 * {@link #MODE_WORLD_READABLE}, and
250 * {@link #MODE_WORLD_WRITEABLE}.
251 * @param handler to call listener from; must not be null.
252 * @param listener to be invoked when the returned descriptor has been
253 * closed; must not be null.
254 * @return a new ParcelFileDescriptor pointing to the given file.
255 * @throws FileNotFoundException if the given file does not exist or can not
256 * be opened with the requested mode.
Jeff Sharkeye8c00d82013-10-15 15:46:10 -0700257 * @see #parseMode(String)
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700258 */
Jeff Sharkey197fe1f2020-01-07 22:06:37 -0700259 // We can't accept a generic Executor here, since we need to use
260 // MessageQueue.addOnFileDescriptorEventListener()
261 @SuppressLint("ExecutorRegistration")
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700262 public static ParcelFileDescriptor open(File file, int mode, Handler handler,
263 final OnCloseListener listener) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700264 if (handler == null) {
265 throw new IllegalArgumentException("Handler must not be null");
266 }
267 if (listener == null) {
268 throw new IllegalArgumentException("Listener must not be null");
269 }
270
271 final FileDescriptor fd = openInternal(file, mode);
272 if (fd == null) return null;
273
Daichi Hirono91e3b502015-12-16 09:24:16 +0900274 return fromFd(fd, handler, listener);
275 }
276
Jeff Sharkey197fe1f2020-01-07 22:06:37 -0700277 /**
278 * Create a new ParcelFileDescriptor wrapping an already-opened file.
279 *
280 * @param pfd The already-opened file.
281 * @param handler to call listener from.
282 * @param listener to be invoked when the returned descriptor has been
283 * closed.
284 * @return a new ParcelFileDescriptor pointing to the given file.
Jeff Sharkey197fe1f2020-01-07 22:06:37 -0700285 */
Jeff Sharkey197fe1f2020-01-07 22:06:37 -0700286 // We can't accept a generic Executor here, since we need to use
287 // MessageQueue.addOnFileDescriptorEventListener()
288 @SuppressLint("ExecutorRegistration")
289 public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd,
290 @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException {
Jeff Sharkeycb394992018-12-01 18:26:43 -0700291 final FileDescriptor original = new FileDescriptor();
292 original.setInt$(pfd.detachFd());
293 return fromFd(original, handler, listener);
294 }
295
296 /** {@hide} */
297 public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler,
298 final OnCloseListener listener) throws IOException {
Daichi Hirono91e3b502015-12-16 09:24:16 +0900299 if (handler == null) {
300 throw new IllegalArgumentException("Handler must not be null");
301 }
302 if (listener == null) {
303 throw new IllegalArgumentException("Listener must not be null");
304 }
305
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700306 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700307 final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
Jeff Brownb2a19852015-03-12 19:49:25 -0700308 final MessageQueue queue = handler.getLooper().getQueue();
Jeff Brown3f640522015-05-15 12:26:15 -0700309 queue.addOnFileDescriptorEventListener(comm[1],
310 OnFileDescriptorEventListener.EVENT_INPUT, new OnFileDescriptorEventListener() {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700311 @Override
312 public int onFileDescriptorEvents(FileDescriptor fd, int events) {
313 Status status = null;
Jeff Brown3f640522015-05-15 12:26:15 -0700314 if ((events & OnFileDescriptorEventListener.EVENT_INPUT) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700315 final byte[] buf = new byte[MAX_STATUS];
316 status = readCommStatus(fd, buf);
Jeff Brown3f640522015-05-15 12:26:15 -0700317 } else if ((events & OnFileDescriptorEventListener.EVENT_ERROR) != 0) {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700318 status = new Status(Status.DEAD);
319 }
320 if (status != null) {
Jeff Brown3f640522015-05-15 12:26:15 -0700321 queue.removeOnFileDescriptorEventListener(fd);
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700322 IoUtils.closeQuietly(fd);
323 listener.onClose(status.asIOException());
Jeff Brownb2a19852015-03-12 19:49:25 -0700324 return 0;
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700325 }
326 return EVENT_INPUT;
327 }
328 });
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700329
330 return pfd;
331 }
332
333 private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800334 final int flags = FileUtils.translateModePfdToPosix(mode) | ifAtLeastQ(O_CLOEXEC);
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600335
336 int realMode = S_IRWXU | S_IRWXG;
337 if ((mode & MODE_WORLD_READABLE) != 0) realMode |= S_IROTH;
338 if ((mode & MODE_WORLD_WRITEABLE) != 0) realMode |= S_IWOTH;
339
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700340 final String path = file.getPath();
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600341 try {
342 return Os.open(path, flags, realMode);
343 } catch (ErrnoException e) {
344 throw new FileNotFoundException(e.getMessage());
345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 }
347
348 /**
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700349 * Create a new ParcelFileDescriptor that is a dup of an 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 static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700355 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800356 final FileDescriptor fd = new FileDescriptor();
357 int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
358 fd.setInt$(intfd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700359 return new ParcelFileDescriptor(fd);
360 } catch (ErrnoException e) {
361 throw e.rethrowAsIOException();
362 }
Dianne Hackborne17aeb32011-04-07 15:11:57 -0700363 }
364
365 /**
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700366 * Create a new ParcelFileDescriptor that is a dup of the existing
367 * FileDescriptor. This obeys standard POSIX semantics, where the
368 * new file descriptor shared state such as file position with the
369 * original file descriptor.
370 */
371 public ParcelFileDescriptor dup() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700372 if (mWrapped != null) {
373 return mWrapped.dup();
374 } else {
375 return dup(getFileDescriptor());
376 }
Dianne Hackborn62f20ec2011-08-15 17:40:28 -0700377 }
378
379 /**
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700380 * Create a new ParcelFileDescriptor from a raw native fd. The new
381 * ParcelFileDescriptor holds a dup of the original fd passed in here,
382 * so you must still close that fd as well as the new ParcelFileDescriptor.
383 *
384 * @param fd The native fd that the ParcelFileDescriptor should dup.
385 *
386 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
387 * for a dup of the given fd.
388 */
389 public static ParcelFileDescriptor fromFd(int fd) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700390 final FileDescriptor original = new FileDescriptor();
391 original.setInt$(fd);
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700392
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700393 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800394 final FileDescriptor dup = new FileDescriptor();
395 int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
396 dup.setInt$(intfd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700397 return new ParcelFileDescriptor(dup);
398 } catch (ErrnoException e) {
399 throw e.rethrowAsIOException();
400 }
401 }
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700402
403 /**
404 * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
405 * The returned ParcelFileDescriptor now owns the given fd, and will be
Josh Gao4a646632019-03-08 11:22:21 -0800406 * responsible for closing it.
407 * <p>
408 * <strong>WARNING:</strong> You must not close the fd yourself after
409 * this call, and ownership of the file descriptor must have been
410 * released prior to the call to this function.
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700411 *
412 * @param fd The native fd that the ParcelFileDescriptor should adopt.
413 *
414 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
415 * for the given fd.
416 */
417 public static ParcelFileDescriptor adoptFd(int fd) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700418 final FileDescriptor fdesc = new FileDescriptor();
419 fdesc.setInt$(fd);
420
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700421 return new ParcelFileDescriptor(fdesc);
422 }
423
Dianne Hackbornea2117bd2011-05-20 10:37:34 -0700424 /**
425 * Create a new ParcelFileDescriptor from the specified Socket. The new
426 * ParcelFileDescriptor holds a dup of the original FileDescriptor in
427 * the Socket, so you must still close the Socket as well as the new
428 * ParcelFileDescriptor.
Josh Gao4a646632019-03-08 11:22:21 -0800429 * <p>
430 * <strong>WARNING:</strong> Prior to API level 29, this function would not
431 * actually dup the Socket's FileDescriptor, and would take a
432 * reference to the its internal FileDescriptor instead. If the Socket
433 * gets garbage collected before the ParcelFileDescriptor, this may
434 * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
435 * this, the following pattern can be used:
436 * <pre>{@code
437 * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket).dup();
438 * }</pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 *
440 * @param socket The Socket whose FileDescriptor is used to create
441 * a new ParcelFileDescriptor.
442 *
Josh Gaoe3589b22018-09-28 10:59:16 -0700443 * @return A new ParcelFileDescriptor with a duped copy of the
444 * FileDescriptor of the specified Socket.
445 *
446 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 */
448 public static ParcelFileDescriptor fromSocket(Socket socket) {
Elliott Hughes43907582011-04-12 14:25:23 -0700449 FileDescriptor fd = socket.getFileDescriptor$();
Josh Gaoe3589b22018-09-28 10:59:16 -0700450 try {
451 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
452 } catch (IOException e) {
453 throw new UncheckedIOException(e);
454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 }
456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 /**
Josh Gaoe3589b22018-09-28 10:59:16 -0700458 * Create a new ParcelFileDescriptor from the specified DatagramSocket. The
459 * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
460 * the DatagramSocket, so you must still close the DatagramSocket as well
461 * as the new ParcelFileDescriptor.
Josh Gao4a646632019-03-08 11:22:21 -0800462 * <p>
463 * <strong>WARNING:</strong> Prior to API level 29, this function would not
464 * actually dup the DatagramSocket's FileDescriptor, and would take a
465 * reference to the its internal FileDescriptor instead. If the DatagramSocket
466 * gets garbage collected before the ParcelFileDescriptor, this may
467 * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
468 * this, the following pattern can be used:
469 * <pre>{@code
470 * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket).dup();
471 * }</pre>
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700472 *
473 * @param datagramSocket The DatagramSocket whose FileDescriptor is used
474 * to create a new ParcelFileDescriptor.
475 *
Josh Gaoe3589b22018-09-28 10:59:16 -0700476 * @return A new ParcelFileDescriptor with a duped copy of the
477 * FileDescriptor of the specified Socket.
478 *
479 * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700480 */
481 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
482 FileDescriptor fd = datagramSocket.getFileDescriptor$();
Josh Gaoe3589b22018-09-28 10:59:16 -0700483 try {
484 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
485 } catch (IOException e) {
486 throw new UncheckedIOException(e);
487 }
Chia-chi Yeh47f8f0f2011-05-12 16:23:44 -0700488 }
489
490 /**
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700491 * Create two ParcelFileDescriptors structured as a data pipe. The first
492 * ParcelFileDescriptor in the returned array is the read side; the second
493 * is the write side.
494 */
495 public static ParcelFileDescriptor[] createPipe() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700496 try {
Nick Kralevich0c48b942018-12-17 14:24:22 -0800497 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700498 return new ParcelFileDescriptor[] {
499 new ParcelFileDescriptor(fds[0]),
500 new ParcelFileDescriptor(fds[1]) };
501 } catch (ErrnoException e) {
502 throw e.rethrowAsIOException();
503 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700504 }
505
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700506 /**
507 * Create two ParcelFileDescriptors structured as a data pipe. The first
508 * ParcelFileDescriptor in the returned array is the read side; the second
509 * is the write side.
510 * <p>
511 * The write end has the ability to deliver an error message through
512 * {@link #closeWithError(String)} which can be handled by the read end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700513 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700514 * This can also be used to detect remote crashes.
515 */
516 public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
517 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700518 final FileDescriptor[] comm = createCommSocketPair();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800519 final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700520 return new ParcelFileDescriptor[] {
521 new ParcelFileDescriptor(fds[0], comm[0]),
522 new ParcelFileDescriptor(fds[1], comm[1]) };
523 } catch (ErrnoException e) {
524 throw e.rethrowAsIOException();
525 }
526 }
527
528 /**
529 * Create two ParcelFileDescriptors structured as a pair of sockets
530 * connected to each other. The two sockets are indistinguishable.
531 */
532 public static ParcelFileDescriptor[] createSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800533 return createSocketPair(SOCK_STREAM);
534 }
535
536 /**
537 * @hide
538 */
539 public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700540 try {
541 final FileDescriptor fd0 = new FileDescriptor();
542 final FileDescriptor fd1 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800543 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700544 return new ParcelFileDescriptor[] {
545 new ParcelFileDescriptor(fd0),
546 new ParcelFileDescriptor(fd1) };
547 } catch (ErrnoException e) {
548 throw e.rethrowAsIOException();
549 }
550 }
551
552 /**
553 * Create two ParcelFileDescriptors structured as a pair of sockets
554 * connected to each other. The two sockets are indistinguishable.
555 * <p>
556 * Both ends have the ability to deliver an error message through
557 * {@link #closeWithError(String)} which can be detected by the other end
Amith Yamasanib433bb82013-09-18 15:10:16 -0700558 * calling {@link #checkError()}, usually after detecting an EOF.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700559 * This can also be used to detect remote crashes.
560 */
561 public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
Mike Lockwoodced0c252014-11-20 12:22:30 -0800562 return createReliableSocketPair(SOCK_STREAM);
563 }
564
565 /**
566 * @hide
567 */
568 public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700569 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700570 final FileDescriptor[] comm = createCommSocketPair();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700571 final FileDescriptor fd0 = new FileDescriptor();
572 final FileDescriptor fd1 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800573 Os.socketpair(AF_UNIX, type | ifAtLeastQ(SOCK_CLOEXEC), 0, fd0, fd1);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700574 return new ParcelFileDescriptor[] {
575 new ParcelFileDescriptor(fd0, comm[0]),
576 new ParcelFileDescriptor(fd1, comm[1]) };
577 } catch (ErrnoException e) {
578 throw e.rethrowAsIOException();
579 }
580 }
581
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700582 private static FileDescriptor[] createCommSocketPair() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700583 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700584 // Use SOCK_SEQPACKET so that we have a guarantee that the status
585 // is written and read atomically as one unit and is not split
586 // across multiple IO operations.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700587 final FileDescriptor comm1 = new FileDescriptor();
588 final FileDescriptor comm2 = new FileDescriptor();
Nick Kralevich0c48b942018-12-17 14:24:22 -0800589 Os.socketpair(AF_UNIX, SOCK_SEQPACKET | ifAtLeastQ(SOCK_CLOEXEC), 0, comm1, comm2);
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700590 IoUtils.setBlocking(comm1, false);
591 IoUtils.setBlocking(comm2, false);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700592 return new FileDescriptor[] { comm1, comm2 };
593 } catch (ErrnoException e) {
594 throw e.rethrowAsIOException();
595 }
596 }
Dianne Hackborn23fdaf62010-08-06 12:16:55 -0700597
598 /**
Dianne Hackborn540f86a2011-01-11 17:52:22 -0800599 * @hide Please use createPipe() or ContentProvider.openPipeHelper().
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100600 * Gets a file descriptor for a read-only copy of the given data.
601 *
602 * @param data Data to copy.
603 * @param name Name for the shared memory area that may back the file descriptor.
604 * This is purely informative and may be {@code null}.
605 * @return A ParcelFileDescriptor.
606 * @throws IOException if there is an error while creating the shared memory area.
607 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000608 @UnsupportedAppUsage
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800609 @Deprecated
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100610 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
611 if (data == null) return null;
612 MemoryFile file = new MemoryFile(name, data.length);
John Reck12ea937f2019-07-26 12:19:56 -0700613 try {
614 if (data.length > 0) {
615 file.writeBytes(data, 0, 0, data.length);
616 }
617 file.deactivate();
618 FileDescriptor fd = file.getFileDescriptor();
619 return fd != null ? ParcelFileDescriptor.dup(fd) : null;
620 } finally {
621 file.close();
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100622 }
Bjorn Bringerta006b4722010-04-14 14:43:26 +0100623 }
624
625 /**
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700626 * Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
627 * with {@link #open}.
628 * <p>
Garfield Tanaf03e5a2017-05-15 14:19:11 -0700629 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw"
630 * or "rwt".
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700631 * @return A bitmask representing the given file mode.
632 * @throws IllegalArgumentException if the given string does not match a known file mode.
633 */
634 public static int parseMode(String mode) {
Jeff Sharkey63280e02018-09-12 11:47:07 -0600635 return FileUtils.translateModePosixToPfd(FileUtils.translateModeStringToPosix(mode));
Adam Lesinskieb8c3f92013-09-20 14:08:25 -0700636 }
637
638 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700639 * Return the filesystem path of the real file on disk that is represented
640 * by the given {@link FileDescriptor}.
641 *
642 * @hide
643 */
Jeff Sharkeycb269aac2019-01-25 11:15:38 -0700644 @TestApi
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700645 public static File getFile(FileDescriptor fd) throws IOException {
646 try {
647 final String path = Os.readlink("/proc/self/fd/" + fd.getInt$());
Zim42f1e9f2019-08-15 17:35:00 +0100648 if (OsConstants.S_ISREG(Os.stat(path).st_mode)
649 || OsConstants.S_ISCHR(Os.stat(path).st_mode)) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700650 return new File(path);
651 } else {
Zim42f1e9f2019-08-15 17:35:00 +0100652 throw new IOException("Not a regular file or character device: " + path);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700653 }
654 } catch (ErrnoException e) {
655 throw e.rethrowAsIOException();
656 }
657 }
658
659 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 * Retrieve the actual FileDescriptor associated with this object.
Elliott Hughes43907582011-04-12 14:25:23 -0700661 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 * @return Returns the FileDescriptor associated with this object.
663 */
664 public FileDescriptor getFileDescriptor() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700665 if (mWrapped != null) {
666 return mWrapped.getFileDescriptor();
667 } else {
668 return mFd;
669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 }
Elliott Hughes43907582011-04-12 14:25:23 -0700671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700673 * Return the total size of the file representing this fd, as determined by
674 * {@code stat()}. Returns -1 if the fd is not a file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 */
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700676 public long getStatSize() {
677 if (mWrapped != null) {
678 return mWrapped.getStatSize();
679 } else {
680 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700681 final StructStat st = Os.fstat(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700682 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
683 return st.st_size;
684 } else {
685 return -1;
686 }
687 } catch (ErrnoException e) {
688 Log.w(TAG, "fstat() failed: " + e);
689 return -1;
690 }
691 }
692 }
Elliott Hughes43907582011-04-12 14:25:23 -0700693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 /**
695 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
696 * and I really don't think we want it to be public.
697 * @hide
698 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000699 @UnsupportedAppUsage
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700700 public long seekTo(long pos) throws IOException {
701 if (mWrapped != null) {
702 return mWrapped.seekTo(pos);
703 } else {
704 try {
Elliott Hughes34385d32014-04-28 11:11:32 -0700705 return Os.lseek(mFd, pos, SEEK_SET);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700706 } catch (ErrnoException e) {
707 throw e.rethrowAsIOException();
708 }
709 }
710 }
Elliott Hughes43907582011-04-12 14:25:23 -0700711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 /**
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800713 * Return the native fd int for this ParcelFileDescriptor. The
714 * ParcelFileDescriptor still owns the fd, and it still must be closed
715 * through this API.
Josh Gao4a646632019-03-08 11:22:21 -0800716 * <p>
717 * <strong>WARNING:</strong> Do not call close on the return value of this
718 * function or pass it to a function that assumes ownership of the fd.
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800719 */
720 public int getFd() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700721 if (mWrapped != null) {
722 return mWrapped.getFd();
723 } else {
724 if (mClosed) {
725 throw new IllegalStateException("Already closed");
726 }
727 return mFd.getInt$();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800728 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800729 }
Elliott Hughes43907582011-04-12 14:25:23 -0700730
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800731 /**
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700732 * Return the native fd int for this ParcelFileDescriptor and detach it from
733 * the object here. You are now responsible for closing the fd in native
734 * code.
735 * <p>
736 * You should not detach when the original creator of the descriptor is
737 * expecting a reliable signal through {@link #close()} or
738 * {@link #closeWithError(String)}.
739 *
740 * @see #canDetectErrors()
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800741 */
742 public int detachFd() {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800743 if (mWrapped != null) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700744 return mWrapped.detachFd();
745 } else {
746 if (mClosed) {
747 throw new IllegalStateException("Already closed");
748 }
Josh Gao5ada8732018-06-26 14:20:29 -0700749 int fd = IoUtils.acquireRawFd(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700750 writeCommStatusAndClose(Status.DETACHED, null);
Makoto Onukib30ad6f2015-06-11 12:34:22 -0700751 mClosed = true;
752 mGuard.close();
753 releaseResources();
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800754 return fd;
755 }
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800756 }
Elliott Hughes43907582011-04-12 14:25:23 -0700757
Dianne Hackbornc9119f52011-02-28 18:03:26 -0800758 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 * Close the ParcelFileDescriptor. This implementation closes the underlying
760 * OS resources allocated to represent this stream.
Elliott Hughes43907582011-04-12 14:25:23 -0700761 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 * @throws IOException
763 * If an error occurs attempting to close this ParcelFileDescriptor.
764 */
Jeff Sharkey7407c942012-11-12 13:42:49 -0800765 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 public void close() throws IOException {
Jeff Sharkey7407c942012-11-12 13:42:49 -0800767 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700768 try {
769 mWrapped.close();
770 } finally {
771 releaseResources();
772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700774 closeWithStatus(Status.OK, null);
775 }
776 }
777
778 /**
779 * Close the ParcelFileDescriptor, informing any peer that an error occurred
780 * while processing. If the creator of this descriptor is not observing
781 * errors, it will close normally.
782 *
783 * @param msg describing the error; must not be null.
784 */
785 public void closeWithError(String msg) throws IOException {
786 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -0700787 try {
788 mWrapped.closeWithError(msg);
789 } finally {
790 releaseResources();
791 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700792 } else {
793 if (msg == null) {
794 throw new IllegalArgumentException("Message must not be null");
795 }
796 closeWithStatus(Status.ERROR, msg);
797 }
798 }
799
Amith Yamasani487c11a2013-09-18 09:16:15 -0700800 private void closeWithStatus(int status, String msg) {
801 if (mClosed) return;
802 mClosed = true;
Andreas Gampe009b8522017-10-10 08:01:38 -0700803 if (mGuard != null) {
804 mGuard.close();
805 }
Amith Yamasani487c11a2013-09-18 09:16:15 -0700806 // Status MUST be sent before closing actual descriptor
807 writeCommStatusAndClose(status, msg);
808 IoUtils.closeQuietly(mFd);
809 releaseResources();
810 }
811
812 /**
813 * Called when the fd is being closed, for subclasses to release any other resources
814 * associated with it, such as acquired providers.
815 * @hide
816 */
817 public void releaseResources() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700818 }
819
820 private byte[] getOrCreateStatusBuffer() {
821 if (mStatusBuf == null) {
822 mStatusBuf = new byte[MAX_STATUS];
823 }
824 return mStatusBuf;
825 }
826
827 private void writeCommStatusAndClose(int status, String msg) {
828 if (mCommFd == null) {
829 // Not reliable, or someone already sent status
830 if (msg != null) {
831 Log.w(TAG, "Unable to inform peer: " + msg);
832 }
833 return;
834 }
835
836 if (status == Status.DETACHED) {
837 Log.w(TAG, "Peer expected signal when closed; unable to deliver after detach");
838 }
839
840 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700841 if (status == Status.SILENCE) return;
842
843 // Since we're about to close, read off any remote status. It's
844 // okay to remember missing here.
845 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
846
847 // Skip writing status when other end has already gone away.
848 if (mStatus != null) return;
849
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700850 try {
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700851 final byte[] buf = getOrCreateStatusBuffer();
852 int writePtr = 0;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700853
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700854 Memory.pokeInt(buf, writePtr, status, ByteOrder.BIG_ENDIAN);
855 writePtr += 4;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700856
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700857 if (msg != null) {
858 final byte[] rawMsg = msg.getBytes();
859 final int len = Math.min(rawMsg.length, buf.length - writePtr);
860 System.arraycopy(rawMsg, 0, buf, writePtr, len);
861 writePtr += len;
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700862 }
Jeff Sharkeyd99f9ca2013-10-25 10:22:18 -0700863
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700864 // Must write the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700865 Os.write(mCommFd, buf, 0, writePtr);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700866 } catch (ErrnoException e) {
867 // Reporting status is best-effort
868 Log.w(TAG, "Failed to report status: " + e);
Neil Fuller43582df2014-04-11 17:29:54 +0100869 } catch (InterruptedIOException e) {
870 // Reporting status is best-effort
871 Log.w(TAG, "Failed to report status: " + e);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700872 }
873
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700874 } finally {
875 IoUtils.closeQuietly(mCommFd);
876 mCommFd = null;
877 }
878 }
879
880 private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
881 try {
Jeff Brown6fd9f9a2015-03-12 19:45:47 -0700882 // Must read the entire status as a single operation.
Elliott Hughes34385d32014-04-28 11:11:32 -0700883 final int n = Os.read(comm, buf, 0, buf.length);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700884 if (n == 0) {
885 // EOF means they're dead
886 return new Status(Status.DEAD);
887 } else {
888 final int status = Memory.peekInt(buf, 0, ByteOrder.BIG_ENDIAN);
889 if (status == Status.ERROR) {
890 final String msg = new String(buf, 4, n - 4);
891 return new Status(status, msg);
892 }
893 return new Status(status);
894 }
895 } catch (ErrnoException e) {
896 if (e.errno == OsConstants.EAGAIN) {
897 // Remote is still alive, but no status written yet
898 return null;
899 } else {
900 Log.d(TAG, "Failed to read status; assuming dead: " + e);
901 return new Status(Status.DEAD);
902 }
Neil Fuller43582df2014-04-11 17:29:54 +0100903 } catch (InterruptedIOException e) {
904 Log.d(TAG, "Failed to read status; assuming dead: " + e);
905 return new Status(Status.DEAD);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700906 }
907 }
908
909 /**
910 * Indicates if this ParcelFileDescriptor can communicate and detect remote
911 * errors/crashes.
912 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700913 * @see #checkError()
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700914 */
915 public boolean canDetectErrors() {
916 if (mWrapped != null) {
917 return mWrapped.canDetectErrors();
918 } else {
919 return mCommFd != null;
920 }
921 }
922
923 /**
924 * Detect and throw if the other end of a pipe or socket pair encountered an
925 * error or crashed. This allows a reader to distinguish between a valid EOF
926 * and an error/crash.
927 * <p>
928 * If this ParcelFileDescriptor is unable to detect remote errors, it will
929 * return silently.
930 *
Amith Yamasanib433bb82013-09-18 15:10:16 -0700931 * @throws IOException for normal errors.
932 * @throws FileDescriptorDetachedException
933 * if the remote side called {@link #detachFd()}. Once detached, the remote
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700934 * side is unable to communicate any errors through
Amith Yamasanib433bb82013-09-18 15:10:16 -0700935 * {@link #closeWithError(String)}.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700936 * @see #canDetectErrors()
937 */
Amith Yamasanib433bb82013-09-18 15:10:16 -0700938 public void checkError() throws IOException {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700939 if (mWrapped != null) {
Amith Yamasanib433bb82013-09-18 15:10:16 -0700940 mWrapped.checkError();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700941 } else {
942 if (mStatus == null) {
943 if (mCommFd == null) {
944 Log.w(TAG, "Peer didn't provide a comm channel; unable to check for errors");
945 return;
946 }
947
948 // Try reading status; it might be null if nothing written yet.
949 // Either way, we keep comm open to write our status later.
950 mStatus = readCommStatus(mCommFd, getOrCreateStatusBuffer());
951 }
952
Amith Yamasanib433bb82013-09-18 15:10:16 -0700953 if (mStatus == null || mStatus.status == Status.OK) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700954 // No status yet, or everything is peachy!
955 return;
956 } else {
957 throw mStatus.asIOException();
958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
960 }
Elliott Hughes43907582011-04-12 14:25:23 -0700961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 /**
963 * An InputStream you can create on a ParcelFileDescriptor, which will
964 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -0700965 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 */
967 public static class AutoCloseInputStream extends FileInputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700968 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -0700969
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -0700970 public AutoCloseInputStream(ParcelFileDescriptor pfd) {
971 super(pfd.getFileDescriptor());
972 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
974
975 @Override
976 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700977 try {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700978 super.close();
Josh Gao401fb242018-11-09 13:40:53 -0800979 } finally {
980 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -0700981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 }
Tomasz Mikolajewskiad3b6162016-05-30 10:17:08 +0900983
984 @Override
985 public int read() throws IOException {
986 final int result = super.read();
987 if (result == -1 && mPfd.canDetectErrors()) {
988 // Check for errors only on EOF, to minimize overhead.
989 mPfd.checkError();
990 }
991 return result;
992 }
993
994 @Override
995 public int read(byte[] b) throws IOException {
996 final int result = super.read(b);
997 if (result == -1 && mPfd.canDetectErrors()) {
998 mPfd.checkError();
999 }
1000 return result;
1001 }
1002
1003 @Override
1004 public int read(byte[] b, int off, int len) throws IOException {
1005 final int result = super.read(b, off, len);
1006 if (result == -1 && mPfd.canDetectErrors()) {
1007 mPfd.checkError();
1008 }
1009 return result;
1010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 }
Elliott Hughes43907582011-04-12 14:25:23 -07001012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 /**
1014 * An OutputStream you can create on a ParcelFileDescriptor, which will
1015 * take care of calling {@link ParcelFileDescriptor#close
Christopher Tatefa9e7c02010-05-06 12:07:10 -07001016 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 */
1018 public static class AutoCloseOutputStream extends FileOutputStream {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001019 private final ParcelFileDescriptor mPfd;
Elliott Hughes43907582011-04-12 14:25:23 -07001020
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001021 public AutoCloseOutputStream(ParcelFileDescriptor pfd) {
1022 super(pfd.getFileDescriptor());
1023 mPfd = pfd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 }
1025
1026 @Override
1027 public void close() throws IOException {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -07001028 try {
Brian Carlstromfd9ddd12010-11-04 11:24:58 -07001029 super.close();
Josh Gao401fb242018-11-09 13:40:53 -08001030 } finally {
1031 mPfd.close();
Brian Carlstromfd9ddd12010-11-04 11:24:58 -07001032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 }
1034 }
Elliott Hughes43907582011-04-12 14:25:23 -07001035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 @Override
1037 public String toString() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001038 if (mWrapped != null) {
1039 return mWrapped.toString();
1040 } else {
1041 return "{ParcelFileDescriptor: " + mFd + "}";
1042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 }
Elliott Hughes43907582011-04-12 14:25:23 -07001044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 @Override
1046 protected void finalize() throws Throwable {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001047 if (mWrapped != null) {
1048 releaseResources();
1049 }
Jeff Sharkey7407c942012-11-12 13:42:49 -08001050 if (mGuard != null) {
1051 mGuard.warnIfOpen();
1052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 try {
1054 if (!mClosed) {
Hans Boehm339d4472019-05-30 15:48:17 -07001055 // mWrapped was and is null.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001056 closeWithStatus(Status.LEAKED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 }
1058 } finally {
1059 super.finalize();
1060 }
1061 }
Elliott Hughes43907582011-04-12 14:25:23 -07001062
Jeff Sharkey7407c942012-11-12 13:42:49 -08001063 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 public int describeContents() {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001065 if (mWrapped != null) {
1066 return mWrapped.describeContents();
1067 } else {
1068 return Parcelable.CONTENTS_FILE_DESCRIPTOR;
1069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071
Dan Egnorb3e4ef32010-07-20 09:03:35 -07001072 /**
1073 * {@inheritDoc}
1074 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
1075 * the file descriptor will be closed after a copy is written to the Parcel.
1076 */
Jeff Sharkey7407c942012-11-12 13:42:49 -08001077 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 public void writeToParcel(Parcel out, int flags) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001079 if (mWrapped != null) {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001080 try {
1081 mWrapped.writeToParcel(out, flags);
1082 } finally {
1083 releaseResources();
1084 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001085 } else {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001086 if (mCommFd != null) {
1087 out.writeInt(1);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001088 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001089 out.writeFileDescriptor(mCommFd);
1090 } else {
1091 out.writeInt(0);
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001092 out.writeFileDescriptor(mFd);
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001093 }
1094 if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
Amith Yamasani487c11a2013-09-18 09:16:15 -07001095 // Not a real close, so emit no status
1096 closeWithStatus(Status.SILENCE, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 }
1098 }
1099 }
1100
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001101 public static final @android.annotation.NonNull Parcelable.Creator<ParcelFileDescriptor> CREATOR
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 = new Parcelable.Creator<ParcelFileDescriptor>() {
Jeff Sharkey7407c942012-11-12 13:42:49 -08001103 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 public ParcelFileDescriptor createFromParcel(Parcel in) {
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001105 int hasCommChannel = in.readInt();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001106 final FileDescriptor fd = in.readRawFileDescriptor();
1107 FileDescriptor commChannel = null;
Tim Kilbourn4bf27b52015-06-02 15:57:45 -07001108 if (hasCommChannel != 0) {
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001109 commChannel = in.readRawFileDescriptor();
1110 }
1111 return new ParcelFileDescriptor(fd, commChannel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 }
Jeff Sharkey7407c942012-11-12 13:42:49 -08001113
1114 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 public ParcelFileDescriptor[] newArray(int size) {
1116 return new ParcelFileDescriptor[size];
1117 }
1118 };
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001119
1120 /**
1121 * Callback indicating that a ParcelFileDescriptor has been closed.
1122 */
1123 public interface OnCloseListener {
1124 /**
1125 * Event indicating the ParcelFileDescriptor to which this listener was
1126 * attached has been closed.
1127 *
1128 * @param e error state, or {@code null} if closed cleanly.
Amith Yamasanib433bb82013-09-18 15:10:16 -07001129 * If the close event was the result of
1130 * {@link ParcelFileDescriptor#detachFd()}, this will be a
1131 * {@link FileDescriptorDetachedException}. After detach the
1132 * remote side may continue reading/writing to the underlying
1133 * {@link FileDescriptor}, but they can no longer deliver
1134 * reliable close/error events.
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001135 */
Amith Yamasanib433bb82013-09-18 15:10:16 -07001136 public void onClose(IOException e);
1137 }
1138
1139 /**
1140 * Exception that indicates that the file descriptor was detached.
1141 */
1142 public static class FileDescriptorDetachedException extends IOException {
1143
1144 private static final long serialVersionUID = 0xDe7ac4edFdL;
1145
1146 public FileDescriptorDetachedException() {
1147 super("Remote side is detached");
1148 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001149 }
1150
1151 /**
1152 * Internal class representing a remote status read by
1153 * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}.
Steven Moreland3de571e2018-11-12 19:44:23 -08001154 *
1155 * Warning: this must be kept in sync with ParcelFileDescriptorStatus at
1156 * frameworks/native/libs/binder/Parcel.cpp
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001157 */
1158 private static class Status {
1159 /** Special value indicating remote side died. */
1160 public static final int DEAD = -2;
1161 /** Special value indicating no status should be written. */
1162 public static final int SILENCE = -1;
1163
1164 /** Remote reported that everything went better than expected. */
1165 public static final int OK = 0;
1166 /** Remote reported error; length and message follow. */
1167 public static final int ERROR = 1;
1168 /** Remote reported {@link #detachFd()} and went rogue. */
1169 public static final int DETACHED = 2;
1170 /** Remote reported their object was finalized. */
1171 public static final int LEAKED = 3;
1172
1173 public final int status;
1174 public final String msg;
1175
1176 public Status(int status) {
1177 this(status, null);
1178 }
1179
1180 public Status(int status, String msg) {
1181 this.status = status;
1182 this.msg = msg;
1183 }
1184
1185 public IOException asIOException() {
1186 switch (status) {
1187 case DEAD:
1188 return new IOException("Remote side is dead");
1189 case OK:
1190 return null;
1191 case ERROR:
1192 return new IOException("Remote error: " + msg);
1193 case DETACHED:
Amith Yamasanib433bb82013-09-18 15:10:16 -07001194 return new FileDescriptorDetachedException();
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001195 case LEAKED:
1196 return new IOException("Remote side was leaked");
1197 default:
1198 return new IOException("Unknown status: " + status);
1199 }
1200 }
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001201
1202 @Override
Jeff Brown6fd9f9a2015-03-12 19:45:47 -07001203 public String toString() {
1204 return "{" + status + ": " + msg + "}";
Jeff Sharkeyda5a3e12013-08-11 12:54:42 -07001205 }
1206 }
Nick Kralevich0c48b942018-12-17 14:24:22 -08001207
1208 private static boolean isAtLeastQ() {
1209 return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q);
1210 }
1211
1212 private static int ifAtLeastQ(int value) {
1213 return isAtLeastQ() ? value : 0;
1214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215}