Source release 15.3.0
This commit is contained in:
103
cdm/src/cdm.cpp
103
cdm/src/cdm.cpp
@@ -38,6 +38,7 @@ using namespace wvcdm;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kNoSandboxId = "";
|
||||
const int64_t kPolicyTimerDurationMilliseconds = 5000;
|
||||
void* const kPolicyTimerContext = nullptr;
|
||||
|
||||
@@ -108,9 +109,59 @@ class PropertySet : public CdmClientPropertySet {
|
||||
const std::string empty_string_;
|
||||
};
|
||||
|
||||
// A wrapper for another IStorage instance that intercepts attempts to write to
|
||||
// that storage and blocks them. Acts as a last-ditch safeguard against the CDM
|
||||
// trying to write erroneously to filesystems where it is critical that we never
|
||||
// overwrite or delete the files. Specifically, preloaded files on ATSC 3.
|
||||
//
|
||||
// TODO(b/148693106): Right now, this wrapper fails writes silently because
|
||||
// there are known bugs where the CDM will still try to write to it. Once these
|
||||
// bugs are resolved, we can change this wrapper to return errors on write
|
||||
// attempts. The wrapper itself will still be necessary, in order to prevent any
|
||||
// future bugs from corrupting ATSC files.
|
||||
class ReadOnlyStorage : public Cdm::IStorage {
|
||||
public:
|
||||
explicit ReadOnlyStorage(Cdm::IStorage* storage) : storage_(storage) {}
|
||||
~ReadOnlyStorage() override {}
|
||||
|
||||
bool read(const std::string& name, std::string* data) override {
|
||||
return storage_->read(name, data);
|
||||
}
|
||||
|
||||
bool write(const std::string& name, const std::string& data) override {
|
||||
// TODO(b/148693106): Once we have resolved the bugs causing the CDM to
|
||||
// erroneously write to read-only files, change this to an error instead of
|
||||
// a silent failure.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exists(const std::string& name) override {
|
||||
return storage_->exists(name);
|
||||
}
|
||||
|
||||
bool remove(const std::string& name) override {
|
||||
// TODO(b/148693106): Once we have resolved the bugs causing the CDM to
|
||||
// erroneously write to read-only files, change this to an error instead of
|
||||
// a silent failure.
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t size(const std::string& name) override {
|
||||
return storage_->size(name);
|
||||
}
|
||||
|
||||
bool list(std::vector<std::string>* file_names) override {
|
||||
return storage_->list(file_names);
|
||||
}
|
||||
|
||||
private:
|
||||
Cdm::IStorage* storage_; // Lifetime is managed by the caller
|
||||
};
|
||||
|
||||
class CdmImpl : public Cdm, public WvCdmEventListener {
|
||||
public:
|
||||
CdmImpl(IEventListener* listener, IStorage* storage, bool privacy_mode);
|
||||
CdmImpl(IEventListener* listener, IStorage* storage, bool privacy_mode,
|
||||
const ReadOnlyStorage* owned_storage_object);
|
||||
|
||||
~CdmImpl() override;
|
||||
|
||||
@@ -262,14 +313,23 @@ class CdmImpl : public Cdm, public WvCdmEventListener {
|
||||
};
|
||||
|
||||
std::map<std::string, SessionMetadata> sessions_;
|
||||
|
||||
// This field will be nullptr unless the create() function had to allocate
|
||||
// memory for a read-only storage wrapper that needs to be cleaned up when
|
||||
// this CDM instance is deleted. The storage should always be accessed via
|
||||
// file_system_ and not via this parameter directly. However, it must be
|
||||
// stored so it can be cleaned up later.
|
||||
const std::unique_ptr<const ReadOnlyStorage> owned_storage_object_;
|
||||
};
|
||||
|
||||
CdmImpl::CdmImpl(IEventListener* listener, IStorage* storage, bool privacy_mode)
|
||||
CdmImpl::CdmImpl(IEventListener* listener, IStorage* storage, bool privacy_mode,
|
||||
const ReadOnlyStorage* owned_storage_object)
|
||||
: listener_(listener),
|
||||
policy_timer_enabled_(false),
|
||||
provisioning_service_certificate_(),
|
||||
file_system_("", storage),
|
||||
cdm_engine_(CdmEngineFactory::CreateCdmEngine(&file_system_)) {
|
||||
cdm_engine_(CdmEngineFactory::CreateCdmEngine(&file_system_)),
|
||||
owned_storage_object_(owned_storage_object) {
|
||||
assert(nullptr != listener_);
|
||||
property_set_.set_use_privacy_mode(privacy_mode);
|
||||
}
|
||||
@@ -292,6 +352,12 @@ Cdm::Status CdmImpl::setServiceCertificate(ServiceRole role,
|
||||
|
||||
if (role == kLicensingService || role == kAllServices) {
|
||||
property_set_.set_service_certificate(certificate);
|
||||
|
||||
// Update all open sessions with the new certificate.
|
||||
for (const auto& session_pair : sessions_) {
|
||||
cdm_engine_->SetSessionServiceCertificate(session_pair.first,
|
||||
certificate);
|
||||
}
|
||||
}
|
||||
|
||||
if (role == kProvisioningService || role == kAllServices) {
|
||||
@@ -680,6 +746,10 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
||||
} else if (result == NEED_PROVISIONING) {
|
||||
LOGE("Device not provisioned");
|
||||
return kNeedsDeviceCertificate;
|
||||
} else if (result == PRIVACY_MODE_ERROR_1 || result == PRIVACY_MODE_ERROR_2 ||
|
||||
result == PRIVACY_MODE_ERROR_3) {
|
||||
LOGE("No licensing service certificate installed");
|
||||
return kNeedsServiceCertificate;
|
||||
} else if (result != KEY_MESSAGE) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
return kUnexpectedError;
|
||||
@@ -1501,6 +1571,8 @@ Cdm::Status CdmImpl::ConvertHdcpLevel(const std::string& query_value,
|
||||
*result = kHdcp2_1;
|
||||
} else if (query_value == QUERY_VALUE_HDCP_V2_2) {
|
||||
*result = kHdcp2_2;
|
||||
} else if (query_value == QUERY_VALUE_HDCP_V2_3) {
|
||||
*result = kHdcp2_3;
|
||||
} else {
|
||||
return kUnexpectedError;
|
||||
}
|
||||
@@ -1513,6 +1585,15 @@ Cdm::Status CdmImpl::ConvertHdcpLevel(const std::string& query_value,
|
||||
Cdm::Status Cdm::initialize(SecureOutputType secure_output_type,
|
||||
const ClientInfo& client_info, IStorage* storage,
|
||||
IClock* clock, ITimer* timer, LogLevel verbosity) {
|
||||
return initialize(secure_output_type, client_info, storage, clock, timer,
|
||||
verbosity, kNoSandboxId);
|
||||
}
|
||||
|
||||
// static
|
||||
Cdm::Status Cdm::initialize(SecureOutputType secure_output_type,
|
||||
const ClientInfo& client_info, IStorage* storage,
|
||||
IClock* clock, ITimer* timer, LogLevel verbosity,
|
||||
const std::string& sandbox_id) {
|
||||
// Specify the maximum severity of message that will be output to
|
||||
// the console. See core/include/log.h for the valid priority values.
|
||||
g_cutoff = static_cast<LogPriority>(verbosity);
|
||||
@@ -1540,6 +1621,7 @@ Cdm::Status Cdm::initialize(SecureOutputType secure_output_type,
|
||||
|
||||
PropertiesCE::SetSecureOutputType(secure_output_type);
|
||||
PropertiesCE::SetClientInfo(client_info);
|
||||
if (sandbox_id != kNoSandboxId) PropertiesCE::SetSandboxId(sandbox_id);
|
||||
Properties::Init();
|
||||
host.storage = storage;
|
||||
host.clock = clock;
|
||||
@@ -1554,6 +1636,13 @@ const char* Cdm::version() { return CDM_VERSION; }
|
||||
// static
|
||||
Cdm* Cdm::create(IEventListener* listener, IStorage* storage,
|
||||
bool privacy_mode) {
|
||||
return create(listener, storage, privacy_mode,
|
||||
false /* storage_is_read_only */);
|
||||
}
|
||||
|
||||
// static
|
||||
Cdm* Cdm::create(IEventListener* listener, IStorage* storage, bool privacy_mode,
|
||||
bool storage_is_read_only) {
|
||||
if (!host.initialized) {
|
||||
LOGE("Not initialized!");
|
||||
return nullptr;
|
||||
@@ -1567,7 +1656,13 @@ Cdm* Cdm::create(IEventListener* listener, IStorage* storage,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new CdmImpl(listener, storage, privacy_mode);
|
||||
if (storage_is_read_only) {
|
||||
ReadOnlyStorage* read_only_storage = new ReadOnlyStorage(storage);
|
||||
return new CdmImpl(listener, read_only_storage, privacy_mode,
|
||||
read_only_storage);
|
||||
} else {
|
||||
return new CdmImpl(listener, storage, privacy_mode, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
Reference in New Issue
Block a user