DO NOT MERGE ANYWHERE: Test whether mediaserver leaks info across invalid binder calls

Bug: 23756261
Change-Id: I884fd26e723d119830cf70f1e1c78bdf46cded08
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 69ccdf0..336b09d 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -33,7 +33,8 @@
 		android_security_cts_MMapExecutableTest.cpp \
 		android_security_cts_NetlinkSocket.cpp \
 		android_security_cts_AudioPolicyBinderTest.cpp \
-		android_security_cts_AudioflingerBinderTest.cpp
+		android_security_cts_AudioflingerBinderTest.cpp \
+		android_security_cts_MediaPlayerInfoLeakTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 22e0997..0d2e6e7 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -28,6 +28,7 @@
 extern int register_android_security_cts_MMapExecutableTest(JNIEnv* env);
 extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
 extern int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env);
+extern int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env);
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
@@ -80,5 +81,9 @@
         return JNI_ERR;
     }
 
+    if (register_android_security_cts_MediaPlayerInfoLeakTest(env)) {
+        return JNI_ERR;
+    }
+
     return JNI_VERSION_1_4;
 }
diff --git a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
index 9daa2cb..fd93387 100644
--- a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
@@ -18,6 +18,7 @@
 
 #include <jni.h>
 #include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
 #include <media/IAudioPolicyService.h>
 #include <media/AudioSystem.h>
 #include <system/audio.h>
@@ -153,6 +154,32 @@
     return true;
 }
 
+jint android_security_cts_AudioPolicy_test_getStreamVolumeLeak(JNIEnv* env __unused,
+                                                           jobject thiz __unused)
+{
+    sp<IAudioPolicyService> aps;
+
+    if (!init(aps, NULL, NULL)) {
+        return -1;
+    }
+
+    // Keep synchronized with IAudioPolicyService.cpp!
+    enum {
+        GET_STREAM_VOLUME = 17,
+    };
+
+    Parcel data, reply;
+    status_t err;
+    data.writeInterfaceToken(aps->getInterfaceDescriptor());
+    data.writeInt32(-1); // stream type
+    data.writeInt32(-1); // device
+    aps->asBinder()->transact(GET_STREAM_VOLUME, data, &reply);
+    int index = reply.readInt32();
+    err = reply.readInt32();
+
+    return index;
+}
+
 static JNINativeMethod gMethods[] = {
     {  "native_test_startOutput", "()Z",
             (void *) android_security_cts_AudioPolicy_test_startOutput },
@@ -160,6 +187,8 @@
                 (void *) android_security_cts_AudioPolicy_test_stopOutput },
     {  "native_test_isStreamActive", "()Z",
                 (void *) android_security_cts_AudioPolicy_test_isStreamActive },
+    {  "native_test_getStreamVolumeLeak", "()I",
+                (void *) android_security_cts_AudioPolicy_test_getStreamVolumeLeak },
 };
 
 int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env)
diff --git a/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
new file mode 100644
index 0000000..41262ac
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "MediaPlayerInfoLeakTest-JNI"
+
+#include <jni.h>
+
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+
+#include <media/IMediaPlayer.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaPlayerClient.h>
+
+#include <sys/stat.h>
+
+using namespace android;
+
+static status_t connectMediaPlayer(sp<IMediaPlayer>& iMP)
+{
+   sp<IServiceManager> sm = defaultServiceManager();
+   sp<IBinder> mediaPlayerService = sm->checkService(String16("media.player"));
+
+   sp<IMediaPlayerService> iMPService = IMediaPlayerService::asInterface(mediaPlayerService);
+   sp<IMediaPlayerClient> client;
+   Parcel data, reply;
+   int dummyAudioSessionId = 1;
+   data.writeInterfaceToken(iMPService->getInterfaceDescriptor());
+   data.writeStrongBinder(client->asBinder());
+   data.writeInt32(dummyAudioSessionId);
+
+   // Keep synchronized with IMediaPlayerService.cpp!
+    enum {
+        CREATE = IBinder::FIRST_CALL_TRANSACTION,
+    };
+   status_t err = iMPService->asBinder()->transact(CREATE, data, &reply);
+
+   if (err == NO_ERROR) {
+       iMP = interface_cast<IMediaPlayer>(reply.readStrongBinder());
+   }
+   return err;
+}
+
+int testMediaPlayerInfoLeak(int command)
+{
+    sp<IMediaPlayer> iMP;
+    if (NO_ERROR != connectMediaPlayer(iMP)) {
+        return false;
+    }
+
+
+    Parcel data, reply;
+    data.writeInterfaceToken(iMP->getInterfaceDescriptor());
+    iMP->asBinder()->transact(command, data, &reply);
+
+    int leak = reply.readInt32();
+    status_t err = reply.readInt32();
+    return  leak;
+}
+
+jint android_security_cts_MediaPlayer_test_getCurrentPositionLeak(JNIEnv* env __unused,
+                                                           jobject thiz __unused)
+{
+  // Keep synchronized with IMediaPlayer.cpp!
+  enum {
+      GET_CURRENT_POSITION = 11,
+  };
+  return testMediaPlayerInfoLeak(GET_CURRENT_POSITION);
+}
+
+jint android_security_cts_MediaPlayer_test_getDurationLeak(JNIEnv* env __unused,
+                                                           jobject thiz __unused)
+{
+  // Keep synchronized with IMediaPlayer.cpp!
+  enum {
+      GET_DURATION = 12,
+  };
+  return testMediaPlayerInfoLeak(GET_DURATION);
+}
+
+static JNINativeMethod gMethods[] = {
+    {  "native_test_getCurrentPositionLeak", "()I",
+            (void *) android_security_cts_MediaPlayer_test_getCurrentPositionLeak },
+    {  "native_test_getDurationLeak", "()I",
+            (void *) android_security_cts_MediaPlayer_test_getDurationLeak },
+};
+
+int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env)
+{
+    jclass clazz = env->FindClass("android/security/cts/MediaPlayerInfoLeakTest");
+    return env->RegisterNatives(clazz, gMethods,
+            sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
index 399d8bb..daa7c83 100644
--- a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
+++ b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
@@ -48,7 +48,17 @@
         assertTrue(native_test_isStreamActive());
     }
 
+    /**
+     * Checks that IAudioPolicyService::getStreamVolumeIndex() does not leak information
+     * when called with an invalid stream/device type.
+     */
+    public void test_getStreamVolumeLeak() throws Exception {
+        int volume = native_test_getStreamVolumeLeak();
+        assertTrue(String.format("Leaked volume 0x%08X", volume), volume == 0);
+    }
+
     private static native boolean native_test_startOutput();
     private static native boolean native_test_stopOutput();
     private static native boolean native_test_isStreamActive();
+    private static native int native_test_getStreamVolumeLeak();
 }
diff --git a/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
new file mode 100644
index 0000000..e34fc05
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import junit.framework.TestCase;
+
+public class MediaPlayerInfoLeakTest extends TestCase {
+
+    static {
+        System.loadLibrary("ctssecurity_jni");
+    }
+
+
+    /**
+     * Checks that IMediaPlayer::getCurrentPosition() does not leak info in error case
+     */
+    public void test_getCurrentPositionLeak() throws Exception {
+        int pos = native_test_getCurrentPositionLeak();
+        assertTrue(String.format("Leaked pos 0x%08X", pos), pos == 0);
+    }
+
+    /**
+     * Checks that IMediaPlayer::getDuration() does not leak info in error case
+     */
+    public void test_getDurationLeak() throws Exception {
+        int dur = native_test_getDurationLeak();
+        assertTrue(String.format("Leaked dur 0x%08X", dur), dur == 0);
+    }
+
+    private static native int native_test_getCurrentPositionLeak();
+    private static native int native_test_getDurationLeak();
+}