1 /*
2  * Copyright (C) 2018 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 "hidl_ClearKeyPlugin"
19 #include <utils/Log.h>
20 
21 #include <stdio.h>
22 #include <inttypes.h>
23 
24 #include "DrmPlugin.h"
25 #include "ClearKeyDrmProperties.h"
26 #include "Session.h"
27 #include "TypeConvert.h"
28 
29 namespace {
30 const int kSecureStopIdStart = 100;
31 const std::string kStreaming("Streaming");
32 const std::string kOffline("Offline");
33 const std::string kTrue("True");
34 
35 const std::string kQueryKeyLicenseType("LicenseType");
36     // Value: "Streaming" or "Offline"
37 const std::string kQueryKeyPlayAllowed("PlayAllowed");
38     // Value: "True" or "False"
39 const std::string kQueryKeyRenewAllowed("RenewAllowed");
40     // Value: "True" or "False"
41 
42 const int kSecureStopIdSize = 10;
43 
uint32ToVector(uint32_t value)44 std::vector<uint8_t> uint32ToVector(uint32_t value) {
45     // 10 bytes to display max value 4294967295 + one byte null terminator
46     char buffer[kSecureStopIdSize];
47     memset(buffer, 0, kSecureStopIdSize);
48     snprintf(buffer, kSecureStopIdSize, "%" PRIu32, value);
49     return std::vector<uint8_t>(buffer, buffer + sizeof(buffer));
50 }
51 
52 }; // unnamed namespace
53 
54 namespace android {
55 namespace hardware {
56 namespace drm {
57 namespace V1_1 {
58 namespace clearkey {
59 
DrmPlugin(SessionLibrary * sessionLibrary)60 DrmPlugin::DrmPlugin(SessionLibrary* sessionLibrary)
61         : mSessionLibrary(sessionLibrary),
62           mOpenSessionOkCount(0),
63           mCloseSessionOkCount(0),
64           mCloseSessionNotOpenedCount(0),
65           mNextSecureStopId(kSecureStopIdStart) {
66     mPlayPolicy.clear();
67     initProperties();
68     mSecureStops.clear();
69 }
70 
initProperties()71 void DrmPlugin::initProperties() {
72     mStringProperties.clear();
73     mStringProperties[kVendorKey] = kVendorValue;
74     mStringProperties[kVersionKey] = kVersionValue;
75     mStringProperties[kPluginDescriptionKey] = kPluginDescriptionValue;
76     mStringProperties[kAlgorithmsKey] = kAlgorithmsValue;
77     mStringProperties[kListenerTestSupportKey] = kListenerTestSupportValue;
78 
79     std::vector<uint8_t> valueVector;
80     valueVector.clear();
81     valueVector.insert(valueVector.end(),
82             kTestDeviceIdData, kTestDeviceIdData + sizeof(kTestDeviceIdData) / sizeof(uint8_t));
83     mByteArrayProperties[kDeviceIdKey] = valueVector;
84 
85     valueVector.clear();
86     valueVector.insert(valueVector.end(),
87             kMetricsData, kMetricsData + sizeof(kMetricsData) / sizeof(uint8_t));
88     mByteArrayProperties[kMetricsKey] = valueVector;
89 }
90 
91 // The secure stop in ClearKey implementation is not installed securely.
92 // This function merely creates a test environment for testing secure stops APIs.
93 // The content in this secure stop is implementation dependent, the clearkey
94 // secureStop does not serve as a reference implementation.
installSecureStop(const hidl_vec<uint8_t> & sessionId)95 void DrmPlugin::installSecureStop(const hidl_vec<uint8_t>& sessionId) {
96     ClearkeySecureStop clearkeySecureStop;
97     clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
98     clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
99 
100     mSecureStops.insert(std::pair<std::vector<uint8_t>, ClearkeySecureStop>(
101             clearkeySecureStop.id, clearkeySecureStop));
102 }
103 
openSession(openSession_cb _hidl_cb)104 Return<void> DrmPlugin::openSession(openSession_cb _hidl_cb) {
105     sp<Session> session = mSessionLibrary->createSession();
106     std::vector<uint8_t> sessionId = session->sessionId();
107 
108     Status status = setSecurityLevel(sessionId, SecurityLevel::SW_SECURE_CRYPTO);
109     _hidl_cb(status, toHidlVec(sessionId));
110     mOpenSessionOkCount++;
111     return Void();
112 }
113 
openSession_1_1(SecurityLevel securityLevel,openSession_1_1_cb _hidl_cb)114 Return<void> DrmPlugin::openSession_1_1(SecurityLevel securityLevel,
115         openSession_1_1_cb _hidl_cb) {
116     sp<Session> session = mSessionLibrary->createSession();
117     std::vector<uint8_t> sessionId = session->sessionId();
118 
119     Status status = setSecurityLevel(sessionId, securityLevel);
120     _hidl_cb(status, toHidlVec(sessionId));
121     mOpenSessionOkCount++;
122     return Void();
123 }
124 
closeSession(const hidl_vec<uint8_t> & sessionId)125 Return<Status> DrmPlugin::closeSession(const hidl_vec<uint8_t>& sessionId) {
126     if (sessionId.size() == 0) {
127         return Status::BAD_VALUE;
128     }
129 
130     sp<Session> session = mSessionLibrary->findSession(toVector(sessionId));
131     if (session.get()) {
132         mCloseSessionOkCount++;
133         mSessionLibrary->destroySession(session);
134         return Status::OK;
135     }
136     mCloseSessionNotOpenedCount++;
137     return Status::ERROR_DRM_SESSION_NOT_OPENED;
138 }
139 
getKeyRequestCommon(const hidl_vec<uint8_t> & scope,const hidl_vec<uint8_t> & initData,const hidl_string & mimeType,KeyType keyType,const hidl_vec<KeyValue> & optionalParameters,std::vector<uint8_t> * request,KeyRequestType * keyRequestType,std::string * defaultUrl)140 Status DrmPlugin::getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
141         const hidl_vec<uint8_t>& initData,
142         const hidl_string& mimeType,
143         KeyType keyType,
144         const hidl_vec<KeyValue>& optionalParameters,
145         std::vector<uint8_t> *request,
146         KeyRequestType *keyRequestType,
147         std::string *defaultUrl) {
148         UNUSED(optionalParameters);
149 
150     *defaultUrl = "";
151     *keyRequestType = KeyRequestType::UNKNOWN;
152     *request = std::vector<uint8_t>();
153 
154     if (scope.size() == 0) {
155         return Status::BAD_VALUE;
156     }
157 
158     if (keyType != KeyType::STREAMING) {
159         return Status::ERROR_DRM_CANNOT_HANDLE;
160     }
161 
162     sp<Session> session = mSessionLibrary->findSession(toVector(scope));
163     if (!session.get()) {
164         return Status::ERROR_DRM_SESSION_NOT_OPENED;
165     }
166 
167     Status status = session->getKeyRequest(initData, mimeType, request);
168     *keyRequestType = KeyRequestType::INITIAL;
169     return status;
170 }
171 
getKeyRequest(const hidl_vec<uint8_t> & scope,const hidl_vec<uint8_t> & initData,const hidl_string & mimeType,KeyType keyType,const hidl_vec<KeyValue> & optionalParameters,getKeyRequest_cb _hidl_cb)172 Return<void> DrmPlugin::getKeyRequest(
173         const hidl_vec<uint8_t>& scope,
174         const hidl_vec<uint8_t>& initData,
175         const hidl_string& mimeType,
176         KeyType keyType,
177         const hidl_vec<KeyValue>& optionalParameters,
178         getKeyRequest_cb _hidl_cb) {
179     UNUSED(optionalParameters);
180 
181     KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
182     std::string defaultUrl("");
183     std::vector<uint8_t> request;
184     Status status = getKeyRequestCommon(
185             scope, initData, mimeType, keyType, optionalParameters,
186             &request, &keyRequestType, &defaultUrl);
187 
188     _hidl_cb(status, toHidlVec(request),
189             static_cast<drm::V1_0::KeyRequestType>(keyRequestType),
190             hidl_string(defaultUrl));
191     return Void();
192 }
193 
getKeyRequest_1_1(const hidl_vec<uint8_t> & scope,const hidl_vec<uint8_t> & initData,const hidl_string & mimeType,KeyType keyType,const hidl_vec<KeyValue> & optionalParameters,getKeyRequest_1_1_cb _hidl_cb)194 Return<void> DrmPlugin::getKeyRequest_1_1(
195         const hidl_vec<uint8_t>& scope,
196         const hidl_vec<uint8_t>& initData,
197         const hidl_string& mimeType,
198         KeyType keyType,
199         const hidl_vec<KeyValue>& optionalParameters,
200         getKeyRequest_1_1_cb _hidl_cb) {
201     UNUSED(optionalParameters);
202 
203     KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
204     std::string defaultUrl("");
205     std::vector<uint8_t> request;
206     Status status = getKeyRequestCommon(
207             scope, initData, mimeType, keyType, optionalParameters,
208             &request, &keyRequestType, &defaultUrl);
209 
210     _hidl_cb(status, toHidlVec(request), keyRequestType, hidl_string(defaultUrl));
211     return Void();
212 }
213 
setPlayPolicy()214 void DrmPlugin::setPlayPolicy() {
215     mPlayPolicy.clear();
216 
217     KeyValue policy;
218     policy.key = kQueryKeyLicenseType;
219     policy.value = kStreaming;
220     mPlayPolicy.push_back(policy);
221 
222     policy.key = kQueryKeyPlayAllowed;
223     policy.value = kTrue;
224     mPlayPolicy.push_back(policy);
225 
226     policy.key = kQueryKeyRenewAllowed;
227     mPlayPolicy.push_back(policy);
228 }
229 
provideKeyResponse(const hidl_vec<uint8_t> & scope,const hidl_vec<uint8_t> & response,provideKeyResponse_cb _hidl_cb)230 Return<void> DrmPlugin::provideKeyResponse(
231         const hidl_vec<uint8_t>& scope,
232         const hidl_vec<uint8_t>& response,
233         provideKeyResponse_cb _hidl_cb) {
234     if (scope.size() == 0 || response.size() == 0) {
235         // Returns empty keySetId
236         _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>());
237         return Void();
238     }
239 
240     sp<Session> session = mSessionLibrary->findSession(toVector(scope));
241     if (!session.get()) {
242         _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>());
243         return Void();
244     }
245 
246     setPlayPolicy();
247     std::vector<uint8_t> keySetId;
248     Status status = session->provideKeyResponse(response);
249     if (status == Status::OK) {
250         // This is for testing AMediaDrm_setOnEventListener only.
251         sendEvent(EventType::VENDOR_DEFINED, 0, scope);
252         keySetId.clear();
253     }
254 
255     installSecureStop(scope);
256 
257     // Returns status and empty keySetId
258     _hidl_cb(status, toHidlVec(keySetId));
259     return Void();
260 }
261 
getPropertyString(const hidl_string & propertyName,getPropertyString_cb _hidl_cb)262 Return<void> DrmPlugin::getPropertyString(
263         const hidl_string& propertyName, getPropertyString_cb _hidl_cb) {
264     std::string name(propertyName.c_str());
265     std::string value;
266 
267     if (name == kVendorKey) {
268         value = mStringProperties[kVendorKey];
269     } else if (name == kVersionKey) {
270         value = mStringProperties[kVersionKey];
271     } else if (name == kPluginDescriptionKey) {
272         value = mStringProperties[kPluginDescriptionKey];
273     } else if (name == kAlgorithmsKey) {
274         value = mStringProperties[kAlgorithmsKey];
275     } else if (name == kListenerTestSupportKey) {
276         value = mStringProperties[kListenerTestSupportKey];
277     } else {
278         ALOGE("App requested unknown string property %s", name.c_str());
279         _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, "");
280         return Void();
281     }
282     _hidl_cb(Status::OK, value.c_str());
283     return Void();
284 }
285 
getPropertyByteArray(const hidl_string & propertyName,getPropertyByteArray_cb _hidl_cb)286 Return<void> DrmPlugin::getPropertyByteArray(
287         const hidl_string& propertyName, getPropertyByteArray_cb _hidl_cb) {
288     std::map<std::string, std::vector<uint8_t> >::iterator itr =
289             mByteArrayProperties.find(std::string(propertyName.c_str()));
290     if (itr == mByteArrayProperties.end()) {
291         ALOGE("App requested unknown property: %s", propertyName.c_str());
292         _hidl_cb(Status::BAD_VALUE, std::vector<uint8_t>());
293         return Void();
294     }
295     _hidl_cb(Status::OK, itr->second);
296     return Void();
297 
298 }
299 
setPropertyString(const hidl_string & name,const hidl_string & value)300 Return<Status> DrmPlugin::setPropertyString(
301     const hidl_string& name, const hidl_string& value) {
302     std::string immutableKeys;
303     immutableKeys.append(kAlgorithmsKey + ",");
304     immutableKeys.append(kPluginDescriptionKey + ",");
305     immutableKeys.append(kVendorKey + ",");
306     immutableKeys.append(kVersionKey + ",");
307 
308     std::string key = std::string(name.c_str());
309     if (immutableKeys.find(key) != std::string::npos) {
310         ALOGD("Cannot set immutable property: %s", key.c_str());
311         return Status::BAD_VALUE;
312     }
313 
314     std::map<std::string, std::string>::iterator itr =
315             mStringProperties.find(key);
316     if (itr == mStringProperties.end()) {
317         ALOGE("Cannot set undefined property string, key=%s", key.c_str());
318         return Status::BAD_VALUE;
319     }
320 
321     mStringProperties[key] = std::string(value.c_str());
322     return Status::OK;
323 }
324 
setPropertyByteArray(const hidl_string & name,const hidl_vec<uint8_t> & value)325 Return<Status> DrmPlugin::setPropertyByteArray(
326     const hidl_string& name, const hidl_vec<uint8_t>& value) {
327    UNUSED(value);
328    if (name == kDeviceIdKey) {
329       ALOGD("Cannot set immutable property: %s", name.c_str());
330       return Status::BAD_VALUE;
331    }
332 
333    // Setting of undefined properties is not supported
334    ALOGE("Failed to set property byte array, key=%s", name.c_str());
335    return Status::ERROR_DRM_CANNOT_HANDLE;
336 }
337 
queryKeyStatus(const hidl_vec<uint8_t> & sessionId,queryKeyStatus_cb _hidl_cb)338 Return<void> DrmPlugin::queryKeyStatus(
339         const hidl_vec<uint8_t>& sessionId,
340         queryKeyStatus_cb _hidl_cb) {
341 
342     if (sessionId.size() == 0) {
343         // Returns empty key status KeyValue pair
344         _hidl_cb(Status::BAD_VALUE, hidl_vec<KeyValue>());
345         return Void();
346     }
347 
348     std::vector<KeyValue> infoMapVec;
349     infoMapVec.clear();
350 
351     KeyValue keyValuePair;
352     for (size_t i = 0; i < mPlayPolicy.size(); ++i) {
353         keyValuePair.key = mPlayPolicy[i].key;
354         keyValuePair.value = mPlayPolicy[i].value;
355         infoMapVec.push_back(keyValuePair);
356     }
357     _hidl_cb(Status::OK, toHidlVec(infoMapVec));
358     return Void();
359 }
360 
getNumberOfSessions(getNumberOfSessions_cb _hidl_cb)361 Return<void> DrmPlugin::getNumberOfSessions(getNumberOfSessions_cb _hidl_cb) {
362         uint32_t currentSessions = mSessionLibrary->numOpenSessions();
363         uint32_t maxSessions = 10;
364         _hidl_cb(Status::OK, currentSessions, maxSessions);
365         return Void();
366 }
367 
getSecurityLevel(const hidl_vec<uint8_t> & sessionId,getSecurityLevel_cb _hidl_cb)368 Return<void> DrmPlugin::getSecurityLevel(const hidl_vec<uint8_t>& sessionId,
369             getSecurityLevel_cb _hidl_cb) {
370     if (sessionId.size() == 0) {
371         _hidl_cb(Status::BAD_VALUE, SecurityLevel::UNKNOWN);
372         return Void();
373     }
374 
375     std::vector<uint8_t> sid = toVector(sessionId);
376     sp<Session> session = mSessionLibrary->findSession(sid);
377     if (!session.get()) {
378         _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, SecurityLevel::UNKNOWN);
379         return Void();
380     }
381 
382     std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr =
383             mSecurityLevel.find(sid);
384     if (itr == mSecurityLevel.end()) {
385         ALOGE("Session id not found");
386         _hidl_cb(Status::ERROR_DRM_INVALID_STATE, SecurityLevel::UNKNOWN);
387         return Void();
388     }
389 
390     _hidl_cb(Status::OK, itr->second);
391     return Void();
392 }
393 
setSecurityLevel(const hidl_vec<uint8_t> & sessionId,SecurityLevel level)394 Return<Status> DrmPlugin::setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
395             SecurityLevel level) {
396     if (sessionId.size() == 0) {
397         ALOGE("Invalid empty session id");
398         return Status::BAD_VALUE;
399     }
400 
401     if (level > SecurityLevel::SW_SECURE_CRYPTO) {
402         ALOGE("Cannot set security level > max");
403         return Status::ERROR_DRM_CANNOT_HANDLE;
404     }
405 
406     std::vector<uint8_t> sid = toVector(sessionId);
407     sp<Session> session = mSessionLibrary->findSession(sid);
408     if (!session.get()) {
409         return Status::ERROR_DRM_SESSION_NOT_OPENED;
410     }
411 
412     std::map<std::vector<uint8_t>, SecurityLevel>::iterator itr =
413             mSecurityLevel.find(sid);
414     if (itr != mSecurityLevel.end()) {
415         mSecurityLevel[sid] = level;
416     } else {
417         if (!mSecurityLevel.insert(
418                 std::pair<std::vector<uint8_t>, SecurityLevel>(sid, level)).second) {
419             ALOGE("Failed to set security level");
420             return Status::ERROR_DRM_INVALID_STATE;
421         }
422     }
423     return Status::OK;
424 }
425 
getMetrics(getMetrics_cb _hidl_cb)426 Return<void> DrmPlugin::getMetrics(getMetrics_cb _hidl_cb) {
427     // Set the open session count metric.
428     DrmMetricGroup::Attribute openSessionOkAttribute = {
429       "status", DrmMetricGroup::ValueType::INT64_TYPE, (int64_t) Status::OK, 0.0, ""
430     };
431     DrmMetricGroup::Value openSessionMetricValue = {
432       "count", DrmMetricGroup::ValueType::INT64_TYPE, mOpenSessionOkCount, 0.0, ""
433     };
434     DrmMetricGroup::Metric openSessionMetric = {
435       "open_session", { openSessionOkAttribute }, { openSessionMetricValue }
436     };
437 
438     // Set the close session count metric.
439     DrmMetricGroup::Attribute closeSessionOkAttribute = {
440       "status", DrmMetricGroup::ValueType::INT64_TYPE, (int64_t) Status::OK, 0.0, ""
441     };
442     DrmMetricGroup::Value closeSessionMetricValue = {
443       "count", DrmMetricGroup::ValueType::INT64_TYPE, mCloseSessionOkCount, 0.0, ""
444     };
445     DrmMetricGroup::Metric closeSessionMetric = {
446       "close_session", { closeSessionOkAttribute }, { closeSessionMetricValue }
447     };
448 
449     // Set the close session, not opened metric.
450     DrmMetricGroup::Attribute closeSessionNotOpenedAttribute = {
451       "status", DrmMetricGroup::ValueType::INT64_TYPE,
452       (int64_t) Status::ERROR_DRM_SESSION_NOT_OPENED, 0.0, ""
453     };
454     DrmMetricGroup::Value closeSessionNotOpenedMetricValue = {
455       "count", DrmMetricGroup::ValueType::INT64_TYPE, mCloseSessionNotOpenedCount, 0.0, ""
456     };
457     DrmMetricGroup::Metric closeSessionNotOpenedMetric = {
458       "close_session", { closeSessionNotOpenedAttribute }, { closeSessionNotOpenedMetricValue }
459     };
460 
461     DrmMetricGroup metrics = { { openSessionMetric, closeSessionMetric,
462                                 closeSessionNotOpenedMetric } };
463 
464     _hidl_cb(Status::OK, hidl_vec<DrmMetricGroup>({metrics}));
465     return Void();
466 }
467 
getSecureStops(getSecureStops_cb _hidl_cb)468 Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) {
469     std::vector<SecureStop> stops;
470     for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
471         ClearkeySecureStop clearkeyStop = itr->second;
472         std::vector<uint8_t> stopVec;
473         stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
474         stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
475 
476         SecureStop stop;
477         stop.opaqueData = toHidlVec(stopVec);
478         stops.push_back(stop);
479     }
480     _hidl_cb(Status::OK, stops);
481     return Void();
482 }
483 
getSecureStop(const hidl_vec<uint8_t> & secureStopId,getSecureStop_cb _hidl_cb)484 Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId,
485         getSecureStop_cb _hidl_cb) {
486     SecureStop stop;
487     auto itr = mSecureStops.find(toVector(secureStopId));
488     if (itr != mSecureStops.end()) {
489         ClearkeySecureStop clearkeyStop = itr->second;
490         std::vector<uint8_t> stopVec;
491         stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
492         stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
493 
494         stop.opaqueData = toHidlVec(stopVec);
495         _hidl_cb(Status::OK, stop);
496     } else {
497         _hidl_cb(Status::BAD_VALUE, stop);
498     }
499 
500     return Void();
501 }
502 
releaseSecureStop(const hidl_vec<uint8_t> & secureStopId)503 Return<Status> DrmPlugin::releaseSecureStop(const hidl_vec<uint8_t>& secureStopId) {
504     return removeSecureStop(secureStopId);
505 }
506 
releaseAllSecureStops()507 Return<Status> DrmPlugin::releaseAllSecureStops() {
508     return removeAllSecureStops();
509 }
510 
getSecureStopIds(getSecureStopIds_cb _hidl_cb)511 Return<void> DrmPlugin::getSecureStopIds(getSecureStopIds_cb _hidl_cb) {
512     std::vector<SecureStopId> ids;
513     for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
514         ids.push_back(itr->first);
515     }
516 
517     _hidl_cb(Status::OK, toHidlVec(ids));
518     return Void();
519 }
520 
releaseSecureStops(const SecureStopRelease & ssRelease)521 Return<Status> DrmPlugin::releaseSecureStops(const SecureStopRelease& ssRelease) {
522     if (ssRelease.opaqueData.size() == 0) {
523         return Status::BAD_VALUE;
524     }
525 
526     Status status = Status::OK;
527     std::vector<uint8_t> input = toVector(ssRelease.opaqueData);
528 
529     // The format of opaqueData is shared between the server
530     // and the drm service. The clearkey implementation consists of:
531     //    count - number of secure stops
532     //    list of fixed length secure stops
533     size_t countBufferSize = sizeof(uint32_t);
534     uint32_t count = 0;
535     sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
536 
537     // Avoid divide by 0 below.
538     if (count == 0) {
539         return Status::BAD_VALUE;
540     }
541 
542     size_t secureStopSize = (input.size() - countBufferSize) / count;
543     uint8_t buffer[secureStopSize];
544     size_t offset = countBufferSize; // skip the count
545     for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
546         memcpy(buffer, input.data() + offset, secureStopSize);
547         std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
548 
549         status = removeSecureStop(toHidlVec(id));
550         if (Status::OK != status) break;
551     }
552 
553     return status;
554 }
555 
removeSecureStop(const hidl_vec<uint8_t> & secureStopId)556 Return<Status> DrmPlugin::removeSecureStop(const hidl_vec<uint8_t>& secureStopId) {
557     if (1 != mSecureStops.erase(toVector(secureStopId))) {
558         return Status::BAD_VALUE;
559     }
560     return Status::OK;
561 }
562 
removeAllSecureStops()563 Return<Status> DrmPlugin::removeAllSecureStops() {
564     mSecureStops.clear();
565     mNextSecureStopId = kSecureStopIdStart;
566     return Status::OK;
567 }
568 
569 }  // namespace clearkey
570 }  // namespace V1_1
571 }  // namespace drm
572 }  // namespace hardware
573 }  // namespace android
574