From d4fa39113d98de9e7bd1cc046aa8152769bd54fa Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 28 Aug 2013 17:03:36 -0700 Subject: [PATCH] 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 --- .../mediacrypto/src/WVCryptoPlugin.cpp | 23 ++- libwvdrmengine/test/java/res/layout/main.xml | 30 +-- .../com/widevine/test/MediaDrmAPITest.java | 174 ++++++++++++------ 3 files changed, 144 insertions(+), 83 deletions(-) diff --git a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp index 0b9700ef..63e3c647 100644 --- a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp +++ b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp @@ -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; } diff --git a/libwvdrmengine/test/java/res/layout/main.xml b/libwvdrmengine/test/java/res/layout/main.xml index 1f015bcb..fbf870b2 100644 --- a/libwvdrmengine/test/java/res/layout/main.xml +++ b/libwvdrmengine/test/java/res/layout/main.xml @@ -1,21 +1,11 @@ - - - - - - + + + + diff --git a/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java b/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java index bf8b0369..117d6b9c 100644 --- a/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java +++ b/libwvdrmengine/test/java/src/com/widevine/test/MediaDrmAPITest.java @@ -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; } } }