• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.drm.cts;
18 
19 import com.android.compatibility.common.util.MediaUtils;
20 
21 import android.content.ContentValues;
22 import android.content.Context;
23 import android.content.res.AssetFileDescriptor;
24 import android.test.AndroidTestCase;
25 import android.util.Log;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.RandomAccessFile;
29 import java.io.SequenceInputStream;
30 import java.nio.charset.StandardCharsets;
31 import java.io.ByteArrayInputStream;
32 import java.io.File;
33 import java.io.FileInputStream;
34 import java.io.FileNotFoundException;
35 import java.io.FileOutputStream;
36 import java.util.HashMap;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Enumeration;
40 import java.util.Iterator;
41 import java.util.Vector;
42 
43 import android.drm.DrmManagerClient;
44 import android.drm.DrmConvertedStatus;
45 import android.drm.DrmEvent;
46 import android.drm.DrmInfo;
47 import android.drm.DrmInfoRequest;
48 import android.drm.DrmInfoStatus;
49 import android.drm.DrmRights;
50 import android.drm.DrmStore;
51 import android.drm.DrmUtils;
52 import android.media.MediaExtractor;
53 import android.media.MediaMetadataRetriever;
54 import android.media.MediaPlayer;
55 import android.net.Uri;
56 import android.os.ParcelFileDescriptor;
57 import android.os.SystemClock;
58 import android.platform.test.annotations.AppModeFull;
59 
60 public class DRMTest extends AndroidTestCase {
61     private static String TAG = "CtsDRMTest";
62     private static final int WAIT_TIME = 60000; // 1 min max
63 
64     private Object mLock = new Object();
65     private ArrayList<Config> mConfigs = new ArrayList<Config>();
66     private DrmRights mDrmRights;
67     private DrmManagerClient mDrmManagerClient;
68 
69     @Override
setUp()70     protected void setUp() throws Exception {
71         super.setUp();
72         mDrmManagerClient = new DrmManagerClient(getContext());
73         String[] plugins = mDrmManagerClient.getAvailableDrmEngines();
74 
75         mConfigs.clear();
76         for(String plugInName : plugins) {
77             Config config = ConfigFactory.getConfig(plugInName);
78             if (null != config) {
79                 mConfigs.add(config);
80             }
81         }
82     }
83 
register(Config config)84     private void register(Config config) throws Exception {
85         DrmInfo drmInfo = executeAcquireDrmInfo(DrmInfoRequest.TYPE_REGISTRATION_INFO,
86                                             config.getInfoOfRegistration(),
87                                             config.getMimeType());
88         executeProcessDrmInfo(drmInfo, config);
89     }
90 
acquireRights(Config config)91     private void acquireRights(Config config) throws Exception {
92         DrmInfo drmInfo = executeAcquireDrmInfo(DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO,
93                                             config.getInfoOfRightsAcquisition(),
94                                             config.getMimeType());
95         executeProcessDrmInfo(drmInfo, config);
96     }
97 
deregister(Config config)98     private void deregister(Config config) throws Exception {
99         DrmInfo drmInfo = executeAcquireDrmInfo(DrmInfoRequest.TYPE_UNREGISTRATION_INFO,
100                                             config.getInfoOfRegistration(),
101                                             config.getMimeType());
102         executeProcessDrmInfo(drmInfo, config);
103     }
104 
testIsDrmDirectoryExist()105     public void testIsDrmDirectoryExist() {
106         assertTrue("/data/drm/ does not exist", new File("/data/drm/").exists());
107     }
108 
testRegisterAndDeregister()109     public void testRegisterAndDeregister() throws Exception {
110         for (Config config : mConfigs) {
111             register(config);
112             deregister(config);
113         }
114     }
115 
testAcquireRights()116     public void testAcquireRights() throws Exception {
117         for (Config config : mConfigs) {
118             register(config);
119             acquireRights(config);
120             deregister(config);
121         }
122     }
123 
testGetConstraints()124     public void testGetConstraints() throws Exception {
125         for (Config config : mConfigs) {
126             register(config);
127             acquireRights(config);
128             ContentValues constraints = mDrmManagerClient.getConstraints(
129                                             config.getContentPath(),
130                                             DrmStore.Action.DEFAULT);
131             assertNotNull("Failed on plugin: " + config.getPluginName(), constraints);
132             deregister(config);
133         }
134     }
135 
testSupportsHttps()136     public void testSupportsHttps() throws Exception {
137         mDrmManagerClient.getConstraints(Uri.parse("https://www.foo.com"),
138                                          DrmStore.Action.DEFAULT);
139     }
140 
testCanHandle()141     public void testCanHandle() throws Exception {
142         for (Config config : mConfigs) {
143             assertTrue("Failed on plugin: " + config.getPluginName(),
144                     mDrmManagerClient.canHandle(config.getContentPath(), config.getMimeType()));
145         }
146     }
147 
testGetOriginalMimeType()148     public void testGetOriginalMimeType() throws Exception {
149         for (Config config : mConfigs) {
150             assertNotNull("Failed on plugin: " + config.getPluginName(),
151                     mDrmManagerClient.getOriginalMimeType(config.getContentPath()));
152         }
153     }
154 
testCheckRightsStatus()155     public void testCheckRightsStatus() throws Exception {
156         for (Config config : mConfigs) {
157             register(config);
158             acquireRights(config);
159             int rightsStatus = mDrmManagerClient.checkRightsStatus(
160                                                 config.getContentPath(),
161                                                 DrmStore.Action.PLAY);
162             assertEquals("Failed on plugin: " + config.getPluginName(),
163                     DrmStore.RightsStatus.RIGHTS_VALID, rightsStatus);
164             deregister(config);
165         }
166     }
167 
testRemoveRights()168     public void testRemoveRights() throws Exception {
169         for (Config config : mConfigs) {
170             assertEquals("Failed on plugin: " + config.getPluginName(),
171                     DrmManagerClient.ERROR_NONE,
172                     mDrmManagerClient.removeRights(config.getContentPath()));
173         }
174     }
175 
testRemoveAllRights()176     public void testRemoveAllRights() throws Exception {
177         for (Config config : mConfigs) {
178             assertEquals("Failed on plugin: " + config.getPluginName(),
179                     mDrmManagerClient.removeAllRights(), DrmManagerClient.ERROR_NONE);
180         }
181     }
182 
testConvertData()183     public void testConvertData() throws Exception {
184         for (Config config : mConfigs) {
185             byte[] inputData = new byte[]{'T','E','S','T'};
186 
187             int convertId = mDrmManagerClient.openConvertSession(config.getMimeType());
188             DrmConvertedStatus drmConvertStatus
189                                 = mDrmManagerClient.convertData(convertId, inputData);
190             mDrmManagerClient.closeConvertSession(convertId);
191         }
192     }
193 
executeAcquireDrmInfo( int type, HashMap<String, String> request, String mimeType)194     private DrmInfo executeAcquireDrmInfo(
195             int type, HashMap<String, String> request, String mimeType) throws Exception {
196         DrmInfoRequest infoRequest = new DrmInfoRequest(type, mimeType);
197 
198         for (Iterator it = request.keySet().iterator(); it.hasNext(); ) {
199             String key = (String) it.next();
200             String value = request.get(key);
201             infoRequest.put(key, value);
202         }
203 
204         return mDrmManagerClient.acquireDrmInfo(infoRequest);
205     }
206 
executeProcessDrmInfo(DrmInfo drmInfo, Config config)207     private void executeProcessDrmInfo(DrmInfo drmInfo, Config config) throws Exception {
208         if (drmInfo == null) {
209             return;
210         }
211 
212         mDrmManagerClient.setOnEventListener(new OnEventListenerImpl(config));
213         drmInfo.put(DrmInfoRequest.ACCOUNT_ID, config.getAccountId());
214         assertEquals("Failed on plugin: " + config.getPluginName(),
215                 DrmManagerClient.ERROR_NONE, mDrmManagerClient.processDrmInfo(drmInfo));
216 
217         synchronized(mLock) {
218             try {
219                 mLock.wait(WAIT_TIME);
220             } catch(Exception e) {
221                 Log.v(TAG, "ProcessDrmInfo: wait was interrupted.");
222             }
223         }
224     }
225 
226     @AppModeFull(reason = "Instant apps cannot hold READ/WRITE_EXTERNAL_STORAGE")
testForwardLockAccess()227     public void testForwardLockAccess()  throws Exception {
228         DrmManagerClient drmManager= new DrmManagerClient(mContext);
229         String[] engines = drmManager.getAvailableDrmEngines();
230         boolean haveForwardLock = false;
231         for (String engine: engines) {
232             if (engine.equals("OMA V1 Forward Lock")) {
233                 haveForwardLock = true;
234             }
235         }
236         drmManager.close();
237         if (!haveForwardLock) {
238             Log.i(TAG, "Skipping forward lock test because forward lock is not available");
239             return;
240         }
241 
242         Vector<InputStream> sequence = new Vector<InputStream>();
243 
244         String dmHeader = "--mime_content_boundary\r\n" +
245         "Content-Type: audio/mpeg\r\n" +
246         "Content-Transfer-Encoding: binary\r\n\r\n";
247         sequence.add(new ByteArrayInputStream(dmHeader.getBytes(StandardCharsets.UTF_8)));
248 
249         AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3_2);
250         FileInputStream body = afd.createInputStream();
251         sequence.add(body);
252 
253         String dmFooter = "\r\n--mime_content_boundary--";
254         sequence.add(new ByteArrayInputStream(dmFooter.getBytes(StandardCharsets.UTF_8)));
255 
256         SequenceInputStream dmStream = new SequenceInputStream(sequence.elements());
257         String flPath = mContext.getExternalCacheDir() + "/temp.fl";
258         RandomAccessFile flFile = new RandomAccessFile(flPath, "rw");
259         assertTrue("couldn't convert to fl file",
260                 MediaUtils.convertDmToFl(mContext, dmStream,  flFile));
261         dmStream.close(); // this closes the underlying streams and AFD as well
262         flFile.close();
263 
264         ParcelFileDescriptor flFd = null;
265         try {
266             // check that the .fl file can be played
267             MediaPlayer player = new MediaPlayer();
268             try {
269                 flFd = ParcelFileDescriptor.open(
270                         new File(flPath), ParcelFileDescriptor.MODE_READ_ONLY);
271                 player.setDataSource(flFd.getFileDescriptor(), 0, flFd.getStatSize());
272                 player.prepare();
273                 player.start();
274                 SystemClock.sleep(2000);
275                 assertTrue("player is not playing", player.isPlaying());
276                 player.release();
277             } catch (Exception e) {
278                 Log.d(TAG, "MediaPlayer playback failed:", e);
279             } finally {
280                 player.release();
281             }
282 
283             // check that the .fl file can be parsed with MediaMetadataRetriever
284             MediaMetadataRetriever retriever = new MediaMetadataRetriever();
285             try {
286                 retriever.setDataSource(flFd.getFileDescriptor());
287                 String numTracks =
288                         retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS);
289                 assertEquals("wrong number of tracks found in file", "1", numTracks);
290             } finally {
291                 retriever.release();
292             }
293 
294             // check that the .fl file cannot be opened with MediaExtractor
295             MediaExtractor ex = new MediaExtractor();
296             try {
297                 ex.setDataSource(flFd.getFileDescriptor());
298                 int n = ex.getTrackCount();
299                 fail("extractor creation should have failed, but found " + n + " tracks");
300             } catch (Exception e) {
301                 // ignore, expected to fail
302             } finally {
303                 ex.release();
304             }
305         } finally {
306             flFd.close();
307             new File(flPath).delete();
308         }
309     }
310 
311     private class OnEventListenerImpl implements DrmManagerClient.OnEventListener {
312         private Config mConfig;
OnEventListenerImpl(Config config)313         public OnEventListenerImpl(Config config) {
314             mConfig = config;
315         }
316 
317         @Override
onEvent(DrmManagerClient client, DrmEvent event)318         public void onEvent(DrmManagerClient client, DrmEvent event) {
319             switch (event.getType()) {
320             case DrmEvent.TYPE_DRM_INFO_PROCESSED:
321                 Log.d(TAG, "processDrmInfo() completed");
322                 DrmInfoStatus infoStatus
323                         = (DrmInfoStatus) event.getAttribute(DrmEvent.DRM_INFO_STATUS_OBJECT);
324                 switch (infoStatus.infoType) {
325                 case DrmInfoRequest.TYPE_RIGHTS_ACQUISITION_INFO:
326                     mDrmRights = new DrmRights(infoStatus.data, infoStatus.mimeType);
327                     assertNotNull(mDrmRights);
328                     try {
329                         assertEquals(DrmManagerClient.ERROR_NONE, mDrmManagerClient.saveRights(
330                                     mDrmRights, mConfig.getRightsPath(), mConfig.getContentPath()));
331                         Log.d(TAG, "Rights saved");
332                     } catch (IOException e) {
333                         Log.e(TAG, "Save Rights failed");
334                         e.printStackTrace();
335                     }
336                     break;
337                 case DrmInfoRequest.TYPE_REGISTRATION_INFO:
338                     Log.d(TAG, "Registration completed");
339                     break;
340                 case DrmInfoRequest.TYPE_UNREGISTRATION_INFO:
341                     Log.d(TAG, "Deregistration completed");
342                     break;
343                 default:
344                     break;
345                 }
346                 break;
347             default:
348                 break;
349             }
350             synchronized (mLock) {
351                 mLock.notify();
352             }
353         }
354     }
355 }
356