Add ParcelFileDescriptor APIs to get raw fd.
Change-Id: I66ba72ffffd27237e60c9411453eef950ae62705
diff --git a/api/current.xml b/api/current.xml
index 2c97892..c007659 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -149691,6 +149691,17 @@
visibility="public"
>
</method>
+<method name="detachFd"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="fromSocket"
return="android.os.ParcelFileDescriptor"
abstract="false"
@@ -149704,6 +149715,17 @@
<parameter name="socket" type="java.net.Socket">
</parameter>
</method>
+<method name="getFd"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFileDescriptor"
return="java.io.FileDescriptor"
abstract="false"
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 8944f12..eca34848 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1385,6 +1385,7 @@
int mode) throws FileNotFoundException;
/*package*/ static native void closeFileDescriptor(FileDescriptor desc)
throws IOException;
+ /*package*/ static native void clearFileDescriptor(FileDescriptor desc);
/**
* Read a byte value from the parcel at the current dataPosition().
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 3a5d26b..5bd129f 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -197,6 +197,40 @@
public native long seekTo(long pos);
/**
+ * Return the native fd int for this ParcelFileDescriptor. The
+ * ParcelFileDescriptor still owns the fd, and it still must be closed
+ * through this API.
+ */
+ public int getFd() {
+ if (mClosed) {
+ throw new IllegalStateException("Already closed");
+ }
+ return getFdNative();
+ }
+
+ private native int getFdNative();
+
+ /**
+ * Return the native fd int for this ParcelFileDescriptor and detach it
+ * from the object here. You are now responsible for closing the fd in
+ * native code.
+ */
+ public int detachFd() {
+ if (mClosed) {
+ throw new IllegalStateException("Already closed");
+ }
+ if (mParcelDescriptor != null) {
+ int fd = mParcelDescriptor.detachFd();
+ mClosed = true;
+ return fd;
+ }
+ int fd = getFd();
+ mClosed = true;
+ Parcel.clearFileDescriptor(mFileDescriptor);
+ return fd;
+ }
+
+ /**
* Close the ParcelFileDescriptor. This implementation closes the underlying
* OS resources allocated to represent this stream.
*
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index eceef1c..1f737f9 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -126,6 +126,17 @@
return lseek(fd, pos, SEEK_SET);
}
+static jlong android_os_ParcelFileDescriptor_getFdNative(JNIEnv* env, jobject clazz)
+{
+ jint fd = getFd(env, clazz);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
+ return -1;
+ }
+
+ return fd;
+}
+
static const JNINativeMethod gParcelFileDescriptorMethods[] = {
{"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
(void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
@@ -134,7 +145,9 @@
{"getStatSize", "()J",
(void*)android_os_ParcelFileDescriptor_getStatSize},
{"seekTo", "(J)J",
- (void*)android_os_ParcelFileDescriptor_seekTo}
+ (void*)android_os_ParcelFileDescriptor_seekTo},
+ {"getFdNative", "()I",
+ (void*)android_os_ParcelFileDescriptor_getFdNative}
};
const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor";
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 7226e31..15362eb 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1520,6 +1520,14 @@
}
}
+static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
+{
+ int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+ if (fd >= 0) {
+ env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
+ }
+}
+
static void android_os_Parcel_freeBuffer(JNIEnv* env, jobject clazz)
{
int32_t own = env->GetIntField(clazz, gParcelOffsets.mOwnObject);
@@ -1719,6 +1727,7 @@
{"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
{"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
{"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
+ {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
{"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer},
{"init", "(I)V", (void*)android_os_Parcel_init},
{"destroy", "()V", (void*)android_os_Parcel_destroy},