DrmHal.cpp revision 987ac7056040ed1594dc975c8a9d7cee463fa834
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> ®istered) { 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> ®istered) { 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: %d", res); 1339 } 1340 } 1341} 1342 1343} // namespace android 1344