am 5c8caba2: am 1b144e62: Merge "Add ParcelFileDescriptor.fromFd() and .adoptFd()." into honeycomb-mr2

* commit '5c8caba2e590792531ffb2c9f4ea924993662abd':
  Add ParcelFileDescriptor.fromFd() and .adoptFd().
diff --git a/api/current.xml b/api/current.xml
index e334322..af8ec6c 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -150314,6 +150314,19 @@
 <parameter name="descriptor" type="android.os.ParcelFileDescriptor">
 </parameter>
 </constructor>
+<method name="adoptFd"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="int">
+</parameter>
+</method>
 <method name="close"
  return="void"
  abstract="false"
@@ -150377,6 +150390,21 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="fromFd"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="int">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
 <method name="fromSocket"
  return="android.os.ParcelFileDescriptor"
  abstract="false"
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index aa959b4..0f1354b 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -128,7 +128,46 @@
     }
 
     /**
-     * Create a new ParcelFileDescriptor from the specified Socket.
+     * Create a new ParcelFileDescriptor from a raw native fd.  The new
+     * ParcelFileDescriptor holds a dup of the original fd passed in here,
+     * so you must still close that fd as well as the new ParcelFileDescriptor.
+     *
+     * @param fd The native fd that the ParcelFileDescriptor should dup.
+     *
+     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
+     * for a dup of the given fd.
+     */
+    public static ParcelFileDescriptor fromFd(int fd) throws IOException {
+        FileDescriptor fdesc = getFileDescriptorFromFd(fd);
+        return new ParcelFileDescriptor(fdesc);
+    }
+
+    // Extracts the file descriptor from the specified socket and returns it untouched
+    private static native FileDescriptor getFileDescriptorFromFd(int fd) throws IOException;
+
+    /**
+     * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
+     * The returned ParcelFileDescriptor now owns the given fd, and will be
+     * responsible for closing it.  You must not close the fd yourself.
+     *
+     * @param fd The native fd that the ParcelFileDescriptor should adopt.
+     *
+     * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
+     * for the given fd.
+     */
+    public static ParcelFileDescriptor adoptFd(int fd) {
+        FileDescriptor fdesc = getFileDescriptorFromFdNoDup(fd);
+        return new ParcelFileDescriptor(fdesc);
+    }
+
+    // Extracts the file descriptor from the specified socket and returns it untouched
+    private static native FileDescriptor getFileDescriptorFromFdNoDup(int fd);
+
+    /**
+     * Create a new ParcelFileDescriptor from the specified Socket.  The new
+     * ParcelFileDescriptor holds a dup of the original FileDescriptor in
+     * the Socket, so you must still close the Socket as well as the new
+     * ParcelFileDescriptor.
      *
      * @param socket The Socket whose FileDescriptor is used to create
      *               a new ParcelFileDescriptor.
@@ -151,17 +190,14 @@
      */
     public static ParcelFileDescriptor[] createPipe() throws IOException {
         FileDescriptor[] fds = new FileDescriptor[2];
-        int res = createPipeNative(fds);
-        if (res == 0) {
-            ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
-            pfds[0] = new ParcelFileDescriptor(fds[0]);
-            pfds[1] = new ParcelFileDescriptor(fds[1]);
-            return pfds;
-        }
-        throw new IOException("Unable to create pipe: errno=" + -res);
+        createPipeNative(fds);
+        ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
+        pfds[0] = new ParcelFileDescriptor(fds[0]);
+        pfds[1] = new ParcelFileDescriptor(fds[1]);
+        return pfds;
     }
 
-    private static native int createPipeNative(FileDescriptor[] outFds);
+    private static native void createPipeNative(FileDescriptor[] outFds) throws IOException;
 
     /**
      * @hide Please use createPipe() or ContentProvider.openPipeHelper().
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index 1f737f9..e73d30b 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -52,6 +52,33 @@
     jfieldID mFileDescriptor;
 } gParcelFileDescriptorOffsets;
 
+static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFd(JNIEnv* env,
+    jobject clazz, jint origfd)
+{
+    int fd = dup(origfd);
+    if (fd < 0) {
+        jniThrowException(env, "java/io/IOException", strerror(errno));
+        return NULL;
+    }
+    jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
+        gFileDescriptorOffsets.mConstructor);
+    if (fileDescriptorClone != NULL) {
+        env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, fd);
+    }
+    return fileDescriptorClone;
+}
+
+static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup(JNIEnv* env,
+    jobject clazz, jint fd)
+{
+    jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
+        gFileDescriptorOffsets.mConstructor);
+    if (fileDescriptorClone != NULL) {
+        env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, fd);
+    }
+    return fileDescriptorClone;
+}
+
 static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
     jobject clazz, jobject object)
 {
@@ -61,17 +88,20 @@
     jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
         gFileDescriptorOffsets.mConstructor);
     if (fileDescriptorClone != NULL) {
+        // XXXX need to throw an exception if the dup fails!
         env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, dup(fd));
     }
     return fileDescriptorClone;
 }
 
-static int android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
+static void android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
     jobject clazz, jobjectArray outFds)
 {
     int fds[2];
     if (pipe(fds) < 0) {
-        return -errno;
+        int therr = errno;
+        jniThrowException(env, "java/io/IOException", strerror(therr));
+        return;
     }
 
     for (int i=0; i<2; i++) {
@@ -82,8 +112,6 @@
         }
         env->SetObjectArrayElement(outFds, i, fdObj);
     }
-
-    return 0;
 }
 
 static jint getFd(JNIEnv* env, jobject clazz)
@@ -138,9 +166,13 @@
 }
 
 static const JNINativeMethod gParcelFileDescriptorMethods[] = {
+    {"getFileDescriptorFromFd", "(I)Ljava/io/FileDescriptor;",
+        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFd},
+    {"getFileDescriptorFromFdNoDup", "(I)Ljava/io/FileDescriptor;",
+        (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromFdNoDup},
     {"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
         (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
-    {"createPipeNative", "([Ljava/io/FileDescriptor;)I",
+    {"createPipeNative", "([Ljava/io/FileDescriptor;)V",
         (void*)android_os_ParcelFileDescriptor_createPipeNative},
     {"getStatSize", "()J",
         (void*)android_os_ParcelFileDescriptor_getStatSize},