DrmHal.cpp revision fb679e38bbc91614faa917024adddeb51ff07d0a
1/*
2 * Copyright (C) 2017 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 "DrmHal"
19#include <iomanip>
20
21#include <utils/Log.h>
22
23#include <binder/IPCThreadState.h>
24#include <binder/IServiceManager.h>
25
26#include <android/hardware/drm/1.0/types.h>
27#include <android/hidl/manager/1.0/IServiceManager.h>
28#include <hidl/ServiceManagement.h>
29
30#include <media/DrmHal.h>
31#include <media/DrmSessionClientInterface.h>
32#include <media/DrmSessionManager.h>
33#include <media/EventMetric.h>
34#include <media/PluginMetricsReporting.h>
35#include <media/drm/DrmAPI.h>
36#include <media/stagefright/foundation/ADebug.h>
37#include <media/stagefright/foundation/AString.h>
38#include <media/stagefright/foundation/hexdump.h>
39#include <media/stagefright/MediaErrors.h>
40
41using drm::V1_0::KeyedVector;
42using drm::V1_0::KeyStatusType;
43using drm::V1_0::KeyType;
44using drm::V1_0::KeyValue;
45using drm::V1_1::HdcpLevel;;
46using drm::V1_0::SecureStop;
47using drm::V1_1::SecureStopRelease;
48using drm::V1_0::SecureStopId;
49using drm::V1_1::SecurityLevel;
50using drm::V1_0::Status;
51using ::android::hardware::hidl_array;
52using ::android::hardware::hidl_string;
53using ::android::hardware::hidl_vec;
54using ::android::hardware::Return;
55using ::android::hardware::Void;
56using ::android::hidl::manager::V1_0::IServiceManager;
57using ::android::os::PersistableBundle;
58using ::android::sp;
59
60namespace {
61
62// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
63// in the MediaDrm API.
64constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
65
66}
67
68namespace android {
69
70#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
71
72static inline int getCallingPid() {
73    return IPCThreadState::self()->getCallingPid();
74}
75
76static bool checkPermission(const char* permissionString) {
77    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
78    bool ok = checkCallingPermission(String16(permissionString));
79    if (!ok) ALOGE("Request requires %s", permissionString);
80    return ok;
81}
82
83static const Vector<uint8_t> toVector(const hidl_vec<uint8_t> &vec) {
84    Vector<uint8_t> vector;
85    vector.appendArray(vec.data(), vec.size());
86    return *const_cast<const Vector<uint8_t> *>(&vector);
87}
88
89static hidl_vec<uint8_t> toHidlVec(const Vector<uint8_t> &vector) {
90    hidl_vec<uint8_t> vec;
91    vec.setToExternal(const_cast<uint8_t *>(vector.array()), vector.size());
92    return vec;
93}
94
95static String8 toString8(const hidl_string &string) {
96    return String8(string.c_str());
97}
98
99static hidl_string toHidlString(const String8& string) {
100    return hidl_string(string.string());
101}
102
103std::string ToHexString(const std::string& str) {
104  std::ostringstream out;
105  out << std::hex << std::setfill('0');
106  for (size_t i = 0; i < str.size(); i++) {
107    out << std::setw(2) << (int)(str[i]);
108  }
109  return out.str();
110}
111
112static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
113    switch(level) {
114    case SecurityLevel::SW_SECURE_CRYPTO:
115        return DrmPlugin::kSecurityLevelSwSecureCrypto;
116    case SecurityLevel::SW_SECURE_DECODE:
117        return DrmPlugin::kSecurityLevelSwSecureDecode;
118    case SecurityLevel::HW_SECURE_CRYPTO:
119        return DrmPlugin::kSecurityLevelHwSecureCrypto;
120    case SecurityLevel::HW_SECURE_DECODE:
121        return DrmPlugin::kSecurityLevelHwSecureDecode;
122    case SecurityLevel::HW_SECURE_ALL:
123        return DrmPlugin::kSecurityLevelHwSecureAll;
124    default:
125        return DrmPlugin::kSecurityLevelUnknown;
126    }
127}
128
129static DrmPlugin::HdcpLevel toHdcpLevel(HdcpLevel level) {
130    switch(level) {
131    case HdcpLevel::HDCP_NONE:
132        return DrmPlugin::kHdcpNone;
133    case HdcpLevel::HDCP_V1:
134        return DrmPlugin::kHdcpV1;
135    case HdcpLevel::HDCP_V2:
136        return DrmPlugin::kHdcpV2;
137    case HdcpLevel::HDCP_V2_1:
138        return DrmPlugin::kHdcpV2_1;
139    case HdcpLevel::HDCP_V2_2:
140        return DrmPlugin::kHdcpV2_2;
141    case HdcpLevel::HDCP_NO_OUTPUT:
142        return DrmPlugin::kHdcpNoOutput;
143    default:
144        return DrmPlugin::kHdcpLevelUnknown;
145    }
146}
147
148
149static ::KeyedVector toHidlKeyedVector(const KeyedVector<String8, String8>&
150        keyedVector) {
151    std::vector<KeyValue> stdKeyedVector;
152    for (size_t i = 0; i < keyedVector.size(); i++) {
153        KeyValue keyValue;
154        keyValue.key = toHidlString(keyedVector.keyAt(i));
155        keyValue.value = toHidlString(keyedVector.valueAt(i));
156        stdKeyedVector.push_back(keyValue);
157    }
158    return ::KeyedVector(stdKeyedVector);
159}
160
161static KeyedVector<String8, String8> toKeyedVector(const ::KeyedVector&
162        hKeyedVector) {
163    KeyedVector<String8, String8> keyedVector;
164    for (size_t i = 0; i < hKeyedVector.size(); i++) {
165        keyedVector.add(toString8(hKeyedVector[i].key),
166                toString8(hKeyedVector[i].value));
167    }
168    return keyedVector;
169}
170
171static List<Vector<uint8_t>> toSecureStops(const hidl_vec<SecureStop>&
172        hSecureStops) {
173    List<Vector<uint8_t>> secureStops;
174    for (size_t i = 0; i < hSecureStops.size(); i++) {
175        secureStops.push_back(toVector(hSecureStops[i].opaqueData));
176    }
177    return secureStops;
178}
179
180static List<Vector<uint8_t>> toSecureStopIds(const hidl_vec<SecureStopId>&
181        hSecureStopIds) {
182    List<Vector<uint8_t>> secureStopIds;
183    for (size_t i = 0; i < hSecureStopIds.size(); i++) {
184        secureStopIds.push_back(toVector(hSecureStopIds[i]));
185    }
186    return secureStopIds;
187}
188
189static status_t toStatusT(Status status) {
190    switch (status) {
191    case Status::OK:
192        return OK;
193        break;
194    case Status::ERROR_DRM_NO_LICENSE:
195        return ERROR_DRM_NO_LICENSE;
196        break;
197    case Status::ERROR_DRM_LICENSE_EXPIRED:
198        return ERROR_DRM_LICENSE_EXPIRED;
199        break;
200    case Status::ERROR_DRM_SESSION_NOT_OPENED:
201        return ERROR_DRM_SESSION_NOT_OPENED;
202        break;
203    case Status::ERROR_DRM_CANNOT_HANDLE:
204        return ERROR_DRM_CANNOT_HANDLE;
205        break;
206    case Status::ERROR_DRM_INVALID_STATE:
207        return ERROR_DRM_TAMPER_DETECTED;
208        break;
209    case Status::BAD_VALUE:
210        return BAD_VALUE;
211        break;
212    case Status::ERROR_DRM_NOT_PROVISIONED:
213        return ERROR_DRM_NOT_PROVISIONED;
214        break;
215    case Status::ERROR_DRM_RESOURCE_BUSY:
216        return ERROR_DRM_RESOURCE_BUSY;
217        break;
218    case Status::ERROR_DRM_DEVICE_REVOKED:
219        return ERROR_DRM_DEVICE_REVOKED;
220        break;
221    case Status::ERROR_DRM_UNKNOWN:
222    default:
223        return ERROR_DRM_UNKNOWN;
224        break;
225    }
226}
227
228
229Mutex DrmHal::mLock;
230
231struct DrmSessionClient : public DrmSessionClientInterface {
232    explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}
233
234    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
235        sp<DrmHal> drm = mDrm.promote();
236        if (drm == NULL) {
237            return true;
238        }
239        status_t err = drm->closeSession(sessionId);
240        if (err != OK) {
241            return false;
242        }
243        drm->sendEvent(EventType::SESSION_RECLAIMED,
244                toHidlVec(sessionId), hidl_vec<uint8_t>());
245        return true;
246    }
247
248protected:
249    virtual ~DrmSessionClient() {}
250
251private:
252    wp<DrmHal> mDrm;
253
254    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
255};
256
257DrmHal::DrmHal()
258   : mDrmSessionClient(new DrmSessionClient(this)),
259     mFactories(makeDrmFactories()),
260     mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
261}
262
263void DrmHal::closeOpenSessions() {
264    if (mPlugin != NULL) {
265        for (size_t i = 0; i < mOpenSessions.size(); i++) {
266            mPlugin->closeSession(toHidlVec(mOpenSessions[i]));
267            DrmSessionManager::Instance()->removeSession(mOpenSessions[i]);
268        }
269    }
270    mOpenSessions.clear();
271}
272
273DrmHal::~DrmHal() {
274    closeOpenSessions();
275    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
276}
277
278Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
279    Vector<sp<IDrmFactory>> factories;
280
281    auto manager = hardware::defaultServiceManager();
282
283    if (manager != NULL) {
284        manager->listByInterface(drm::V1_0::IDrmFactory::descriptor,
285                [&factories](const hidl_vec<hidl_string> &registered) {
286                    for (const auto &instance : registered) {
287                        auto factory = drm::V1_0::IDrmFactory::getService(instance);
288                        if (factory != NULL) {
289                            ALOGD("found drm@1.0 IDrmFactory %s", instance.c_str());
290                            factories.push_back(factory);
291                        }
292                    }
293                }
294            );
295        manager->listByInterface(drm::V1_1::IDrmFactory::descriptor,
296                [&factories](const hidl_vec<hidl_string> &registered) {
297                    for (const auto &instance : registered) {
298                        auto factory = drm::V1_1::IDrmFactory::getService(instance);
299                        if (factory != NULL) {
300                            ALOGD("found drm@1.1 IDrmFactory %s", instance.c_str());
301                            factories.push_back(factory);
302                        }
303                    }
304                }
305            );
306    }
307
308    if (factories.size() == 0) {
309        // must be in passthrough mode, load the default passthrough service
310        auto passthrough = IDrmFactory::getService();
311        if (passthrough != NULL) {
312            ALOGI("makeDrmFactories: using default passthrough drm instance");
313            factories.push_back(passthrough);
314        } else {
315            ALOGE("Failed to find any drm factories");
316        }
317    }
318    return factories;
319}
320
321sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
322        const uint8_t uuid[16], const String8& appPackageName) {
323    mMetrics.SetAppPackageName(appPackageName);
324
325    sp<IDrmPlugin> plugin;
326    Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
327            [&](Status status, const sp<IDrmPlugin>& hPlugin) {
328                if (status != Status::OK) {
329                    ALOGE("Failed to make drm plugin");
330                    return;
331                }
332                plugin = hPlugin;
333            }
334        );
335
336    if (!hResult.isOk()) {
337        ALOGE("createPlugin remote call failed");
338    }
339
340    return plugin;
341}
342
343status_t DrmHal::initCheck() const {
344    return mInitCheck;
345}
346
347status_t DrmHal::setListener(const sp<IDrmClient>& listener)
348{
349    Mutex::Autolock lock(mEventLock);
350    if (mListener != NULL){
351        IInterface::asBinder(mListener)->unlinkToDeath(this);
352    }
353    if (listener != NULL) {
354        IInterface::asBinder(listener)->linkToDeath(this);
355    }
356    mListener = listener;
357    return NO_ERROR;
358}
359
360Return<void> DrmHal::sendEvent(EventType hEventType,
361        const hidl_vec<uint8_t>& sessionId, const hidl_vec<uint8_t>& data) {
362    mMetrics.mEventCounter.Increment(hEventType);
363
364    mEventLock.lock();
365    sp<IDrmClient> listener = mListener;
366    mEventLock.unlock();
367
368    if (listener != NULL) {
369        Parcel obj;
370        writeByteArray(obj, sessionId);
371        writeByteArray(obj, data);
372
373        Mutex::Autolock lock(mNotifyLock);
374        DrmPlugin::EventType eventType;
375        switch(hEventType) {
376        case EventType::PROVISION_REQUIRED:
377            eventType = DrmPlugin::kDrmPluginEventProvisionRequired;
378            break;
379        case EventType::KEY_NEEDED:
380            eventType = DrmPlugin::kDrmPluginEventKeyNeeded;
381            break;
382        case EventType::KEY_EXPIRED:
383            eventType = DrmPlugin::kDrmPluginEventKeyExpired;
384            break;
385        case EventType::VENDOR_DEFINED:
386            eventType = DrmPlugin::kDrmPluginEventVendorDefined;
387            break;
388        case EventType::SESSION_RECLAIMED:
389            eventType = DrmPlugin::kDrmPluginEventSessionReclaimed;
390            break;
391        default:
392            return Void();
393        }
394        listener->notify(eventType, 0, &obj);
395    }
396    return Void();
397}
398
399Return<void> DrmHal::sendExpirationUpdate(const hidl_vec<uint8_t>& sessionId,
400        int64_t expiryTimeInMS) {
401
402    mEventLock.lock();
403    sp<IDrmClient> listener = mListener;
404    mEventLock.unlock();
405
406    if (listener != NULL) {
407        Parcel obj;
408        writeByteArray(obj, sessionId);
409        obj.writeInt64(expiryTimeInMS);
410
411        Mutex::Autolock lock(mNotifyLock);
412        listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
413    }
414    return Void();
415}
416
417Return<void> DrmHal::sendKeysChange(const hidl_vec<uint8_t>& sessionId,
418        const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
419
420    mEventLock.lock();
421    sp<IDrmClient> listener = mListener;
422    mEventLock.unlock();
423
424    if (listener != NULL) {
425        Parcel obj;
426        writeByteArray(obj, sessionId);
427
428        size_t nKeys = keyStatusList.size();
429        obj.writeInt32(nKeys);
430        for (size_t i = 0; i < nKeys; ++i) {
431            const KeyStatus &keyStatus = keyStatusList[i];
432            writeByteArray(obj, keyStatus.keyId);
433            uint32_t type;
434            switch(keyStatus.type) {
435            case KeyStatusType::USABLE:
436                type = DrmPlugin::kKeyStatusType_Usable;
437                break;
438            case KeyStatusType::EXPIRED:
439                type = DrmPlugin::kKeyStatusType_Expired;
440                break;
441            case KeyStatusType::OUTPUTNOTALLOWED:
442                type = DrmPlugin::kKeyStatusType_OutputNotAllowed;
443                break;
444            case KeyStatusType::STATUSPENDING:
445                type = DrmPlugin::kKeyStatusType_StatusPending;
446                break;
447            case KeyStatusType::INTERNALERROR:
448            default:
449                type = DrmPlugin::kKeyStatusType_InternalError;
450                break;
451            }
452            obj.writeInt32(type);
453            mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
454        }
455        obj.writeInt32(hasNewUsableKey);
456
457        Mutex::Autolock lock(mNotifyLock);
458        listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
459    } else {
460        // There's no listener. But we still want to count the key change
461        // events.
462        size_t nKeys = keyStatusList.size();
463        for (size_t i = 0; i < nKeys; i++) {
464            mMetrics.mKeyStatusChangeCounter.Increment(keyStatusList[i].type);
465        }
466    }
467
468    return Void();
469}
470
471bool DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
472    Mutex::Autolock autoLock(mLock);
473
474    for (size_t i = 0; i < mFactories.size(); i++) {
475        if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
476            if (mimeType != "") {
477                if (mFactories[i]->isContentTypeSupported(mimeType.string())) {
478                    return true;
479                }
480            } else {
481                return true;
482            }
483        }
484    }
485    return false;
486}
487
488status_t DrmHal::createPlugin(const uint8_t uuid[16],
489        const String8& appPackageName) {
490    Mutex::Autolock autoLock(mLock);
491
492    for (size_t i = 0; i < mFactories.size(); i++) {
493        if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
494            mPlugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
495            if (mPlugin != NULL) {
496                mPluginV1_1 = drm::V1_1::IDrmPlugin::castFrom(mPlugin);
497            }
498        }
499    }
500
501    if (mPlugin == NULL) {
502        mInitCheck = ERROR_UNSUPPORTED;
503    } else {
504        if (!mPlugin->setListener(this).isOk()) {
505            mInitCheck = DEAD_OBJECT;
506        } else {
507            mInitCheck = OK;
508        }
509    }
510
511    return mInitCheck;
512}
513
514status_t DrmHal::destroyPlugin() {
515    Mutex::Autolock autoLock(mLock);
516    INIT_CHECK();
517
518    closeOpenSessions();
519    reportPluginMetrics();
520    reportFrameworkMetrics();
521    setListener(NULL);
522    mInitCheck = NO_INIT;
523
524    if (mPlugin != NULL) {
525        if (!mPlugin->setListener(NULL).isOk()) {
526            mInitCheck = DEAD_OBJECT;
527        }
528    }
529    mPlugin.clear();
530    mPluginV1_1.clear();
531    return OK;
532}
533
534status_t DrmHal::openSession(DrmPlugin::SecurityLevel level,
535        Vector<uint8_t> &sessionId) {
536    Mutex::Autolock autoLock(mLock);
537    INIT_CHECK();
538
539    SecurityLevel hSecurityLevel;
540    bool setSecurityLevel = true;
541
542    switch(level) {
543    case DrmPlugin::kSecurityLevelSwSecureCrypto:
544        hSecurityLevel = SecurityLevel::SW_SECURE_CRYPTO;
545        break;
546    case DrmPlugin::kSecurityLevelSwSecureDecode:
547        hSecurityLevel = SecurityLevel::SW_SECURE_DECODE;
548        break;
549    case DrmPlugin::kSecurityLevelHwSecureCrypto:
550        hSecurityLevel = SecurityLevel::HW_SECURE_CRYPTO;
551        break;
552    case DrmPlugin::kSecurityLevelHwSecureDecode:
553        hSecurityLevel = SecurityLevel::HW_SECURE_DECODE;
554        break;
555    case DrmPlugin::kSecurityLevelHwSecureAll:
556        hSecurityLevel = SecurityLevel::HW_SECURE_ALL;
557        break;
558    case DrmPlugin::kSecurityLevelMax:
559        setSecurityLevel = false;
560        break;
561    default:
562        return ERROR_DRM_CANNOT_HANDLE;
563    }
564
565    status_t  err = UNKNOWN_ERROR;
566    bool retry = true;
567    do {
568        hidl_vec<uint8_t> hSessionId;
569
570        Return<void> hResult;
571        if (mPluginV1_1 == NULL || !setSecurityLevel) {
572            hResult = mPlugin->openSession(
573                    [&](Status status,const hidl_vec<uint8_t>& id) {
574                        if (status == Status::OK) {
575                            sessionId = toVector(id);
576                        }
577                        err = toStatusT(status);
578                    }
579                );
580        } else {
581            hResult = mPluginV1_1->openSession_1_1(hSecurityLevel,
582                    [&](Status status, const hidl_vec<uint8_t>& id) {
583                        if (status == Status::OK) {
584                            sessionId = toVector(id);
585                        }
586                        err = toStatusT(status);
587                    }
588                );
589        }
590
591        if (!hResult.isOk()) {
592            err = DEAD_OBJECT;
593        }
594
595        if (err == ERROR_DRM_RESOURCE_BUSY && retry) {
596            mLock.unlock();
597            // reclaimSession may call back to closeSession, since mLock is
598            // shared between Drm instances, we should unlock here to avoid
599            // deadlock.
600            retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
601            mLock.lock();
602        } else {
603            retry = false;
604        }
605    } while (retry);
606
607    if (err == OK) {
608        DrmSessionManager::Instance()->addSession(getCallingPid(),
609                mDrmSessionClient, sessionId);
610        mOpenSessions.push(sessionId);
611        mMetrics.SetSessionStart(sessionId);
612    }
613
614    mMetrics.mOpenSessionCounter.Increment(err);
615    return err;
616}
617
618status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) {
619    Mutex::Autolock autoLock(mLock);
620    INIT_CHECK();
621
622    Return<Status> status = mPlugin->closeSession(toHidlVec(sessionId));
623    if (status.isOk()) {
624        if (status == Status::OK) {
625            DrmSessionManager::Instance()->removeSession(sessionId);
626            for (size_t i = 0; i < mOpenSessions.size(); i++) {
627                if (mOpenSessions[i] == sessionId) {
628                    mOpenSessions.removeAt(i);
629                    break;
630                }
631            }
632        }
633        status_t response = toStatusT(status);
634        mMetrics.SetSessionEnd(sessionId);
635        mMetrics.mCloseSessionCounter.Increment(response);
636        reportPluginMetrics();
637        return response;
638    }
639    mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT);
640    return DEAD_OBJECT;
641}
642
643status_t DrmHal::getKeyRequest(Vector<uint8_t> const &sessionId,
644        Vector<uint8_t> const &initData, String8 const &mimeType,
645        DrmPlugin::KeyType keyType, KeyedVector<String8,
646        String8> const &optionalParameters, Vector<uint8_t> &request,
647        String8 &defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) {
648    Mutex::Autolock autoLock(mLock);
649    INIT_CHECK();
650    EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
651
652    DrmSessionManager::Instance()->useSession(sessionId);
653
654    KeyType hKeyType;
655    if (keyType == DrmPlugin::kKeyType_Streaming) {
656        hKeyType = KeyType::STREAMING;
657    } else if (keyType == DrmPlugin::kKeyType_Offline) {
658        hKeyType = KeyType::OFFLINE;
659    } else if (keyType == DrmPlugin::kKeyType_Release) {
660        hKeyType = KeyType::RELEASE;
661    } else {
662        keyRequestTimer.SetAttribute(BAD_VALUE);
663        return BAD_VALUE;
664    }
665
666    ::KeyedVector hOptionalParameters = toHidlKeyedVector(optionalParameters);
667
668    status_t err = UNKNOWN_ERROR;
669
670    if (mPluginV1_1 != NULL) {
671        Return<void> hResult =
672            mPluginV1_1->getKeyRequest_1_1(
673                toHidlVec(sessionId), toHidlVec(initData),
674                toHidlString(mimeType), hKeyType, hOptionalParameters,
675                [&](Status status, const hidl_vec<uint8_t>& hRequest,
676                    drm::V1_1::KeyRequestType hKeyRequestType,
677                    const hidl_string& hDefaultUrl) {
678
679            if (status == Status::OK) {
680                request = toVector(hRequest);
681                defaultUrl = toString8(hDefaultUrl);
682
683                switch (hKeyRequestType) {
684                    case drm::V1_1::KeyRequestType::INITIAL:
685                        *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
686                        break;
687                    case drm::V1_1::KeyRequestType::RENEWAL:
688                        *keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
689                        break;
690                    case drm::V1_1::KeyRequestType::RELEASE:
691                        *keyRequestType = DrmPlugin::kKeyRequestType_Release;
692                        break;
693                    case drm::V1_1::KeyRequestType::NONE:
694                        *keyRequestType = DrmPlugin::kKeyRequestType_None;
695                        break;
696                    case drm::V1_1::KeyRequestType::UPDATE:
697                        *keyRequestType = DrmPlugin::kKeyRequestType_Update;
698                        break;
699                    default:
700                        *keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
701                        break;
702                }
703                err = toStatusT(status);
704            }
705        });
706        return hResult.isOk() ? err : DEAD_OBJECT;
707    }
708
709    Return<void> hResult = mPlugin->getKeyRequest(toHidlVec(sessionId),
710            toHidlVec(initData), toHidlString(mimeType), hKeyType, hOptionalParameters,
711            [&](Status status, const hidl_vec<uint8_t>& hRequest,
712                    drm::V1_0::KeyRequestType hKeyRequestType,
713                    const hidl_string& hDefaultUrl) {
714
715                if (status == Status::OK) {
716                    request = toVector(hRequest);
717                    defaultUrl = toString8(hDefaultUrl);
718
719                    switch (hKeyRequestType) {
720                    case drm::V1_0::KeyRequestType::INITIAL:
721                        *keyRequestType = DrmPlugin::kKeyRequestType_Initial;
722                        break;
723                    case drm::V1_0::KeyRequestType::RENEWAL:
724                        *keyRequestType = DrmPlugin::kKeyRequestType_Renewal;
725                        break;
726                    case drm::V1_0::KeyRequestType::RELEASE:
727                        *keyRequestType = DrmPlugin::kKeyRequestType_Release;
728                        break;
729                    default:
730                        *keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
731                        break;
732                    }
733                    err = toStatusT(status);
734                }
735            });
736
737    err = hResult.isOk() ? err : DEAD_OBJECT;
738    keyRequestTimer.SetAttribute(err);
739    return err;
740}
741
742status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
743        Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
744    Mutex::Autolock autoLock(mLock);
745    EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
746
747    INIT_CHECK();
748
749    DrmSessionManager::Instance()->useSession(sessionId);
750
751    status_t err = UNKNOWN_ERROR;
752
753    Return<void> hResult = mPlugin->provideKeyResponse(toHidlVec(sessionId),
754            toHidlVec(response),
755            [&](Status status, const hidl_vec<uint8_t>& hKeySetId) {
756                if (status == Status::OK) {
757                    keySetId = toVector(hKeySetId);
758                }
759                err = toStatusT(status);
760            }
761        );
762    err = hResult.isOk() ? err : DEAD_OBJECT;
763    keyResponseTimer.SetAttribute(err);
764    return err;
765}
766
767status_t DrmHal::removeKeys(Vector<uint8_t> const &keySetId) {
768    Mutex::Autolock autoLock(mLock);
769    INIT_CHECK();
770
771    return toStatusT(mPlugin->removeKeys(toHidlVec(keySetId)));
772}
773
774status_t DrmHal::restoreKeys(Vector<uint8_t> const &sessionId,
775        Vector<uint8_t> const &keySetId) {
776    Mutex::Autolock autoLock(mLock);
777    INIT_CHECK();
778
779    DrmSessionManager::Instance()->useSession(sessionId);
780
781    return toStatusT(mPlugin->restoreKeys(toHidlVec(sessionId),
782                    toHidlVec(keySetId)));
783}
784
785status_t DrmHal::queryKeyStatus(Vector<uint8_t> const &sessionId,
786        KeyedVector<String8, String8> &infoMap) const {
787    Mutex::Autolock autoLock(mLock);
788    INIT_CHECK();
789
790    DrmSessionManager::Instance()->useSession(sessionId);
791
792    ::KeyedVector hInfoMap;
793
794    status_t err = UNKNOWN_ERROR;
795
796    Return<void> hResult = mPlugin->queryKeyStatus(toHidlVec(sessionId),
797            [&](Status status, const hidl_vec<KeyValue>& map) {
798                if (status == Status::OK) {
799                    infoMap = toKeyedVector(map);
800                }
801                err = toStatusT(status);
802            }
803        );
804
805    return hResult.isOk() ? err : DEAD_OBJECT;
806}
807
808status_t DrmHal::getProvisionRequest(String8 const &certType,
809        String8 const &certAuthority, Vector<uint8_t> &request,
810        String8 &defaultUrl) {
811    Mutex::Autolock autoLock(mLock);
812    INIT_CHECK();
813
814    status_t err = UNKNOWN_ERROR;
815
816    Return<void> hResult = mPlugin->getProvisionRequest(
817            toHidlString(certType), toHidlString(certAuthority),
818            [&](Status status, const hidl_vec<uint8_t>& hRequest,
819                    const hidl_string& hDefaultUrl) {
820                if (status == Status::OK) {
821                    request = toVector(hRequest);
822                    defaultUrl = toString8(hDefaultUrl);
823                }
824                err = toStatusT(status);
825            }
826        );
827
828    err = hResult.isOk() ? err : DEAD_OBJECT;
829    mMetrics.mGetProvisionRequestCounter.Increment(err);
830    return err;
831}
832
833status_t DrmHal::provideProvisionResponse(Vector<uint8_t> const &response,
834        Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey) {
835    Mutex::Autolock autoLock(mLock);
836    INIT_CHECK();
837
838    status_t err = UNKNOWN_ERROR;
839
840    Return<void> hResult = mPlugin->provideProvisionResponse(toHidlVec(response),
841            [&](Status status, const hidl_vec<uint8_t>& hCertificate,
842                    const hidl_vec<uint8_t>& hWrappedKey) {
843                if (status == Status::OK) {
844                    certificate = toVector(hCertificate);
845                    wrappedKey = toVector(hWrappedKey);
846                }
847                err = toStatusT(status);
848            }
849        );
850
851    err = hResult.isOk() ? err : DEAD_OBJECT;
852    mMetrics.mProvideProvisionResponseCounter.Increment(err);
853    return err;
854}
855
856status_t DrmHal::getSecureStops(List<Vector<uint8_t>> &secureStops) {
857    Mutex::Autolock autoLock(mLock);
858    INIT_CHECK();
859
860    status_t err = UNKNOWN_ERROR;
861
862    Return<void> hResult = mPlugin->getSecureStops(
863            [&](Status status, const hidl_vec<SecureStop>& hSecureStops) {
864                if (status == Status::OK) {
865                    secureStops = toSecureStops(hSecureStops);
866                }
867                err = toStatusT(status);
868            }
869    );
870
871    return hResult.isOk() ? err : DEAD_OBJECT;
872}
873
874
875status_t DrmHal::getSecureStopIds(List<Vector<uint8_t>> &secureStopIds) {
876    Mutex::Autolock autoLock(mLock);
877
878    if (mInitCheck != OK) {
879        return mInitCheck;
880    }
881
882    if (mPluginV1_1 == NULL) {
883        return ERROR_DRM_CANNOT_HANDLE;
884    }
885
886    status_t err = UNKNOWN_ERROR;
887
888    Return<void> hResult = mPluginV1_1->getSecureStopIds(
889            [&](Status status, const hidl_vec<SecureStopId>& hSecureStopIds) {
890                if (status == Status::OK) {
891                    secureStopIds = toSecureStopIds(hSecureStopIds);
892                }
893                err = toStatusT(status);
894            }
895    );
896
897    return hResult.isOk() ? err : DEAD_OBJECT;
898}
899
900
901status_t DrmHal::getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
902    Mutex::Autolock autoLock(mLock);
903    INIT_CHECK();
904
905    status_t err = UNKNOWN_ERROR;
906
907    Return<void> hResult = mPlugin->getSecureStop(toHidlVec(ssid),
908            [&](Status status, const SecureStop& hSecureStop) {
909                if (status == Status::OK) {
910                    secureStop = toVector(hSecureStop.opaqueData);
911                }
912                err = toStatusT(status);
913            }
914    );
915
916    return hResult.isOk() ? err : DEAD_OBJECT;
917}
918
919status_t DrmHal::releaseSecureStops(Vector<uint8_t> const &ssRelease) {
920    Mutex::Autolock autoLock(mLock);
921    INIT_CHECK();
922
923    if (mPluginV1_1 != NULL) {
924        SecureStopRelease secureStopRelease;
925        secureStopRelease.opaqueData = toHidlVec(ssRelease);
926        return toStatusT(mPluginV1_1->releaseSecureStops(secureStopRelease));
927    }
928
929    return toStatusT(mPlugin->releaseSecureStop(toHidlVec(ssRelease)));
930}
931
932status_t DrmHal::removeSecureStop(Vector<uint8_t> const &ssid) {
933    Mutex::Autolock autoLock(mLock);
934
935    if (mInitCheck != OK) {
936        return mInitCheck;
937    }
938
939    if (mPluginV1_1 == NULL) {
940        return ERROR_DRM_CANNOT_HANDLE;
941    }
942
943    return toStatusT(mPluginV1_1->removeSecureStop(toHidlVec(ssid)));
944}
945
946status_t DrmHal::removeAllSecureStops() {
947    Mutex::Autolock autoLock(mLock);
948    INIT_CHECK();
949
950    if (mPluginV1_1 != NULL) {
951        return toStatusT(mPluginV1_1->removeAllSecureStops());
952    }
953    return toStatusT(mPlugin->releaseAllSecureStops());
954}
955
956status_t DrmHal::getHdcpLevels(DrmPlugin::HdcpLevel *connected,
957            DrmPlugin::HdcpLevel *max) const {
958    Mutex::Autolock autoLock(mLock);
959    INIT_CHECK();
960
961    if (connected == NULL || max == NULL) {
962        return BAD_VALUE;
963    }
964    status_t err = UNKNOWN_ERROR;
965
966    if (mPluginV1_1 == NULL) {
967        return ERROR_DRM_CANNOT_HANDLE;
968    }
969
970    *connected = DrmPlugin::kHdcpLevelUnknown;
971    *max = DrmPlugin::kHdcpLevelUnknown;
972
973    Return<void> hResult = mPluginV1_1->getHdcpLevels(
974            [&](Status status, const HdcpLevel& hConnected, const HdcpLevel& hMax) {
975                if (status == Status::OK) {
976                    *connected = toHdcpLevel(hConnected);
977                    *max = toHdcpLevel(hMax);
978                }
979                err = toStatusT(status);
980            }
981    );
982
983    return hResult.isOk() ? err : DEAD_OBJECT;
984}
985
986status_t DrmHal::getNumberOfSessions(uint32_t *open, uint32_t *max) const {
987    Mutex::Autolock autoLock(mLock);
988    INIT_CHECK();
989
990    if (open == NULL || max == NULL) {
991        return BAD_VALUE;
992    }
993    status_t err = UNKNOWN_ERROR;
994
995    *open = 0;
996    *max = 0;
997
998    if (mPluginV1_1 == NULL) {
999        return ERROR_DRM_CANNOT_HANDLE;
1000    }
1001
1002    Return<void> hResult = mPluginV1_1->getNumberOfSessions(
1003            [&](Status status, uint32_t hOpen, uint32_t hMax) {
1004                if (status == Status::OK) {
1005                    *open = hOpen;
1006                    *max = hMax;
1007                }
1008                err = toStatusT(status);
1009            }
1010    );
1011
1012    return hResult.isOk() ? err : DEAD_OBJECT;
1013}
1014
1015status_t DrmHal::getSecurityLevel(Vector<uint8_t> const &sessionId,
1016        DrmPlugin::SecurityLevel *level) const {
1017    Mutex::Autolock autoLock(mLock);
1018    INIT_CHECK();
1019
1020    if (level == NULL) {
1021        return BAD_VALUE;
1022    }
1023    status_t err = UNKNOWN_ERROR;
1024
1025    if (mPluginV1_1 == NULL) {
1026        return ERROR_DRM_CANNOT_HANDLE;
1027    }
1028
1029    *level = DrmPlugin::kSecurityLevelUnknown;
1030
1031    Return<void> hResult = mPluginV1_1->getSecurityLevel(toHidlVec(sessionId),
1032            [&](Status status, SecurityLevel hLevel) {
1033                if (status == Status::OK) {
1034                    *level = toSecurityLevel(hLevel);
1035                }
1036                err = toStatusT(status);
1037            }
1038    );
1039
1040    return hResult.isOk() ? err : DEAD_OBJECT;
1041}
1042
1043status_t DrmHal::getPropertyString(String8 const &name, String8 &value ) const {
1044    Mutex::Autolock autoLock(mLock);
1045    return getPropertyStringInternal(name, value);
1046}
1047
1048status_t DrmHal::getPropertyStringInternal(String8 const &name, String8 &value) const {
1049    // This function is internal to the class and should only be called while
1050    // mLock is already held.
1051    INIT_CHECK();
1052
1053    status_t err = UNKNOWN_ERROR;
1054
1055    Return<void> hResult = mPlugin->getPropertyString(toHidlString(name),
1056            [&](Status status, const hidl_string& hValue) {
1057                if (status == Status::OK) {
1058                    value = toString8(hValue);
1059                }
1060                err = toStatusT(status);
1061            }
1062    );
1063
1064    return hResult.isOk() ? err : DEAD_OBJECT;
1065}
1066
1067status_t DrmHal::getPropertyByteArray(String8 const &name, Vector<uint8_t> &value ) const {
1068    Mutex::Autolock autoLock(mLock);
1069    return getPropertyByteArrayInternal(name, value);
1070}
1071
1072status_t DrmHal::getPropertyByteArrayInternal(String8 const &name, Vector<uint8_t> &value ) const {
1073    // This function is internal to the class and should only be called while
1074    // mLock is already held.
1075    INIT_CHECK();
1076
1077    status_t err = UNKNOWN_ERROR;
1078
1079    Return<void> hResult = mPlugin->getPropertyByteArray(toHidlString(name),
1080            [&](Status status, const hidl_vec<uint8_t>& hValue) {
1081                if (status == Status::OK) {
1082                    value = toVector(hValue);
1083                }
1084                err = toStatusT(status);
1085            }
1086    );
1087
1088    err = hResult.isOk() ? err : DEAD_OBJECT;
1089    if (name == kPropertyDeviceUniqueId) {
1090        mMetrics.mGetDeviceUniqueIdCounter.Increment(err);
1091    }
1092    return err;
1093}
1094
1095status_t DrmHal::setPropertyString(String8 const &name, String8 const &value ) const {
1096    Mutex::Autolock autoLock(mLock);
1097    INIT_CHECK();
1098
1099    Status status = mPlugin->setPropertyString(toHidlString(name),
1100            toHidlString(value));
1101    return toStatusT(status);
1102}
1103
1104status_t DrmHal::setPropertyByteArray(String8 const &name,
1105                                   Vector<uint8_t> const &value ) const {
1106    Mutex::Autolock autoLock(mLock);
1107    INIT_CHECK();
1108
1109    Status status = mPlugin->setPropertyByteArray(toHidlString(name),
1110            toHidlVec(value));
1111    return toStatusT(status);
1112}
1113
1114status_t DrmHal::getMetrics(PersistableBundle* item) {
1115    if (item == nullptr) {
1116      return UNEXPECTED_NULL;
1117    }
1118
1119    mMetrics.Export(item);
1120    return OK;
1121}
1122
1123status_t DrmHal::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
1124                                 String8 const &algorithm) {
1125    Mutex::Autolock autoLock(mLock);
1126    INIT_CHECK();
1127
1128    DrmSessionManager::Instance()->useSession(sessionId);
1129
1130    Status status = mPlugin->setCipherAlgorithm(toHidlVec(sessionId),
1131            toHidlString(algorithm));
1132    return toStatusT(status);
1133}
1134
1135status_t DrmHal::setMacAlgorithm(Vector<uint8_t> const &sessionId,
1136                              String8 const &algorithm) {
1137    Mutex::Autolock autoLock(mLock);
1138    INIT_CHECK();
1139
1140    DrmSessionManager::Instance()->useSession(sessionId);
1141
1142    Status status = mPlugin->setMacAlgorithm(toHidlVec(sessionId),
1143            toHidlString(algorithm));
1144    return toStatusT(status);
1145}
1146
1147status_t DrmHal::encrypt(Vector<uint8_t> const &sessionId,
1148        Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
1149        Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
1150    Mutex::Autolock autoLock(mLock);
1151    INIT_CHECK();
1152
1153    DrmSessionManager::Instance()->useSession(sessionId);
1154
1155    status_t err = UNKNOWN_ERROR;
1156
1157    Return<void> hResult = mPlugin->encrypt(toHidlVec(sessionId),
1158            toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
1159            [&](Status status, const hidl_vec<uint8_t>& hOutput) {
1160                if (status == Status::OK) {
1161                    output = toVector(hOutput);
1162                }
1163                err = toStatusT(status);
1164            }
1165    );
1166
1167    return hResult.isOk() ? err : DEAD_OBJECT;
1168}
1169
1170status_t DrmHal::decrypt(Vector<uint8_t> const &sessionId,
1171        Vector<uint8_t> const &keyId, Vector<uint8_t> const &input,
1172        Vector<uint8_t> const &iv, Vector<uint8_t> &output) {
1173    Mutex::Autolock autoLock(mLock);
1174    INIT_CHECK();
1175
1176    DrmSessionManager::Instance()->useSession(sessionId);
1177
1178    status_t  err = UNKNOWN_ERROR;
1179
1180    Return<void> hResult = mPlugin->decrypt(toHidlVec(sessionId),
1181            toHidlVec(keyId), toHidlVec(input), toHidlVec(iv),
1182            [&](Status status, const hidl_vec<uint8_t>& hOutput) {
1183                if (status == Status::OK) {
1184                    output = toVector(hOutput);
1185                }
1186                err = toStatusT(status);
1187            }
1188    );
1189
1190    return hResult.isOk() ? err : DEAD_OBJECT;
1191}
1192
1193status_t DrmHal::sign(Vector<uint8_t> const &sessionId,
1194        Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
1195        Vector<uint8_t> &signature) {
1196    Mutex::Autolock autoLock(mLock);
1197    INIT_CHECK();
1198
1199    DrmSessionManager::Instance()->useSession(sessionId);
1200
1201    status_t err = UNKNOWN_ERROR;
1202
1203    Return<void> hResult = mPlugin->sign(toHidlVec(sessionId),
1204            toHidlVec(keyId), toHidlVec(message),
1205            [&](Status status, const hidl_vec<uint8_t>& hSignature)  {
1206                if (status == Status::OK) {
1207                    signature = toVector(hSignature);
1208                }
1209                err = toStatusT(status);
1210            }
1211    );
1212
1213    return hResult.isOk() ? err : DEAD_OBJECT;
1214}
1215
1216status_t DrmHal::verify(Vector<uint8_t> const &sessionId,
1217        Vector<uint8_t> const &keyId, Vector<uint8_t> const &message,
1218        Vector<uint8_t> const &signature, bool &match) {
1219    Mutex::Autolock autoLock(mLock);
1220    INIT_CHECK();
1221
1222    DrmSessionManager::Instance()->useSession(sessionId);
1223
1224    status_t err = UNKNOWN_ERROR;
1225
1226    Return<void> hResult = mPlugin->verify(toHidlVec(sessionId),toHidlVec(keyId),
1227            toHidlVec(message), toHidlVec(signature),
1228            [&](Status status, bool hMatch) {
1229                if (status == Status::OK) {
1230                    match = hMatch;
1231                } else {
1232                    match = false;
1233                }
1234                err = toStatusT(status);
1235            }
1236    );
1237
1238    return hResult.isOk() ? err : DEAD_OBJECT;
1239}
1240
1241status_t DrmHal::signRSA(Vector<uint8_t> const &sessionId,
1242        String8 const &algorithm, Vector<uint8_t> const &message,
1243        Vector<uint8_t> const &wrappedKey, Vector<uint8_t> &signature) {
1244    Mutex::Autolock autoLock(mLock);
1245    INIT_CHECK();
1246
1247    if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
1248        return -EPERM;
1249    }
1250
1251    DrmSessionManager::Instance()->useSession(sessionId);
1252
1253    status_t err = UNKNOWN_ERROR;
1254
1255    Return<void> hResult = mPlugin->signRSA(toHidlVec(sessionId),
1256            toHidlString(algorithm), toHidlVec(message), toHidlVec(wrappedKey),
1257            [&](Status status, const hidl_vec<uint8_t>& hSignature) {
1258                if (status == Status::OK) {
1259                    signature = toVector(hSignature);
1260                }
1261                err = toStatusT(status);
1262            }
1263        );
1264
1265    return hResult.isOk() ? err : DEAD_OBJECT;
1266}
1267
1268void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
1269{
1270    Mutex::Autolock autoLock(mLock);
1271    closeOpenSessions();
1272    setListener(NULL);
1273    mInitCheck = NO_INIT;
1274
1275    if (mPlugin != NULL) {
1276        if (!mPlugin->setListener(NULL).isOk()) {
1277            mInitCheck = DEAD_OBJECT;
1278        }
1279    }
1280    mPlugin.clear();
1281}
1282
1283void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
1284{
1285    if (vec.size()) {
1286        obj.writeInt32(vec.size());
1287        obj.write(vec.data(), vec.size());
1288    } else {
1289        obj.writeInt32(0);
1290    }
1291}
1292
1293void DrmHal::reportFrameworkMetrics() const
1294{
1295    MediaAnalyticsItem item("mediadrm");
1296    item.generateSessionID();
1297    item.setPkgName(mMetrics.GetAppPackageName().c_str());
1298    String8 vendor;
1299    String8 description;
1300    status_t result = getPropertyStringInternal(String8("vendor"), vendor);
1301    if (result != OK) {
1302        ALOGE("Failed to get vendor from drm plugin. %d", result);
1303    } else {
1304        item.setCString("vendor", vendor.c_str());
1305    }
1306    result = getPropertyStringInternal(String8("description"), description);
1307    if (result != OK) {
1308        ALOGE("Failed to get description from drm plugin. %d", result);
1309    } else {
1310        item.setCString("description", description.c_str());
1311    }
1312
1313    std::string serializedMetrics;
1314    result = mMetrics.GetSerializedMetrics(&serializedMetrics);
1315    if (result != OK) {
1316        ALOGE("Failed to serialize Framework metrics: %d", result);
1317    }
1318    serializedMetrics = ToHexString(serializedMetrics);
1319    if (!serializedMetrics.empty()) {
1320        item.setCString("serialized_metrics", serializedMetrics.c_str());
1321    }
1322    if (!item.selfrecord()) {
1323        ALOGE("Failed to self record framework metrics.");
1324    }
1325}
1326
1327void DrmHal::reportPluginMetrics() const
1328{
1329    Vector<uint8_t> metrics;
1330    String8 vendor;
1331    String8 description;
1332    if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
1333            getPropertyStringInternal(String8("description"), description) == OK &&
1334            getPropertyByteArrayInternal(String8("metrics"), metrics) == OK) {
1335        status_t res = android::reportDrmPluginMetrics(
1336                metrics, vendor, description);
1337        if (res != OK) {
1338            ALOGE("Metrics were retrieved but could not be reported: %i", res);
1339        }
1340    }
1341}
1342
1343}  // namespace android
1344