Source release 15.3.0

This commit is contained in:
John W. Bruce
2020-02-11 14:22:17 -08:00
parent 2990f23065
commit 1ff9f8588a
29 changed files with 534 additions and 153 deletions

View File

@@ -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