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},