Improve Widevine MediaDrm plugin tests

1. add missing checks to set the overall result when some tests fail
(to verify b/10528466)

2. Fix test result on L1 devices where we can't hash the decrypt result
due to inaccessible memory buffers.

3. Configure the codec with a surface to avoid codec errors on L1 devices

b/10528466

Merge of https://widevine-internal-review.googlesource.com/#/c/7510/
from the widevine CDM repo

Change-Id: I5c7ef5ce802cc4ff63f62524ef2120fb671920f4
This commit is contained in:
Jeff Tinker
2013-08-28 17:03:36 -07:00
parent b4dae0af49
commit d4fa39113d
3 changed files with 144 additions and 83 deletions

View File

@@ -206,6 +206,10 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
// can then use the hash to verify that decryption was successful. // can then use the hash to verify that decryption was successful.
if (mTestMode) { if (mTestMode) {
if (secure) {
// can't access data in secure mode
errorDetailMsg->setTo("secure");
} else {
SHA256_CTX ctx; SHA256_CTX ctx;
uint8_t digest[SHA256_DIGEST_LENGTH]; uint8_t digest[SHA256_DIGEST_LENGTH];
SHA256_Init(&ctx); SHA256_Init(&ctx);
@@ -215,8 +219,9 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
for (size_t i = 0; i < sizeof(digest); i++) { for (size_t i = 0; i < sizeof(digest); i++) {
buf.appendFormat("%02x", digest[i]); buf.appendFormat("%02x", digest[i]);
} }
errorDetailMsg->setTo(buf.string()); errorDetailMsg->setTo(buf.string());
}
return kErrorTestMode; return kErrorTestMode;
} }

View File

@@ -1,21 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" /> android:layout_height="fill_parent"
<FrameLayout android:orientation="vertical">
android:id="@android:id/tabcontent"
android:layout_width="match_parent" <com.widevine.test.SurfacePanel
android:layout_height="match_parent" android:id="@+id/surface_view"
/> android:layout_width="fill_parent"
</LinearLayout> android:layout_height="fill_parent"/>
</TabHost> </LinearLayout>

View File

@@ -4,9 +4,14 @@
package com.widevine.test; package com.widevine.test;
import android.app.TabActivity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.os.Looper; import android.os.Looper;
import android.view.View;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.view.Surface;
import android.content.Context;
import android.media.MediaDrm; import android.media.MediaDrm;
import android.media.MediaDrmException; import android.media.MediaDrmException;
import android.media.NotProvisionedException; import android.media.NotProvisionedException;
@@ -19,6 +24,7 @@ import android.media.MediaCodec.CryptoInfo;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.util.Log; import android.util.Log;
import android.util.AttributeSet;
import java.util.UUID; import java.util.UUID;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
@@ -32,7 +38,38 @@ import java.lang.InterruptedException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
public class MediaDrmAPITest extends TabActivity { class SurfacePanel extends SurfaceView implements SurfaceHolder.Callback
{
private final String TAG = "SurfacePanel";
public SurfacePanel(Context context, AttributeSet attrSet)
{
super(context, attrSet);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
Log.d(TAG, "surfaceDestroyed");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
{
Log.d(TAG, "surfaceChanged");
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
Log.d(TAG, "surfaceCreated");
}
}
public class MediaDrmAPITest extends Activity {
private final String TAG = "MediaDrmAPITest"; private final String TAG = "MediaDrmAPITest";
static final UUID kWidevineScheme = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL); static final UUID kWidevineScheme = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
@@ -52,6 +89,9 @@ public class MediaDrmAPITest extends TabActivity {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.main); setContentView(R.layout.main);
new Thread() {
@Override
public void run() {
mTestFailed = false; mTestFailed = false;
testWidevineSchemeSupported(); testWidevineSchemeSupported();
@@ -66,6 +106,8 @@ public class MediaDrmAPITest extends TabActivity {
Log.e(TAG, "TEST SUCCESS!"); Log.e(TAG, "TEST SUCCESS!");
} }
} }
}.start();
}
private MediaDrm mDrm; private MediaDrm mDrm;
private Looper mLooper; private Looper mLooper;
@@ -88,6 +130,7 @@ public class MediaDrmAPITest extends TabActivity {
} catch (MediaDrmException e) { } catch (MediaDrmException e) {
Log.e(TAG, "Failed to create MediaDrm: " + e.getMessage()); Log.e(TAG, "Failed to create MediaDrm: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
mTestFailed = true;
return; return;
} }
@@ -133,6 +176,7 @@ public class MediaDrmAPITest extends TabActivity {
private void stopDrm(MediaDrm drm) { private void stopDrm(MediaDrm drm) {
if (drm != mDrm) { if (drm != mDrm) {
Log.e(TAG, "invalid drm specified in stopDrm"); Log.e(TAG, "invalid drm specified in stopDrm");
mTestFailed = true;
} }
mLooper.quit(); mLooper.quit();
} }
@@ -157,6 +201,7 @@ public class MediaDrmAPITest extends TabActivity {
private void testWidevineSchemeSupported() { private void testWidevineSchemeSupported() {
if (!MediaDrm.isCryptoSchemeSupported(kWidevineScheme)) { if (!MediaDrm.isCryptoSchemeSupported(kWidevineScheme)) {
Log.e(TAG, "testWidevineSchemeSupported failed"); Log.e(TAG, "testWidevineSchemeSupported failed");
mTestFailed = true;
finish(); finish();
} }
} }
@@ -244,6 +289,7 @@ public class MediaDrmAPITest extends TabActivity {
} catch (MediaCryptoException e) { } catch (MediaCryptoException e) {
Log.e(TAG, "test failed due to exception: " + e.getMessage()); Log.e(TAG, "test failed due to exception: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
mTestFailed = true;
finish(); finish();
} }
@@ -255,9 +301,9 @@ public class MediaDrmAPITest extends TabActivity {
codec = MediaCodec.createDecoderByType(mime); codec = MediaCodec.createDecoderByType(mime);
} }
MediaFormat format = MediaFormat.createVideoFormat(mime, 640, 480); MediaFormat format = MediaFormat.createVideoFormat(mime, 1280, 720);
codec.configure(format, null, crypto, 0); SurfaceView sv = (SurfaceView)findViewById(R.id.surface_view);
codec.configure(format, sv.getHolder().getSurface(), crypto, 0);
codec.start(); codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers(); ByteBuffer[] inputBuffers = codec.getInputBuffers();
@@ -311,6 +357,8 @@ public class MediaDrmAPITest extends TabActivity {
// in test mode, the WV CryptoPlugin throws a CryptoException where the // in test mode, the WV CryptoPlugin throws a CryptoException where the
// message string contains a SHA256 hash of the decrypted data, for verification // message string contains a SHA256 hash of the decrypted data, for verification
// purposes. // purposes.
if (!e.getMessage().equals("secure")) {
Log.i(TAG, "e.getMessage()='" + e.getMessage() + "'");
MessageDigest digest = null; MessageDigest digest = null;
try { try {
digest = MessageDigest.getInstance("SHA-256"); digest = MessageDigest.getInstance("SHA-256");
@@ -331,6 +379,7 @@ public class MediaDrmAPITest extends TabActivity {
mTestFailed = true; mTestFailed = true;
} }
} }
}
// clear buffers for next sample // clear buffers for next sample
numSubSamples = 0; numSubSamples = 0;
@@ -377,20 +426,23 @@ public class MediaDrmAPITest extends TabActivity {
} catch (MediaCryptoException e) { } catch (MediaCryptoException e) {
Log.e(TAG, "test failed due to exception: " + e.getMessage()); Log.e(TAG, "test failed due to exception: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
mTestFailed = true;
finish(); finish();
} }
String mime = "video/avc"; String mime = "video/avc";
MediaCodec codec; MediaCodec codec;
boolean secure = false;
if (crypto.requiresSecureDecoderComponent(mime)) { if (crypto.requiresSecureDecoderComponent(mime)) {
codec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime)); codec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime));
secure = true;
} else { } else {
codec = MediaCodec.createDecoderByType(mime); codec = MediaCodec.createDecoderByType(mime);
} }
MediaFormat format = MediaFormat.createVideoFormat(mime, 640, 480); MediaFormat format = MediaFormat.createVideoFormat(mime, 1280, 720);
codec.configure(format, null, crypto, 0); SurfaceView sv = (SurfaceView)findViewById(R.id.surface_view);
codec.configure(format, sv.getHolder().getSurface(), crypto, 0);
codec.start(); codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers(); ByteBuffer[] inputBuffers = codec.getInputBuffers();
@@ -413,8 +465,20 @@ public class MediaDrmAPITest extends TabActivity {
inputBuffers[index].put(tv.mClearBuf, 0, tv.mClearBuf.length); inputBuffers[index].put(tv.mClearBuf, 0, tv.mClearBuf.length);
try { try {
if (secure) {
int clearSizes[] = new int[1];
clearSizes[0] = tv.mClearBuf.length;
int encryptedSizes[] = new int[1];
encryptedSizes[0] = 0;
CryptoInfo info = new CryptoInfo();
info.set(1, clearSizes, encryptedSizes, null, null, MediaCodec.CRYPTO_MODE_UNENCRYPTED);
codec.queueSecureInputBuffer(index, 0 /* offset */, info,
0 /* sampleTime */, 0 /* flags */);
} else {
codec.queueInputBuffer(index, 0 /* offset */, tv.mClearBuf.length, codec.queueInputBuffer(index, 0 /* offset */, tv.mClearBuf.length,
0 /* sampleTime */, 0 /* flags */); 0 /* sampleTime */, 0 /* flags */);
}
} catch (CryptoException e) { } catch (CryptoException e) {
ByteBuffer refBuffer = ByteBuffer.allocate(tv.mClearBuf.length); ByteBuffer refBuffer = ByteBuffer.allocate(tv.mClearBuf.length);
refBuffer.put(tv.mClearBuf, 0, tv.mClearBuf.length); refBuffer.put(tv.mClearBuf, 0, tv.mClearBuf.length);
@@ -422,6 +486,7 @@ public class MediaDrmAPITest extends TabActivity {
// in test mode, the WV CryptoPlugin throws a CryptoException where the // in test mode, the WV CryptoPlugin throws a CryptoException where the
// message string contains a SHA256 hash of the decrypted data, for verification // message string contains a SHA256 hash of the decrypted data, for verification
// purposes. // purposes.
if (!e.getMessage().equals("secure")) {
MessageDigest digest = null; MessageDigest digest = null;
try { try {
digest = MessageDigest.getInstance("SHA-256"); digest = MessageDigest.getInstance("SHA-256");
@@ -442,6 +507,7 @@ public class MediaDrmAPITest extends TabActivity {
} }
} }
} }
}
codec.stop(); codec.stop();
codec.release(); codec.release();