1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.virtualdevice.cts.applaunch;
18 
19 
20 import static com.google.common.truth.Truth.assertThat;
21 import static com.google.common.truth.Truth.assertWithMessage;
22 
23 import android.app.Activity;
24 import android.companion.virtual.VirtualDeviceManager.VirtualDevice;
25 import android.hardware.display.DisplayManager;
26 import android.hardware.display.VirtualDisplay;
27 import android.media.MediaDrm;
28 import android.media.NotProvisionedException;
29 import android.media.ResourceBusyException;
30 import android.media.UnsupportedSchemeException;
31 import android.platform.test.annotations.AppModeFull;
32 import android.platform.test.annotations.RequiresFlagsEnabled;
33 import android.util.Log;
34 import android.virtualdevice.cts.common.VirtualDeviceRule;
35 
36 import androidx.test.ext.junit.runners.AndroidJUnit4;
37 
38 import org.junit.Before;
39 import org.junit.Rule;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 
43 import java.util.UUID;
44 
45 /**
46  * Tests for DRM APIs called from applications running on virtual devices.
47  */
48 @RunWith(AndroidJUnit4.class)
49 @AppModeFull(reason = "VirtualDeviceManager cannot be accessed by instant apps")
50 @RequiresFlagsEnabled({android.companion.virtual.flags.Flags.FLAG_ENABLE_NATIVE_VDM,
51         android.companion.virtualdevice.flags.Flags.FLAG_DEVICE_AWARE_DRM})
52 public class VirtualDeviceDrmTest {
53 
54     private static final String TAG = "MediaDrmTest";
55 
56     @Rule
57     public VirtualDeviceRule mRule = VirtualDeviceRule.createDefault();
58 
59     private DrmActivity mDrmActivity;
60 
61     @Before
setUp()62     public void setUp() throws Exception {
63         VirtualDevice virtualDevice = mRule.createManagedVirtualDevice();
64         VirtualDisplay virtualDisplay = mRule.createManagedVirtualDisplayWithFlags(virtualDevice,
65                 DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
66                         | DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED
67                         | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
68 
69         mDrmActivity = mRule.startActivityOnDisplaySync(virtualDisplay, DrmActivity.class);
70     }
71 
72     @Test
activityOnVirtualDevice_isCryptoSchemeSupported_testUnsupported()73     public void activityOnVirtualDevice_isCryptoSchemeSupported_testUnsupported() {
74         for (UUID scheme : MediaDrm.getSupportedCryptoSchemes()) {
75             int[] unsupportedLevels = {
76                     MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL,
77                     MediaDrm.SECURITY_LEVEL_HW_SECURE_CRYPTO,
78                     MediaDrm.SECURITY_LEVEL_HW_SECURE_DECODE,
79                     MediaDrm.SECURITY_LEVEL_SW_SECURE_DECODE
80             };
81             for (int level : unsupportedLevels) {
82                 for (String mime : new String[]{"audio/mp4", "video/mp4"}) {
83                     assertWithMessage(String.format(
84                             "Should not be supported on virtual devices: Scheme: %s, Mime: %s, "
85                                     + "Securitylevel: %d",
86                             scheme, mime, level)).that(
87                             mDrmActivity.isCryptoSchemeSupported(scheme, mime, level)).isFalse();
88                 }
89             }
90         }
91     }
92 
93     @Test
activityOnVirtualDevice_openSession_verifyDowngradedSecurityLevel()94     public void activityOnVirtualDevice_openSession_verifyDowngradedSecurityLevel() {
95         for (UUID scheme : MediaDrm.getSupportedCryptoSchemes()) {
96             int[] securityLevels = {
97                     MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO,
98                     MediaDrm.SECURITY_LEVEL_SW_SECURE_DECODE,
99                     MediaDrm.SECURITY_LEVEL_HW_SECURE_CRYPTO,
100                     MediaDrm.SECURITY_LEVEL_HW_SECURE_DECODE,
101                     MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL,
102                     MediaDrm.getMaxSecurityLevel()
103             };
104             for (int level : securityLevels) {
105                 assertThat(mDrmActivity.getSecurityLevel(scheme, level)).isAtMost(
106                         MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO);
107             }
108         }
109     }
110 
111     public static class DrmActivity extends Activity {
112 
113         private static final String TAG = "DrmActivity";
114 
isCryptoSchemeSupported(UUID uuid, String mimeType, int securityLevel)115         boolean isCryptoSchemeSupported(UUID uuid, String mimeType, int securityLevel) {
116             return MediaDrm.isCryptoSchemeSupported(uuid, mimeType, securityLevel);
117         }
118 
getSecurityLevel(UUID uuid, int securityLevel)119         int getSecurityLevel(UUID uuid, int securityLevel) {
120             try (MediaDrm drm = new MediaDrm(uuid)) {
121                 byte[] sessionId = drm.openSession(securityLevel);
122                 return drm.getSecurityLevel(sessionId);
123             } catch (UnsupportedSchemeException | NotProvisionedException
124                      | ResourceBusyException | IllegalArgumentException e) {
125                 Log.w(TAG, "Skipping scheme: " + uuid + " at security level: " + securityLevel);
126             }
127             return MediaDrm.SECURITY_LEVEL_UNKNOWN;
128         }
129     }
130 }
131