1/*
2 * Copyright (C) 2016 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#define LOG_TAG "android.hardware.drm@1.0-impl"
17
18#include "CryptoPlugin.h"
19#include "TypeConvert.h"
20
21#include <android/hidl/memory/1.0/IMemory.h>
22#include <hidlmemory/mapping.h>
23#include <log/log.h>
24#include <media/stagefright/foundation/AString.h>
25
26using android::hardware::hidl_memory;
27using android::hidl::memory::V1_0::IMemory;
28
29namespace android {
30namespace hardware {
31namespace drm {
32namespace V1_0 {
33namespace implementation {
34
35    // Methods from ::android::hardware::drm::V1_0::ICryptoPlugin follow
36    Return<bool> CryptoPlugin::requiresSecureDecoderComponent(
37            const hidl_string& mime) {
38        return mLegacyPlugin->requiresSecureDecoderComponent(mime.c_str());
39    }
40
41    Return<void> CryptoPlugin::notifyResolution(uint32_t width,
42            uint32_t height) {
43        mLegacyPlugin->notifyResolution(width, height);
44        return Void();
45    }
46
47    Return<Status> CryptoPlugin::setMediaDrmSession(
48            const hidl_vec<uint8_t>& sessionId) {
49        return toStatus(mLegacyPlugin->setMediaDrmSession(toVector(sessionId)));
50    }
51
52    Return<void> CryptoPlugin::setSharedBufferBase(const hidl_memory& base,
53            uint32_t bufferId) {
54        mSharedBufferMap[bufferId] = mapMemory(base);
55        return Void();
56    }
57
58    Return<void> CryptoPlugin::decrypt(bool secure,
59            const hidl_array<uint8_t, 16>& keyId,
60            const hidl_array<uint8_t, 16>& iv, Mode mode,
61            const Pattern& pattern, const hidl_vec<SubSample>& subSamples,
62            const SharedBuffer& source, uint64_t offset,
63            const DestinationBuffer& destination,
64            decrypt_cb _hidl_cb) {
65
66        if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
67            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source decrypt buffer base not set");
68            return Void();
69        }
70
71        if (destination.type == BufferType::SHARED_MEMORY) {
72            const SharedBuffer& dest = destination.nonsecureMemory;
73            if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) {
74                _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "destination decrypt buffer base not set");
75                return Void();
76            }
77        }
78
79        android::CryptoPlugin::Mode legacyMode;
80        switch(mode) {
81        case Mode::UNENCRYPTED:
82            legacyMode = android::CryptoPlugin::kMode_Unencrypted;
83            break;
84        case Mode::AES_CTR:
85            legacyMode = android::CryptoPlugin::kMode_AES_CTR;
86            break;
87        case Mode::AES_CBC_CTS:
88            legacyMode = android::CryptoPlugin::kMode_AES_WV;
89            break;
90        case Mode::AES_CBC:
91            legacyMode = android::CryptoPlugin::kMode_AES_CBC;
92            break;
93        }
94        android::CryptoPlugin::Pattern legacyPattern;
95        legacyPattern.mEncryptBlocks = pattern.encryptBlocks;
96        legacyPattern.mSkipBlocks = pattern.skipBlocks;
97
98        android::CryptoPlugin::SubSample *legacySubSamples =
99            new android::CryptoPlugin::SubSample[subSamples.size()];
100
101        for (size_t i = 0; i < subSamples.size(); i++) {
102            legacySubSamples[i].mNumBytesOfClearData
103                = subSamples[i].numBytesOfClearData;
104            legacySubSamples[i].mNumBytesOfEncryptedData
105                = subSamples[i].numBytesOfEncryptedData;
106        }
107
108        AString detailMessage;
109        sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
110
111        if (source.offset + offset + source.size > sourceBase->getSize()) {
112            _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
113            return Void();
114        }
115
116        uint8_t *base = static_cast<uint8_t *>
117                (static_cast<void *>(sourceBase->getPointer()));
118        void *srcPtr = static_cast<void *>(base + source.offset + offset);
119
120        void *destPtr = NULL;
121        if (destination.type == BufferType::SHARED_MEMORY) {
122            const SharedBuffer& destBuffer = destination.nonsecureMemory;
123            sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
124            if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
125                _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
126                return Void();
127            }
128            destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
129        } else if (destination.type == BufferType::NATIVE_HANDLE) {
130            native_handle_t *handle = const_cast<native_handle_t *>(
131                    destination.secureMemory.getNativeHandle());
132            destPtr = static_cast<void *>(handle);
133        }
134        ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
135                legacyMode, legacyPattern, srcPtr, legacySubSamples,
136                subSamples.size(), destPtr, &detailMessage);
137
138        delete[] legacySubSamples;
139
140        uint32_t status;
141        uint32_t bytesWritten;
142
143        if (result >= 0) {
144            status = android::OK;
145            bytesWritten = result;
146        } else {
147            status = result;
148            bytesWritten = 0;
149        }
150
151        _hidl_cb(toStatus(status), bytesWritten, detailMessage.c_str());
152        return Void();
153    }
154
155} // namespace implementation
156}  // namespace V1_0
157}  // namespace drm
158}  // namespace hardware
159}  // namespace android
160