Recover when stored information is corrupted am: a20034e3a2
am: 0dc79e547f
Change-Id: I68795d284dfcde4ccd8484bdccf3ddf3a9ee0882
This commit is contained in:
@@ -1203,6 +1203,9 @@ bool DeviceFiles::RetrieveHashedFile(
|
|||||||
|
|
||||||
if (bytes != static_cast<ssize_t>(serialized_hash_file.size())) {
|
if (bytes != static_cast<ssize_t>(serialized_hash_file.size())) {
|
||||||
LOGW("DeviceFiles::RetrieveHashedFile: read failed");
|
LOGW("DeviceFiles::RetrieveHashedFile: read failed");
|
||||||
|
// Remove the corrupted file so the caller will not get the same error
|
||||||
|
// when trying to access the file repeatedly, causing the system to stall.
|
||||||
|
file_system_->Remove(path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1212,6 +1215,9 @@ bool DeviceFiles::RetrieveHashedFile(
|
|||||||
HashedFile hash_file;
|
HashedFile hash_file;
|
||||||
if (!hash_file.ParseFromString(serialized_hash_file)) {
|
if (!hash_file.ParseFromString(serialized_hash_file)) {
|
||||||
LOGW("DeviceFiles::RetrieveHashedFile: Unable to parse hash file");
|
LOGW("DeviceFiles::RetrieveHashedFile: Unable to parse hash file");
|
||||||
|
// Remove the corrupted file so the caller will not get the same error
|
||||||
|
// when trying to access the file repeatedly, causing the system to stall.
|
||||||
|
file_system_->Remove(path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1231,6 +1237,9 @@ bool DeviceFiles::RetrieveHashedFile(
|
|||||||
|
|
||||||
if (!deserialized_file->ParseFromString(hash_file.file())) {
|
if (!deserialized_file->ParseFromString(hash_file.file())) {
|
||||||
LOGW("DeviceFiles::RetrieveHashedFile: Unable to parse file");
|
LOGW("DeviceFiles::RetrieveHashedFile: Unable to parse file");
|
||||||
|
// Remove the corrupted file so the caller will not get the same error
|
||||||
|
// when trying to access the file repeatedly, causing the system to stall.
|
||||||
|
file_system_->Remove(path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "cdm_identifier.h"
|
#include "cdm_identifier.h"
|
||||||
#include "config_test_env.h"
|
#include "config_test_env.h"
|
||||||
#include "device_files.h"
|
#include "device_files.h"
|
||||||
|
#include "device_files.pb.h"
|
||||||
#include "file_store.h"
|
#include "file_store.h"
|
||||||
#include "file_utils.h"
|
#include "file_utils.h"
|
||||||
#include "license_protocol.pb.h"
|
#include "license_protocol.pb.h"
|
||||||
@@ -3419,6 +3420,170 @@ TEST_F(WvCdmRequestLicenseTest, RemoveCorruptedUsageInfoTest) {
|
|||||||
EXPECT_TRUE(usage_info.empty());
|
EXPECT_TRUE(usage_info.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WvCdmRequestLicenseTest, RemoveCorruptedUsageInfoTest2) {
|
||||||
|
Unprovision();
|
||||||
|
|
||||||
|
std::string app_id_empty = "";
|
||||||
|
std::string app_id_not_empty = "not empty";
|
||||||
|
|
||||||
|
TestWvCdmClientPropertySet property_set;
|
||||||
|
Provision(kLevelDefault);
|
||||||
|
|
||||||
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
||||||
|
FileSystem file_system;
|
||||||
|
DeviceFiles handle(&file_system);
|
||||||
|
EXPECT_TRUE(handle.Init(security_level));
|
||||||
|
std::vector<std::string> psts;
|
||||||
|
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
|
||||||
|
DeviceFiles::GetUsageInfoFileName(""), &psts));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < N_ELEM(usage_info_sub_samples_icp); ++i) {
|
||||||
|
SubSampleInfo* data = usage_info_sub_samples_icp + i;
|
||||||
|
property_set.set_app_id(i % 2 == 0 ? app_id_empty : app_id_not_empty);
|
||||||
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
||||||
|
NULL, &session_id_);
|
||||||
|
std::string key_id = a2bs_hex(
|
||||||
|
"000000427073736800000000" // blob size and pssh
|
||||||
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
||||||
|
"08011a0d7769646576696e655f74657374220f73" // pssh data
|
||||||
|
"747265616d696e675f636c6970");
|
||||||
|
|
||||||
|
char ch = 0x33 + i;
|
||||||
|
key_id.append(1, ch);
|
||||||
|
|
||||||
|
GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set);
|
||||||
|
|
||||||
|
// TODO(rfrias): streaming_clip6 is a streaming license without a pst
|
||||||
|
if (ch == '6')
|
||||||
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
|
||||||
|
else
|
||||||
|
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
|
||||||
|
|
||||||
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
||||||
|
CdmDecryptionParameters decryption_parameters(
|
||||||
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
||||||
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
||||||
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
||||||
|
decryption_parameters.is_secure = data->is_secure;
|
||||||
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
||||||
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
||||||
|
decryption_parameters));
|
||||||
|
|
||||||
|
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
||||||
|
decrypt_buffer.begin()));
|
||||||
|
decryptor_.CloseSession(session_id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmUsageInfo usage_info;
|
||||||
|
EXPECT_EQ(
|
||||||
|
KEY_MESSAGE,
|
||||||
|
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
|
||||||
|
&usage_info));
|
||||||
|
EXPECT_TRUE(usage_info.size() > 0);
|
||||||
|
EXPECT_EQ(
|
||||||
|
KEY_MESSAGE,
|
||||||
|
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
|
||||||
|
&usage_info));
|
||||||
|
EXPECT_TRUE(usage_info.size() > 0);
|
||||||
|
|
||||||
|
// Read in usage info file
|
||||||
|
std::string path;
|
||||||
|
EXPECT_TRUE(Properties::GetDeviceFilesBasePath(security_level, &path));
|
||||||
|
std::string usage_info_not_empty_app_id_file_name =
|
||||||
|
path + DeviceFiles::GetUsageInfoFileName(app_id_not_empty);
|
||||||
|
|
||||||
|
ssize_t file_size =
|
||||||
|
file_system.FileSize(usage_info_not_empty_app_id_file_name);
|
||||||
|
EXPECT_LT(4, file_size);
|
||||||
|
File* file =
|
||||||
|
file_system.Open(usage_info_not_empty_app_id_file_name,
|
||||||
|
FileSystem::kReadOnly);
|
||||||
|
EXPECT_TRUE(NULL != file);
|
||||||
|
std::string file_data;
|
||||||
|
file_data.resize(file_size);
|
||||||
|
ssize_t bytes = file->Read(&file_data[0], file_data.size());
|
||||||
|
EXPECT_EQ(file_size, bytes);
|
||||||
|
file->Close();
|
||||||
|
|
||||||
|
video_widevine_client::sdk::HashedFile hash_file;
|
||||||
|
|
||||||
|
EXPECT_TRUE(hash_file.ParseFromString(file_data));
|
||||||
|
size_t pos = file_data.find(hash_file.hash());
|
||||||
|
EXPECT_NE(std::string::npos, pos);
|
||||||
|
EXPECT_NE(0u, pos);
|
||||||
|
|
||||||
|
// Corrupt the protobuf key field of the hash of the usage info file
|
||||||
|
// with non-empty app id and write it back out
|
||||||
|
file_data[pos-1] = 0xff;
|
||||||
|
|
||||||
|
file = file_system.Open(usage_info_not_empty_app_id_file_name,
|
||||||
|
FileSystem::kCreate | FileSystem::kTruncate);
|
||||||
|
EXPECT_TRUE(NULL != file);
|
||||||
|
bytes = file->Write(file_data.data(), file_data.size());
|
||||||
|
EXPECT_EQ(file_size, bytes);
|
||||||
|
file->Close();
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
NO_ERROR,
|
||||||
|
decryptor_.RemoveAllUsageInfo(app_id_not_empty, kDefaultCdmIdentifier));
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
NO_ERROR,
|
||||||
|
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
|
||||||
|
&usage_info));
|
||||||
|
EXPECT_TRUE(usage_info.empty());
|
||||||
|
EXPECT_EQ(
|
||||||
|
KEY_MESSAGE,
|
||||||
|
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
|
||||||
|
&usage_info));
|
||||||
|
EXPECT_TRUE(usage_info.size() > 0);
|
||||||
|
|
||||||
|
// Read in usage info file
|
||||||
|
std::string usage_info_empty_app_id_file_name =
|
||||||
|
path + DeviceFiles::GetUsageInfoFileName(app_id_empty);
|
||||||
|
|
||||||
|
file_size = file_system.FileSize(usage_info_empty_app_id_file_name);
|
||||||
|
EXPECT_LT(4, file_size);
|
||||||
|
file = file_system.Open(usage_info_empty_app_id_file_name,
|
||||||
|
FileSystem::kReadOnly);
|
||||||
|
EXPECT_TRUE(NULL != file);
|
||||||
|
file_data.resize(file_size);
|
||||||
|
bytes = file->Read(&file_data[0], file_data.size());
|
||||||
|
EXPECT_EQ(file_size, bytes);
|
||||||
|
file->Close();
|
||||||
|
|
||||||
|
EXPECT_TRUE(hash_file.ParseFromString(file_data));
|
||||||
|
pos = file_data.find(hash_file.hash());
|
||||||
|
EXPECT_NE(std::string::npos, pos);
|
||||||
|
EXPECT_NE(0u, pos);
|
||||||
|
|
||||||
|
// Corrupt the protobuf key field of the hash of the usage info file
|
||||||
|
// with empty app id and write it back out
|
||||||
|
file_data[pos-1] = 0xff;
|
||||||
|
|
||||||
|
file = file_system.Open(usage_info_empty_app_id_file_name,
|
||||||
|
FileSystem::kCreate | FileSystem::kTruncate);
|
||||||
|
EXPECT_TRUE(NULL != file);
|
||||||
|
bytes = file->Write(file_data.data(), file_data.size());
|
||||||
|
EXPECT_EQ(file_size, bytes);
|
||||||
|
file->Close();
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
NO_ERROR,
|
||||||
|
decryptor_.RemoveAllUsageInfo(app_id_empty, kDefaultCdmIdentifier));
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
NO_ERROR,
|
||||||
|
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
|
||||||
|
&usage_info));
|
||||||
|
EXPECT_TRUE(usage_info.empty());
|
||||||
|
EXPECT_EQ(
|
||||||
|
NO_ERROR,
|
||||||
|
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
|
||||||
|
&usage_info));
|
||||||
|
EXPECT_TRUE(usage_info.empty());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, GetSecureStopIdsTest) {
|
TEST_F(WvCdmRequestLicenseTest, GetSecureStopIdsTest) {
|
||||||
Unprovision();
|
Unprovision();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user