media: fix encrypted buffer handling

Bug: 153488982
Test: atest CtsMediaTestCases:MediaCodecBlockModelTest
Change-Id: I6802a60ede494922036e6da5f14fd0fcdadaebfe
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 331477f..43cb25f 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -43,7 +43,7 @@
 
 #include <android_runtime/android_hardware_HardwareBuffer.h>
 
-#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryDealer.h>
 
 #include <cutils/compiler.h>
 
@@ -306,6 +306,7 @@
     CHECK(format->findString("mime", &mime));
     mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))
             && !(flags & CONFIGURE_FLAG_ENCODE);
+    mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);
 
     return mCodec->configure(
             format, mSurfaceTextureClient, crypto, descrambler, flags);
@@ -1603,14 +1604,13 @@
         ScopedLocalRef<jobject> patternObj{
             env, env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID)};
 
-        CryptoPlugin::Pattern pattern;
         if (patternObj.get() == nullptr) {
-            pattern.mEncryptBlocks = 0;
-            pattern.mSkipBlocks = 0;
+            mPattern.mEncryptBlocks = 0;
+            mPattern.mSkipBlocks = 0;
         } else {
-            pattern.mEncryptBlocks = env->GetIntField(
+            mPattern.mEncryptBlocks = env->GetIntField(
                     patternObj.get(), gFields.patternEncryptBlocksID);
-            pattern.mSkipBlocks = env->GetIntField(
+            mPattern.mSkipBlocks = env->GetIntField(
                     patternObj.get(), gFields.patternSkipBlocksID);
         }
 
@@ -1679,6 +1679,18 @@
                 mIv = env->GetByteArrayElements(mIvObj.get(), nullptr);
             }
         }
+
+    }
+
+    explicit NativeCryptoInfo(jint size)
+        : mIvObj{nullptr, nullptr},
+          mKeyObj{nullptr, nullptr},
+          mMode{CryptoPlugin::kMode_Unencrypted},
+          mPattern{0, 0} {
+        mSubSamples = new CryptoPlugin::SubSample[1];
+        mNumSubSamples = 1;
+        mSubSamples[0].mNumBytesOfClearData = size;
+        mSubSamples[0].mNumBytesOfEncryptedData = 0;
     }
 
     ~NativeCryptoInfo() {
@@ -2128,10 +2140,13 @@
         if (env->GetBooleanField(bufferObj, gLinearBlockInfo.validId)) {
             JMediaCodecLinearBlock *context =
                 (JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
-            if (cryptoInfoObj != nullptr) {
+            if (codec->hasCryptoOrDescrambler()) {
                 memory = context->toHidlMemory();
+                // TODO: copy if memory is null
+                offset += context->mHidlMemoryOffset;
             } else {
                 buffer = context->toC2Buffer(offset, size);
+                // TODO: copy if buffer is null
             }
         }
         env->MonitorExit(lock.get());
@@ -2141,13 +2156,19 @@
     }
 
     AString errorDetailMsg;
-    if (cryptoInfoObj != nullptr) {
+    if (codec->hasCryptoOrDescrambler()) {
         if (!memory) {
+            ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
             throwExceptionAsNecessary(env, BAD_VALUE);
             return;
         }
-
-        NativeCryptoInfo cryptoInfo{env, cryptoInfoObj};
+        NativeCryptoInfo cryptoInfo = [env, cryptoInfoObj, size]{
+            if (cryptoInfoObj == nullptr) {
+                return NativeCryptoInfo{size};
+            } else {
+                return NativeCryptoInfo{env, cryptoInfoObj};
+            }
+        }();
         err = codec->queueEncryptedLinearBlock(
                 index,
                 memory,
@@ -2162,6 +2183,7 @@
                 &errorDetailMsg);
     } else {
         if (!buffer) {
+            ALOGI("queueLinearBlock: no C2Buffer found");
             throwExceptionAsNecessary(env, BAD_VALUE);
             return;
         }
@@ -2955,13 +2977,13 @@
                 context->mLegacyBuffer->size(),
                 true,  // readOnly
                 true /* clearBuffer */);
-    } else if (context->mHeap) {
+    } else if (context->mMemory) {
         return CreateByteBuffer(
                 env,
-                static_cast<uint8_t *>(context->mHeap->getBase()) + context->mHeap->getOffset(),
-                context->mHeap->getSize(),
+                context->mMemory->unsecurePointer(),
+                context->mMemory->size(),
                 0,
-                context->mHeap->getSize(),
+                context->mMemory->size(),
                 false,  // readOnly
                 true /* clearBuffer */);
     }
@@ -3011,8 +3033,26 @@
         }
     }
     if (hasSecure && !hasNonSecure) {
-        context->mHeap = new MemoryHeapBase(capacity);
-        context->mMemory = hardware::fromHeap(context->mHeap);
+        constexpr size_t kInitialDealerCapacity = 1048576;  // 1MB
+        thread_local sp<MemoryDealer> sDealer = new MemoryDealer(
+                kInitialDealerCapacity, "JNI(1MB)");
+        context->mMemory = sDealer->allocate(capacity);
+        if (context->mMemory == nullptr) {
+            size_t newDealerCapacity = sDealer->getMemoryHeap()->getSize() * 2;
+            while (capacity * 2 > newDealerCapacity) {
+                newDealerCapacity *= 2;
+            }
+            ALOGI("LinearBlock.native_obtain: "
+                  "Dealer capacity increasing from %zuMB to %zuMB",
+                  sDealer->getMemoryHeap()->getSize() / 1048576,
+                  newDealerCapacity / 1048576);
+            sDealer = new MemoryDealer(
+                    newDealerCapacity,
+                    AStringPrintf("JNI(%zuMB)", newDealerCapacity).c_str());
+            context->mMemory = sDealer->allocate(capacity);
+        }
+        context->mHidlMemory = hardware::fromHeap(context->mMemory->getMemory(
+                    &context->mHidlMemoryOffset, &context->mHidlMemorySize));
     } else {
         context->mBlock = MediaCodec::FetchLinearBlock(capacity, names);
         if (!context->mBlock) {
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 400ce1b..5c34341 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -162,6 +162,8 @@
 
     void selectAudioPresentation(const int32_t presentationId, const int32_t programId);
 
+    bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
+
 protected:
     virtual ~JMediaCodec();
 
@@ -181,6 +183,7 @@
     sp<MediaCodec> mCodec;
     AString mNameAtCreation;
     bool mGraphicOutput{false};
+    bool mHasCryptoOrDescrambler{false};
     std::once_flag mReleaseFlag;
 
     sp<AMessage> mCallbackNotification;
diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h
index 0843834..8f1d2fa 100644
--- a/media/jni/android_media_MediaCodecLinearBlock.h
+++ b/media/jni/android_media_MediaCodecLinearBlock.h
@@ -31,8 +31,10 @@
     std::shared_ptr<C2LinearBlock> mBlock;
     std::shared_ptr<C2WriteView> mReadWriteMapping;
 
-    sp<IMemoryHeap> mHeap;
-    sp<hardware::HidlMemory> mMemory;
+    sp<IMemory> mMemory;
+    sp<hardware::HidlMemory> mHidlMemory;
+    ssize_t mHidlMemoryOffset;
+    size_t mHidlMemorySize;
 
     sp<MediaCodecBuffer> mLegacyBuffer;
 
@@ -56,8 +58,8 @@
     }
 
     sp<hardware::HidlMemory> toHidlMemory() {
-        if (mMemory) {
-            return mMemory;
+        if (mHidlMemory) {
+            return mHidlMemory;
         }
         return nullptr;
     }
@@ -65,4 +67,4 @@
 
 }  // namespace android
 
-#endif  // _ANDROID_MEDIA_MEDIACODECLINEARBLOCK_H_
\ No newline at end of file
+#endif  // _ANDROID_MEDIA_MEDIACODECLINEARBLOCK_H_