Merge "Make MediaDrm device-aware" into main
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 5331046..6593533 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -205,6 +205,10 @@
      * media container format specified by mimeType at the requested
      * security level.
      *
+     * Calling this method while the application is running on the physical Android device or a
+     * {@link android.companion.virtual.VirtualDevice} may lead to different results, based on
+     * the different DRM capabilities of the devices.
+     *
      * @param uuid The UUID of the crypto scheme.
      * @param mimeType The MIME type of the media container, e.g. "video/mp4"
      *   or "video/webm"
@@ -1400,6 +1404,10 @@
      * Open a new session with the MediaDrm object. A session ID is returned.
      * By default, sessions are opened at the native security level of the device.
      *
+     * If the application is currently running on a {@link android.companion.virtual.VirtualDevice}
+     * the security level will be adjusted accordingly to the maximum supported level for the
+     * display.
+     *
      * @throws NotProvisionedException if provisioning is needed
      * @throws ResourceBusyException if required resources are in use
      */
@@ -1422,6 +1430,10 @@
      * can be queried using {@link #getSecurityLevel}. A session
      * ID is returned.
      *
+     * If the application is currently running on a {@link android.companion.virtual.VirtualDevice}
+     * the security level will be adjusted accordingly to the maximum supported level for the
+     * display.
+     *
      * @param level the new security level
      * @throws NotProvisionedException if provisioning is needed
      * @throws ResourceBusyException if required resources are in use
@@ -2180,6 +2192,11 @@
      * Returns a value that may be passed as a parameter to {@link #openSession(int)}
      * requesting that the session be opened at the maximum security level of
      * the device.
+     *
+     * This security level is only valid for the application running on the physical Android
+     * device (e.g. {@link android.content.Context#DEVICE_ID_DEFAULT}). While running on a
+     * {@link android.companion.virtual.VirtualDevice} the maximum supported security level
+     * might be different.
      */
     public static final int getMaxSecurityLevel() {
         return SECURITY_LEVEL_MAX;
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 94fce79..8609c4d 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -82,6 +82,7 @@
         "libhidlbase",
         "libsonivox",
         "server_configurable_flags",
+        "android.companion.virtual.virtualdevice_aidl-cpp",
         "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
         "android.hardware.drm@1.3",
@@ -100,6 +101,7 @@
     static_libs: [
         "libgrallocusage",
         "libmedia_midiiowrapper",
+        "android.companion.virtualdevice.flags-aconfig-cc",
         "android.media.playback.flags-aconfig-cc",
     ],
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 1c25080..48cd53d 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -27,6 +27,8 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 
+#include <android_companion_virtualdevice_flags.h>
+#include <android/companion/virtualnative/IVirtualDeviceManagerNative.h>
 #include <android/hardware/drm/1.3/IDrmFactory.h>
 #include <binder/Parcel.h>
 #include <binder/PersistableBundle.h>
@@ -41,8 +43,10 @@
 #include <map>
 #include <string>
 
+using ::android::companion::virtualnative::IVirtualDeviceManagerNative;
 using ::android::os::PersistableBundle;
 namespace drm = ::android::hardware::drm;
+namespace virtualdevice_flags = android::companion::virtualdevice::flags;
 
 namespace android {
 
@@ -1045,6 +1049,26 @@
     return level;
 }
 
+std::vector<int> getVirtualDeviceIds() {
+    if (!virtualdevice_flags::device_aware_drm()) {
+        ALOGW("Device-aware DRM flag disabled.");
+        return std::vector<int>();
+    }
+
+    sp<IBinder> binder =
+            defaultServiceManager()->checkService(String16("virtualdevice_native"));
+    if (binder != nullptr) {
+        auto vdm = interface_cast<IVirtualDeviceManagerNative>(binder);
+        std::vector<int> deviceIds;
+        const uid_t uid = IPCThreadState::self()->getCallingUid();
+        vdm->getDeviceIdsForUid(uid, &deviceIds);
+        return deviceIds;
+    } else {
+        ALOGW("Cannot get virtualdevice_native service");
+        return std::vector<int>();
+    }
+}
+
 static jbyteArray android_media_MediaDrm_getSupportedCryptoSchemesNative(JNIEnv *env) {
     sp<IDrm> drm = android::DrmUtils::MakeDrm();
     if (drm == NULL) return env->NewByteArray(0);
@@ -1081,6 +1105,15 @@
     }
     DrmPlugin::SecurityLevel securityLevel = jintToSecurityLevel(jSecurityLevel);
 
+    if (getVirtualDeviceIds().size() > 0) {
+        // Cap security level at max SECURITY_LEVEL_SW_SECURE_CRYPTO because at
+        // higher security levels decode output cannot be captured and
+        // streamed to virtual devices rendered on virtual displays.
+        if (securityLevel > DrmPlugin::kSecurityLevelSwSecureCrypto) {
+            return false;
+        }
+    }
+
     bool isSupported;
     status_t err = JDrm::IsCryptoSchemeSupported(uuid.array(), mimeType,
             securityLevel, &isSupported);
@@ -1106,6 +1139,16 @@
         return NULL;
     }
 
+    if (getVirtualDeviceIds().size() > 0) {
+        // Cap security level at max SECURITY_LEVEL_SW_SECURE_CRYPTO because at
+        // higher security levels decode output cannot be captured and
+        // streamed to virtual devices rendered on virtual displays.
+        if (level == DrmPlugin::kSecurityLevelMax ||
+            level > DrmPlugin::kSecurityLevelSwSecureCrypto) {
+            level = DrmPlugin::kSecurityLevelSwSecureCrypto;
+        }
+    }
+
     DrmStatus err = drm->openSession(level, sessionId);
 
     if (throwExceptionAsNecessary(env, drm, err, "Failed to open session")) {
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index a64e3f2..36cba2d 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -19,6 +19,8 @@
 
 #include "jni.h"
 
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <mediadrm/IDrm.h>
 #include <mediadrm/IDrmClient.h>