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:
@@ -206,17 +206,22 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
|
||||
// can then use the hash to verify that decryption was successful.
|
||||
|
||||
if (mTestMode) {
|
||||
SHA256_CTX ctx;
|
||||
uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, dstPtr, offset);
|
||||
SHA256_Final(digest, &ctx);
|
||||
String8 buf;
|
||||
for (size_t i = 0; i < sizeof(digest); i++) {
|
||||
buf.appendFormat("%02x", digest[i]);
|
||||
if (secure) {
|
||||
// can't access data in secure mode
|
||||
errorDetailMsg->setTo("secure");
|
||||
} else {
|
||||
SHA256_CTX ctx;
|
||||
uint8_t digest[SHA256_DIGEST_LENGTH];
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, dstPtr, offset);
|
||||
SHA256_Final(digest, &ctx);
|
||||
String8 buf;
|
||||
for (size_t i = 0; i < sizeof(digest); i++) {
|
||||
buf.appendFormat("%02x", digest[i]);
|
||||
}
|
||||
errorDetailMsg->setTo(buf.string());
|
||||
}
|
||||
|
||||
errorDetailMsg->setTo(buf.string());
|
||||
return kErrorTestMode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TabHost 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_height="wrap_content" />
|
||||
<FrameLayout
|
||||
android:id="@android:id/tabcontent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</TabHost>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.widevine.test.SurfacePanel
|
||||
android:id="@+id/surface_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -4,9 +4,14 @@
|
||||
|
||||
package com.widevine.test;
|
||||
|
||||
import android.app.TabActivity;
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
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.MediaDrmException;
|
||||
import android.media.NotProvisionedException;
|
||||
@@ -19,6 +24,7 @@ import android.media.MediaCodec.CryptoInfo;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaFormat;
|
||||
import android.util.Log;
|
||||
import android.util.AttributeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
@@ -32,7 +38,38 @@ import java.lang.InterruptedException;
|
||||
import java.security.MessageDigest;
|
||||
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";
|
||||
|
||||
static final UUID kWidevineScheme = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
|
||||
@@ -52,19 +89,24 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
mTestFailed = false;
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
mTestFailed = false;
|
||||
|
||||
testWidevineSchemeSupported();
|
||||
testProperties();
|
||||
testQueryKeyStatus();
|
||||
testClearContentNoKeys();
|
||||
testEncryptedContent();
|
||||
testWidevineSchemeSupported();
|
||||
testProperties();
|
||||
testQueryKeyStatus();
|
||||
testClearContentNoKeys();
|
||||
testEncryptedContent();
|
||||
|
||||
if (mTestFailed) {
|
||||
Log.e(TAG, "TEST FAILED!");
|
||||
} else {
|
||||
Log.e(TAG, "TEST SUCCESS!");
|
||||
}
|
||||
if (mTestFailed) {
|
||||
Log.e(TAG, "TEST FAILED!");
|
||||
} else {
|
||||
Log.e(TAG, "TEST SUCCESS!");
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private MediaDrm mDrm;
|
||||
@@ -88,6 +130,7 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
} catch (MediaDrmException e) {
|
||||
Log.e(TAG, "Failed to create MediaDrm: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
mTestFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -133,6 +176,7 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
private void stopDrm(MediaDrm drm) {
|
||||
if (drm != mDrm) {
|
||||
Log.e(TAG, "invalid drm specified in stopDrm");
|
||||
mTestFailed = true;
|
||||
}
|
||||
mLooper.quit();
|
||||
}
|
||||
@@ -157,6 +201,7 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
private void testWidevineSchemeSupported() {
|
||||
if (!MediaDrm.isCryptoSchemeSupported(kWidevineScheme)) {
|
||||
Log.e(TAG, "testWidevineSchemeSupported failed");
|
||||
mTestFailed = true;
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -244,6 +289,7 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
} catch (MediaCryptoException e) {
|
||||
Log.e(TAG, "test failed due to exception: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
mTestFailed = true;
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -255,9 +301,9 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
codec = MediaCodec.createDecoderByType(mime);
|
||||
}
|
||||
|
||||
MediaFormat format = MediaFormat.createVideoFormat(mime, 640, 480);
|
||||
codec.configure(format, null, crypto, 0);
|
||||
|
||||
MediaFormat format = MediaFormat.createVideoFormat(mime, 1280, 720);
|
||||
SurfaceView sv = (SurfaceView)findViewById(R.id.surface_view);
|
||||
codec.configure(format, sv.getHolder().getSurface(), crypto, 0);
|
||||
codec.start();
|
||||
|
||||
ByteBuffer[] inputBuffers = codec.getInputBuffers();
|
||||
@@ -311,24 +357,27 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
// in test mode, the WV CryptoPlugin throws a CryptoException where the
|
||||
// message string contains a SHA256 hash of the decrypted data, for verification
|
||||
// purposes.
|
||||
MessageDigest digest = null;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
ex.printStackTrace();
|
||||
finish();
|
||||
}
|
||||
byte buf[] = Arrays.copyOf(refBuffer.array(), sampleSize);
|
||||
byte[] sha256 = digest.digest(buf);
|
||||
if (Arrays.equals(sha256, hex2ba(e.getMessage()))) {
|
||||
Log.i(TAG, "sha256: " + e.getMessage() + " matches OK");
|
||||
} else {
|
||||
Log.i(TAG, "MediaCrypto sha256: " + e.getMessage() +
|
||||
" does not match test vector sha256: ");
|
||||
for (int i = 0; i < sha256.length; i++) {
|
||||
System.out.printf("%02x", sha256[i]);
|
||||
if (!e.getMessage().equals("secure")) {
|
||||
Log.i(TAG, "e.getMessage()='" + e.getMessage() + "'");
|
||||
MessageDigest digest = null;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
ex.printStackTrace();
|
||||
finish();
|
||||
}
|
||||
byte buf[] = Arrays.copyOf(refBuffer.array(), sampleSize);
|
||||
byte[] sha256 = digest.digest(buf);
|
||||
if (Arrays.equals(sha256, hex2ba(e.getMessage()))) {
|
||||
Log.i(TAG, "sha256: " + e.getMessage() + " matches OK");
|
||||
} else {
|
||||
Log.i(TAG, "MediaCrypto sha256: " + e.getMessage() +
|
||||
" does not match test vector sha256: ");
|
||||
for (int i = 0; i < sha256.length; i++) {
|
||||
System.out.printf("%02x", sha256[i]);
|
||||
}
|
||||
mTestFailed = true;
|
||||
}
|
||||
mTestFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,20 +426,23 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
} catch (MediaCryptoException e) {
|
||||
Log.e(TAG, "test failed due to exception: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
mTestFailed = true;
|
||||
finish();
|
||||
}
|
||||
|
||||
String mime = "video/avc";
|
||||
MediaCodec codec;
|
||||
boolean secure = false;
|
||||
if (crypto.requiresSecureDecoderComponent(mime)) {
|
||||
codec = MediaCodec.createByCodecName(getSecureDecoderNameForMime(mime));
|
||||
secure = true;
|
||||
} else {
|
||||
codec = MediaCodec.createDecoderByType(mime);
|
||||
}
|
||||
|
||||
MediaFormat format = MediaFormat.createVideoFormat(mime, 640, 480);
|
||||
codec.configure(format, null, crypto, 0);
|
||||
|
||||
MediaFormat format = MediaFormat.createVideoFormat(mime, 1280, 720);
|
||||
SurfaceView sv = (SurfaceView)findViewById(R.id.surface_view);
|
||||
codec.configure(format, sv.getHolder().getSurface(), crypto, 0);
|
||||
codec.start();
|
||||
|
||||
ByteBuffer[] inputBuffers = codec.getInputBuffers();
|
||||
@@ -413,8 +465,20 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
inputBuffers[index].put(tv.mClearBuf, 0, tv.mClearBuf.length);
|
||||
|
||||
try {
|
||||
codec.queueInputBuffer(index, 0 /* offset */, tv.mClearBuf.length,
|
||||
0 /* sampleTime */, 0 /* flags */);
|
||||
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,
|
||||
0 /* sampleTime */, 0 /* flags */);
|
||||
}
|
||||
} catch (CryptoException e) {
|
||||
ByteBuffer refBuffer = ByteBuffer.allocate(tv.mClearBuf.length);
|
||||
refBuffer.put(tv.mClearBuf, 0, tv.mClearBuf.length);
|
||||
@@ -422,23 +486,25 @@ public class MediaDrmAPITest extends TabActivity {
|
||||
// in test mode, the WV CryptoPlugin throws a CryptoException where the
|
||||
// message string contains a SHA256 hash of the decrypted data, for verification
|
||||
// purposes.
|
||||
MessageDigest digest = null;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
ex.printStackTrace();
|
||||
finish();
|
||||
}
|
||||
byte[] sha256 = digest.digest(refBuffer.array());
|
||||
if (Arrays.equals(sha256, hex2ba(e.getMessage()))) {
|
||||
Log.i(TAG, "sha256: " + e.getMessage() + " matches OK");
|
||||
} else {
|
||||
Log.i(TAG, "MediaCrypto sha256: " + e.getMessage() +
|
||||
" does not match test vector sha256: ");
|
||||
for (int i = 0; i < sha256.length; i++) {
|
||||
System.out.printf("%02x", sha256[i]);
|
||||
if (!e.getMessage().equals("secure")) {
|
||||
MessageDigest digest = null;
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
ex.printStackTrace();
|
||||
finish();
|
||||
}
|
||||
byte[] sha256 = digest.digest(refBuffer.array());
|
||||
if (Arrays.equals(sha256, hex2ba(e.getMessage()))) {
|
||||
Log.i(TAG, "sha256: " + e.getMessage() + " matches OK");
|
||||
} else {
|
||||
Log.i(TAG, "MediaCrypto sha256: " + e.getMessage() +
|
||||
" does not match test vector sha256: ");
|
||||
for (int i = 0; i < sha256.length; i++) {
|
||||
System.out.printf("%02x", sha256[i]);
|
||||
}
|
||||
mTestFailed = true;
|
||||
}
|
||||
mTestFailed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user