Add mechanism for Parcel to not allow FDs to be written to it.

This is to help implement issue #5224703.

Change-Id: I026a5890495537d15b57fe61227a640aac806d46
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 034e3c7..4a144a2 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3246,6 +3246,7 @@
         try {
             String resolvedType = null;
             if (fillInIntent != null) {
+                fillInIntent.setAllowFds(false);
                 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -3370,6 +3371,7 @@
         if (mParent == null) {
             int result = IActivityManager.START_RETURN_INTENT_TO_CALLER;
             try {
+                intent.setAllowFds(false);
                 result = ActivityManagerNative.getDefault()
                     .startActivity(mMainThread.getApplicationThread(),
                             intent, intent.resolveTypeIfNeeded(
@@ -3419,6 +3421,7 @@
     public boolean startNextMatchingActivity(Intent intent) {
         if (mParent == null) {
             try {
+                intent.setAllowFds(false);
                 return ActivityManagerNative.getDefault()
                     .startNextMatchingActivity(mToken, intent);
             } catch (RemoteException e) {
@@ -3692,6 +3695,9 @@
             }
             if (false) Log.v(TAG, "Finishing self: token=" + mToken);
             try {
+                if (resultData != null) {
+                    resultData.setAllowFds(false);
+                }
                 if (ActivityManagerNative.getDefault()
                     .finishActivity(mToken, resultCode, resultData)) {
                     mFinished = true;
@@ -3812,6 +3818,7 @@
             int flags) {
         String packageName = getPackageName();
         try {
+            data.setAllowFds(false);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                         IActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0776e10..99aae37 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2674,6 +2674,7 @@
             // Next have the activity save its current state and managed dialogs...
             if (!r.activity.mFinished && saveState) {
                 state = new Bundle();
+                state.setAllowFds(false);
                 mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
                 r.state = state;
             }
@@ -2775,6 +2776,7 @@
             if (!r.activity.mFinished && saveState) {
                 if (r.state == null) {
                     state = new Bundle();
+                    state.setAllowFds(false);
                     mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
                     r.state = state;
                 } else {
@@ -3306,6 +3308,7 @@
         }
         if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
             r.state = new Bundle();
+            r.state.setAllowFds(false);
             mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
         }
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2139704..2bf1fb7 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -874,6 +874,7 @@
         try {
             String resolvedType = null;
             if (fillInIntent != null) {
+                fillInIntent.setAllowFds(false);
                 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -892,6 +893,7 @@
     public void sendBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
+            intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, false, false);
@@ -903,6 +905,7 @@
     public void sendBroadcast(Intent intent, String receiverPermission) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
+            intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, receiverPermission, false, false);
@@ -915,6 +918,7 @@
             String receiverPermission) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
+            intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, receiverPermission, true, false);
@@ -946,6 +950,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
+            intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, receiverPermission,
@@ -958,6 +963,7 @@
     public void sendStickyBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
+            intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, false, true);
@@ -989,6 +995,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
+            intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
@@ -1005,6 +1012,7 @@
             intent.setDataAndType(intent.getData(), resolvedType);
         }
         try {
+            intent.setAllowFds(false);
             ActivityManagerNative.getDefault().unbroadcastIntent(
                 mMainThread.getApplicationThread(), intent);
         } catch (RemoteException e) {
@@ -1069,6 +1077,7 @@
     @Override
     public ComponentName startService(Intent service) {
         try {
+            service.setAllowFds(false);
             ComponentName cn = ActivityManagerNative.getDefault().startService(
                 mMainThread.getApplicationThread(), service,
                 service.resolveTypeIfNeeded(getContentResolver()));
@@ -1086,6 +1095,7 @@
     @Override
     public boolean stopService(Intent service) {
         try {
+            service.setAllowFds(false);
             int res = ActivityManagerNative.getDefault().stopService(
                 mMainThread.getApplicationThread(), service,
                 service.resolveTypeIfNeeded(getContentResolver()));
@@ -1116,6 +1126,7 @@
                     < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                 flags |= BIND_WAIVE_PRIORITY;
             }
+            service.setAllowFds(false);
             int res = ActivityManagerNative.getDefault().bindService(
                 mMainThread.getApplicationThread(), getActivityToken(),
                 service, service.resolveTypeIfNeeded(getContentResolver()),
@@ -1148,6 +1159,9 @@
     public boolean startInstrumentation(ComponentName className,
             String profileFile, Bundle arguments) {
         try {
+            if (arguments != null) {
+                arguments.setAllowFds(false);
+            }
             return ActivityManagerNative.getDefault().startInstrumentation(
                     className, profileFile, 0, arguments, null);
         } catch (RemoteException e) {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index f3bc495..d7f5c55 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1375,6 +1375,7 @@
             }
         }
         try {
+            intent.setAllowFds(false);
             int result = ActivityManagerNative.getDefault()
                 .startActivity(whoThread, intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1415,6 +1416,7 @@
         try {
             String[] resolvedTypes = new String[intents.length];
             for (int i=0; i<intents.length; i++) {
+                intents[i].setAllowFds(false);
                 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -1471,6 +1473,7 @@
             }
         }
         try {
+            intent.setAllowFds(false);
             int result = ActivityManagerNative.getDefault()
                 .startActivity(whoThread, intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 2549c84..522f477 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -661,6 +661,9 @@
                             "Finishing broadcast to unregistered receiver");
                     IActivityManager mgr = ActivityManagerNative.getDefault();
                     try {
+                        if (extras != null) {
+                            extras.setAllowFds(false);
+                        }
                         mgr.finishReceiver(this, resultCode, data, extras, false);
                     } catch (RemoteException e) {
                         Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index b4827cb..b0637a7 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -192,6 +192,7 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
+            intent.setAllowFds(false);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     IActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -249,6 +250,7 @@
         String packageName = context.getPackageName();
         String[] resolvedTypes = new String[intents.length];
         for (int i=0; i<intents.length; i++) {
+            intents[i].setAllowFds(false);
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
         try {
@@ -287,6 +289,7 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
+            intent.setAllowFds(false);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     IActivityManager.INTENT_SENDER_BROADCAST, packageName,
@@ -324,6 +327,7 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
+            intent.setAllowFds(false);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     IActivityManager.INTENT_SENDER_SERVICE, packageName,
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 028149b..3cbaf92 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -366,6 +366,9 @@
                 mFinished = true;
             
                 try {
+                    if (mResultExtras != null) {
+                        mResultExtras.setAllowFds(false);
+                    }
                     if (mOrderedHint) {
                         am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                                 mAbortBroadcast);
@@ -462,6 +465,7 @@
         IActivityManager am = ActivityManagerNative.getDefault();
         IBinder binder = null;
         try {
+            service.setAllowFds(false);
             binder = am.peekService(service, service.resolveTypeIfNeeded(
                     myContext.getContentResolver()));
         } catch (RemoteException e) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index f44d038..08fe0aa 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3568,6 +3568,13 @@
         return mExtras != null && mExtras.hasFileDescriptors();
     }
 
+    /** @hide */
+    public void setAllowFds(boolean allowFds) {
+        if (mExtras != null) {
+            mExtras.setAllowFds(allowFds);
+        }
+    }
+
     /**
      * Retrieve extended data from the intent.
      *
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index c288f8a..e698c1d 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -54,6 +54,7 @@
 
     private boolean mHasFds = false;
     private boolean mFdsKnown = true;
+    private boolean mAllowFds = true;
 
     /**
      * The ClassLoader used when unparcelling data from mParcelledData.
@@ -186,7 +187,14 @@
     public ClassLoader getClassLoader() {
         return mClassLoader;
     }
-    
+
+    /** @hide */
+    public boolean setAllowFds(boolean allowFds) {
+        boolean orig = mAllowFds;
+        mAllowFds = allowFds;
+        return orig;
+    }
+
     /**
      * Clones the current Bundle. The internal map is cloned, but the keys and
      * values to which it refers are copied by reference.
@@ -1589,24 +1597,29 @@
      * @param parcel The parcel to copy this bundle to.
      */
     public void writeToParcel(Parcel parcel, int flags) {
-        if (mParcelledData != null) {
-            int length = mParcelledData.dataSize();
-            parcel.writeInt(length);
-            parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
-            parcel.appendFrom(mParcelledData, 0, length);
-        } else {
-            parcel.writeInt(-1); // dummy, will hold length
-            parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
-
-            int oldPos = parcel.dataPosition();
-            parcel.writeMapInternal(mMap);
-            int newPos = parcel.dataPosition();
-
-            // Backpatch length
-            parcel.setDataPosition(oldPos - 8);
-            int length = newPos - oldPos;
-            parcel.writeInt(length);
-            parcel.setDataPosition(newPos);
+        final boolean oldAllowFds = parcel.setAllowFds(mAllowFds);
+        try {
+            if (mParcelledData != null) {
+                int length = mParcelledData.dataSize();
+                parcel.writeInt(length);
+                parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
+                parcel.appendFrom(mParcelledData, 0, length);
+            } else {
+                parcel.writeInt(-1); // dummy, will hold length
+                parcel.writeInt(0x4C444E42); // 'B' 'N' 'D' 'L'
+    
+                int oldPos = parcel.dataPosition();
+                parcel.writeMapInternal(mMap);
+                int newPos = parcel.dataPosition();
+    
+                // Backpatch length
+                parcel.setDataPosition(oldPos - 8);
+                int length = newPos - oldPos;
+                parcel.writeInt(length);
+                parcel.setDataPosition(newPos);
+            }
+        } finally {
+            parcel.setAllowFds(oldAllowFds);
         }
     }
 
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index e9ed676..36a08b9 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -323,6 +323,9 @@
      */
     public final native void setDataCapacity(int size);
 
+    /** @hide */
+    public final native boolean setAllowFds(boolean allowFds);
+
     /**
      * Returns the raw bytes of the parcel.
      *
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 494a2b3..efdaad6 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -697,6 +697,10 @@
             LOGE("!!! FAILED BINDER TRANSACTION !!!");
             //jniThrowException(env, "java/lang/OutOfMemoryError", "Binder transaction too large");
             break;
+        case FDS_NOT_ALLOWED:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "Not allowed to write file descriptors here");
+            break;
         default:
             LOGE("Unknown binder error code. 0x%x", err);
     }
@@ -1275,7 +1279,7 @@
     if (parcel != NULL) {
         const status_t err = parcel->setDataSize(size);
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1294,11 +1298,21 @@
     if (parcel != NULL) {
         const status_t err = parcel->setDataCapacity(size);
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
 
+static jboolean android_os_Parcel_setAllowFds(JNIEnv* env, jobject clazz, jboolean allowFds)
+{
+    Parcel* parcel = parcelForJavaObject(env, clazz);
+    jboolean ret = JNI_TRUE;
+    if (parcel != NULL) {
+        ret = (jboolean)parcel->setAllowFds((bool)allowFds);
+    }
+    return ret;
+}
+
 static void android_os_Parcel_writeNative(JNIEnv* env, jobject clazz,
                                           jobject data, jint offset,
                                           jint length)
@@ -1310,12 +1324,13 @@
 
     const status_t err = parcel->writeInt32(length);
     if (err != NO_ERROR) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        signalExceptionForError(env, clazz, err);
+        return;
     }
 
     void* dest = parcel->writeInplace(length);
     if (dest == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+        signalExceptionForError(env, clazz, NO_MEMORY);
         return;
     }
 
@@ -1333,7 +1348,7 @@
     if (parcel != NULL) {
         const status_t err = parcel->writeInt32(val);
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1344,7 +1359,7 @@
     if (parcel != NULL) {
         const status_t err = parcel->writeInt64(val);
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1355,7 +1370,7 @@
     if (parcel != NULL) {
         const status_t err = parcel->writeFloat(val);
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1366,7 +1381,7 @@
     if (parcel != NULL) {
         const status_t err = parcel->writeDouble(val);
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1386,7 +1401,7 @@
             err = parcel->writeString16(NULL, 0);
         }
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1397,7 +1412,7 @@
     if (parcel != NULL) {
         const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1409,7 +1424,7 @@
         const status_t err =
                 parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
         if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+            signalExceptionForError(env, clazz, err);
         }
     }
 }
@@ -1717,7 +1732,10 @@
        return;
     }
 
-    (void) thisParcel->appendFrom(otherParcel, offset, length);
+    status_t err = thisParcel->appendFrom(otherParcel, offset, length);
+    if (err != NO_ERROR) {
+        signalExceptionForError(env, clazz, err);
+    }
 }
 
 static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jobject clazz)
@@ -1792,6 +1810,7 @@
     {"setDataSize",         "(I)V", (void*)android_os_Parcel_setDataSize},
     {"setDataPosition",     "(I)V", (void*)android_os_Parcel_setDataPosition},
     {"setDataCapacity",     "(I)V", (void*)android_os_Parcel_setDataCapacity},
+    {"setAllowFds",         "(Z)Z", (void*)android_os_Parcel_setAllowFds},
     {"writeNative",         "([BII)V", (void*)android_os_Parcel_writeNative},
     {"writeInt",            "(I)V", (void*)android_os_Parcel_writeInt},
     {"writeLong",           "(J)V", (void*)android_os_Parcel_writeLong},