1 /*
2 * Copyright (C) 2014 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
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ClearKeyDrmPlugin"
19 #include <utils/Log.h>
20
21 #include <media/stagefright/MediaErrors.h>
22 #include <utils/StrongPointer.h>
23
24 #include "DrmPlugin.h"
25 #include "ClearKeyDrmProperties.h"
26 #include "Session.h"
27
28 namespace {
29 const android::String8 kStreaming("Streaming");
30 const android::String8 kOffline("Offline");
31 const android::String8 kTrue("True");
32
33 const android::String8 kQueryKeyLicenseType("LicenseType");
34 // Value: "Streaming" or "Offline"
35 const android::String8 kQueryKeyPlayAllowed("PlayAllowed");
36 // Value: "True" or "False"
37 const android::String8 kQueryKeyRenewAllowed("RenewAllowed");
38 // Value: "True" or "False"
39 };
40
41 namespace clearkeydrm {
42
43 using android::sp;
44
DrmPlugin(SessionLibrary * sessionLibrary)45 DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
46 : mSessionLibrary(sessionLibrary) {
47
48 mPlayPolicy.clear();
49 initProperties();
50 }
51
initProperties()52 void DrmPlugin::initProperties() {
53 mStringProperties.clear();
54 mStringProperties.add(kVendorKey, kVendorValue);
55 mStringProperties.add(kVersionKey, kVersionValue);
56 mStringProperties.add(kPluginDescriptionKey, kPluginDescriptionValue);
57 mStringProperties.add(kAlgorithmsKey, kAlgorithmsValue);
58 mStringProperties.add(kListenerTestSupportKey, kListenerTestSupportValue);
59
60 Vector<uint8_t> testDeviceId;
61 testDeviceId.appendArray(kTestDeviceIdData, sizeof(kTestDeviceIdData) / sizeof(uint8_t));
62 mByteArrayProperties.add(kDeviceIdKey, testDeviceId);
63 }
64
openSession(Vector<uint8_t> & sessionId)65 status_t DrmPlugin::openSession(Vector<uint8_t>& sessionId) {
66 sp<Session> session = mSessionLibrary->createSession();
67 sessionId = session->sessionId();
68 return android::OK;
69 }
70
closeSession(const Vector<uint8_t> & sessionId)71 status_t DrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
72 sp<Session> session = mSessionLibrary->findSession(sessionId);
73 if (sessionId.size() == 0) {
74 return android::BAD_VALUE;
75 }
76 if (session.get()) {
77 mSessionLibrary->destroySession(session);
78 return android::OK;
79 }
80 return android::ERROR_DRM_SESSION_NOT_OPENED;
81 }
82
getKeyRequest(const Vector<uint8_t> & scope,const Vector<uint8_t> & initData,const String8 & mimeType,KeyType keyType,const KeyedVector<String8,String8> & optionalParameters,Vector<uint8_t> & request,String8 & defaultUrl,DrmPlugin::KeyRequestType * keyRequestType)83 status_t DrmPlugin::getKeyRequest(
84 const Vector<uint8_t>& scope,
85 const Vector<uint8_t>& initData,
86 const String8& mimeType,
87 KeyType keyType,
88 const KeyedVector<String8, String8>& optionalParameters,
89 Vector<uint8_t>& request,
90 String8& defaultUrl,
91 DrmPlugin::KeyRequestType *keyRequestType) {
92 UNUSED(optionalParameters);
93 if (scope.size() == 0) {
94 return android::BAD_VALUE;
95 }
96
97 if (keyType != kKeyType_Streaming) {
98 return android::ERROR_DRM_CANNOT_HANDLE;
99 }
100
101 *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
102 defaultUrl.clear();
103 sp<Session> session = mSessionLibrary->findSession(scope);
104 if (!session.get()) {
105 return android::ERROR_DRM_SESSION_NOT_OPENED;
106 }
107
108 return session->getKeyRequest(initData, mimeType, &request);
109 }
110
setPlayPolicy()111 void DrmPlugin::setPlayPolicy() {
112 mPlayPolicy.clear();
113 mPlayPolicy.add(kQueryKeyLicenseType, kStreaming);
114 mPlayPolicy.add(kQueryKeyPlayAllowed, kTrue);
115 mPlayPolicy.add(kQueryKeyRenewAllowed, kTrue);
116 }
117
provideKeyResponse(const Vector<uint8_t> & scope,const Vector<uint8_t> & response,Vector<uint8_t> & keySetId)118 status_t DrmPlugin::provideKeyResponse(
119 const Vector<uint8_t>& scope,
120 const Vector<uint8_t>& response,
121 Vector<uint8_t>& keySetId) {
122 if (scope.size() == 0 || response.size() == 0) {
123 return android::BAD_VALUE;
124 }
125 sp<Session> session = mSessionLibrary->findSession(scope);
126 if (!session.get()) {
127 return android::ERROR_DRM_SESSION_NOT_OPENED;
128 }
129
130 setPlayPolicy();
131 status_t res = session->provideKeyResponse(response);
132 if (res == android::OK) {
133 // This is for testing AMediaDrm_setOnEventListener only.
134 sendEvent(kDrmPluginEventVendorDefined, 0, &scope, NULL);
135 keySetId.clear();
136 }
137 return res;
138 }
139
getPropertyByteArray(const String8 & name,Vector<uint8_t> & value) const140 status_t DrmPlugin::getPropertyByteArray(
141 const String8& name, Vector<uint8_t>& value) const {
142 ssize_t index = mByteArrayProperties.indexOfKey(name);
143 if (index < 0) {
144 ALOGE("App requested unknown property: %s", name.string());
145 return android::ERROR_DRM_CANNOT_HANDLE;
146 }
147 value = mByteArrayProperties.valueAt(index);
148 return android::OK;
149 }
150
setPropertyByteArray(const String8 & name,const Vector<uint8_t> & value)151 status_t DrmPlugin::setPropertyByteArray(
152 const String8& name, const Vector<uint8_t>& value)
153 {
154 UNUSED(value);
155 if (0 == name.compare(kDeviceIdKey)) {
156 ALOGD("Cannot set immutable property: %s", name.string());
157 return android::ERROR_DRM_CANNOT_HANDLE;
158 }
159
160 // Setting of undefined properties is not supported
161 ALOGE("Failed to set property byte array, key=%s", name.string());
162 return android::ERROR_DRM_CANNOT_HANDLE;
163 }
164
getPropertyString(const String8 & name,String8 & value) const165 status_t DrmPlugin::getPropertyString(
166 const String8& name, String8& value) const {
167 ssize_t index = mStringProperties.indexOfKey(name);
168 if (index < 0) {
169 ALOGE("App requested unknown property: %s", name.string());
170 return android::ERROR_DRM_CANNOT_HANDLE;
171 }
172 value = mStringProperties.valueAt(index);
173 return android::OK;
174 }
175
setPropertyString(const String8 & name,const String8 & value)176 status_t DrmPlugin::setPropertyString(
177 const String8& name, const String8& value) {
178 String8 immutableKeys;
179 immutableKeys.appendFormat("%s,%s,%s,%s",
180 kAlgorithmsKey.string(), kPluginDescriptionKey.string(),
181 kVendorKey.string(), kVersionKey.string());
182 if (immutableKeys.contains(name.string())) {
183 ALOGD("Cannot set immutable property: %s", name.string());
184 return android::ERROR_DRM_CANNOT_HANDLE;
185 }
186
187 ssize_t index = mStringProperties.indexOfKey(name);
188 if (index < 0) {
189 ALOGE("Cannot set undefined property string, key=%s", name.string());
190 return android::ERROR_DRM_CANNOT_HANDLE;
191 }
192
193 if (mStringProperties.add(name, value) < 0) {
194 ALOGE("Failed to set property string, key=%s", name.string());
195 return android::ERROR_DRM_UNKNOWN;
196 }
197 return android::OK;
198 }
199
queryKeyStatus(const Vector<uint8_t> & sessionId,KeyedVector<String8,String8> & infoMap) const200 status_t DrmPlugin::queryKeyStatus(
201 const Vector<uint8_t>& sessionId,
202 KeyedVector<String8, String8>& infoMap) const {
203
204 if (sessionId.size() == 0) {
205 return android::BAD_VALUE;
206 }
207
208 infoMap.clear();
209 for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
210 infoMap.add(mPlayPolicy.keyAt(i), mPlayPolicy.valueAt(i));
211 }
212 return android::OK;
213 }
214 } // namespace clearkeydrm
215