Merge changes Ia54117ff,I4d469a73,I926d8309 into udc-dev
* changes: Remove comment. Request debug headers and log URL correctly Integration tests for renew on license load
This commit is contained in:
@@ -80,6 +80,8 @@ const RenewalPolicy kLDLRenewal = {"CDM_LimitedDurationLicense_renewal", 0, 0};
|
|||||||
const RenewalPolicy kInfiniteRenewal = {"CDM_InfiniteRenewal_renewal", 0, 0};
|
const RenewalPolicy kInfiniteRenewal = {"CDM_InfiniteRenewal_renewal", 0, 0};
|
||||||
const RenewalPolicy kLicenseDurationWithRenewal = {
|
const RenewalPolicy kLicenseDurationWithRenewal = {
|
||||||
"CDM_LicenseDurationWithRenewal_renewal", 10, 0};
|
"CDM_LicenseDurationWithRenewal_renewal", 10, 0};
|
||||||
|
const RenewalPolicy kRenewOnLicenseLoad = {"CDM_RenewOnLicenseLoad_renewal", 0,
|
||||||
|
0};
|
||||||
const RenewalPolicy kHeartbeatRenewal = {"CDM_Heartbeat_renewal", 10, 30};
|
const RenewalPolicy kHeartbeatRenewal = {"CDM_Heartbeat_renewal", 10, 30};
|
||||||
|
|
||||||
// Key ID in all duration tests.
|
// Key ID in all duration tests.
|
||||||
@@ -1549,10 +1551,121 @@ class CdmUseCase_RenewOnLicenseLoad : public RenewalTest {
|
|||||||
uint64_t renewal_recovery_;
|
uint64_t renewal_recovery_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(b/253513745): Replace this with some real tests.
|
// License loaded within rental duration window and playback continues.
|
||||||
TEST_P(CdmUseCase_RenewOnLicenseLoad, FakeTest) {
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case1S) {
|
||||||
FAIL() << "This test will fail on a v18 server, but "
|
start_of_playback_ = 10;
|
||||||
<< "should be skipped on all existing servers.";
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
SleepUntilRenewalNeeded();
|
||||||
|
const uint64_t start = 15; // time of first decrypt
|
||||||
|
const uint64_t load_renewal = 20;
|
||||||
|
const uint64_t stop = 45;
|
||||||
|
RenewAndContinue(start, load_renewal, stop, kRenewOnLicenseLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// License loaded within rental duration window and playback continues.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case1M) {
|
||||||
|
start_of_playback_ = 10;
|
||||||
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
SleepUntilRenewalNeeded();
|
||||||
|
const uint64_t start = 20; // time of first decrypt
|
||||||
|
const uint64_t load_renewal = 20;
|
||||||
|
const uint64_t stop = 45; // end of decrypt
|
||||||
|
RenewAndContinue(start, load_renewal, stop, kRenewOnLicenseLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// License loaded within rental duration window and playback continues.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case1L) {
|
||||||
|
start_of_playback_ = 10;
|
||||||
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
SleepUntilRenewalNeeded();
|
||||||
|
RequestRenewal(kRenewOnLicenseLoad);
|
||||||
|
const uint64_t load_renewal = 20;
|
||||||
|
const uint64_t start = 25; // time of first decrypt
|
||||||
|
const uint64_t stop = 45; // end of decrypt
|
||||||
|
LoadRenewal(load_renewal, kRenewOnLicenseLoad);
|
||||||
|
AllowPlayback(start, stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// License loaded after rental duration window and playback should fail.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case2) {
|
||||||
|
start_of_playback_ = EndOfRentalWindow() + 1;
|
||||||
|
ForbidPlayback(start_of_playback_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// License loaded within rental duration window but renewal not received.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case3S) {
|
||||||
|
start_of_playback_ = 10;
|
||||||
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
const uint64_t start = 15; // time of first decrypt
|
||||||
|
// Allow playback within the initial renewal window.
|
||||||
|
const uint64_t cutoff =
|
||||||
|
start_of_playback_ + renewal_delay_ + renewal_recovery_;
|
||||||
|
TerminatePlayback(start, cutoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// License loaded within rental duration window but renewal not received.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case3M) {
|
||||||
|
start_of_playback_ = 10;
|
||||||
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
const uint64_t start = 25; // time of first decrypt
|
||||||
|
// Allow playback within the initial renewal window.
|
||||||
|
const uint64_t cutoff =
|
||||||
|
start_of_playback_ + renewal_delay_ + renewal_recovery_;
|
||||||
|
TerminatePlayback(start, cutoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// License loaded within rental duration window but renewal not received.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case3L) {
|
||||||
|
start_of_playback_ = 10;
|
||||||
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
const uint64_t start = 35; // time of first decrypt
|
||||||
|
SleepUntil(start);
|
||||||
|
// No playback at all.
|
||||||
|
FailDecrypt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Playback is started within the rental duration window and the renewal is
|
||||||
|
// received, but playback exceeds the playback duration.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case4) {
|
||||||
|
start_of_playback_ = 10;
|
||||||
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
SleepUntilRenewalNeeded();
|
||||||
|
const uint64_t start = 20; // time of first decrypt
|
||||||
|
const uint64_t load_renewal = 20;
|
||||||
|
const uint64_t stop = 45; // end of decrypt
|
||||||
|
const uint64_t cutoff = EndOfPlaybackWindow();
|
||||||
|
RenewAndContinue(start, load_renewal, stop, kRenewOnLicenseLoad);
|
||||||
|
TerminatePlayback(stop, cutoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Playback is able to be restarted.
|
||||||
|
TEST_P(CdmUseCase_RenewOnLicenseLoad, Case5) {
|
||||||
|
start_of_playback_ = 10;
|
||||||
|
const uint64_t load_renewal = 20;
|
||||||
|
SleepUntil(start_of_playback_);
|
||||||
|
LoadLicense();
|
||||||
|
SleepUntilRenewalNeeded();
|
||||||
|
RequestRenewal(kRenewOnLicenseLoad);
|
||||||
|
const uint64_t start = 20;
|
||||||
|
const uint64_t end = 35;
|
||||||
|
RenewAndContinue(start, load_renewal, end, kRenewOnLicenseLoad);
|
||||||
|
UnloadLicense();
|
||||||
|
// Simulate reloading the license, and then reloading the renewal, and then
|
||||||
|
// restarting playback. That is allowed, and playback shall be terminated at
|
||||||
|
// the end of the original playback window.
|
||||||
|
const uint64_t reload_time = 45;
|
||||||
|
ReloadAndAllowPlayback(reload_time, EndOfPlaybackWindow(),
|
||||||
|
kRenewOnLicenseLoad);
|
||||||
|
// But not beyond playback window.
|
||||||
|
SleepUntil(EndOfPlaybackWindow() + 3 * kFudge);
|
||||||
|
FailDecrypt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heartbeat Playback Window License. (See above for notes on Use Case tests).
|
// Heartbeat Playback Window License. (See above for notes on Use Case tests).
|
||||||
|
|||||||
@@ -328,14 +328,13 @@ bool HttpSocket::Connect(int timeout_in_ms) {
|
|||||||
} else {
|
} else {
|
||||||
if (GetError() != ERROR_ASYNC_COMPLETE) {
|
if (GetError() != ERROR_ASYNC_COMPLETE) {
|
||||||
// failed right away.
|
// failed right away.
|
||||||
LOGE("cannot connect to %s, errno = %d", domain_name_.c_str(),
|
LOGE("cannot connect to %s, errno = %d", url().c_str(), GetError());
|
||||||
GetError());
|
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// in progress. block until timeout expired or connection established.
|
// in progress. block until timeout expired or connection established.
|
||||||
if (!Wait(/* for_read */ false, timeout_in_ms)) {
|
if (!Wait(/* for_read */ false, timeout_in_ms)) {
|
||||||
LOGE("cannot connect to %s", domain_name_.c_str());
|
LOGE("cannot connect to %s", url().c_str());
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ class HttpSocket {
|
|||||||
const std::string& domain_name() const { return domain_name_; }
|
const std::string& domain_name() const { return domain_name_; }
|
||||||
int port() const { return atoi(port_.c_str()); }
|
int port() const { return atoi(port_.c_str()); }
|
||||||
const std::string& resource_path() const { return resource_path_; }
|
const std::string& resource_path() const { return resource_path_; }
|
||||||
|
std::string url() const {
|
||||||
|
return scheme_ + "://" + domain_name_ + ":" + port_ + resource_path_;
|
||||||
|
}
|
||||||
|
|
||||||
int ReadAndLogErrors(char* data, int len, int timeout_in_ms);
|
int ReadAndLogErrors(char* data, int len, int timeout_in_ms);
|
||||||
int WriteAndLogErrors(const char* data, int len, int timeout_in_ms);
|
int WriteAndLogErrors(const char* data, int len, int timeout_in_ms);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ void UrlRequest::Reconnect() {
|
|||||||
is_connected_ = true;
|
is_connected_ = true;
|
||||||
} else {
|
} else {
|
||||||
LOGE("Failed to connect: url = %s, port = %d, attempt = %u",
|
LOGE("Failed to connect: url = %s, port = %d, attempt = %u",
|
||||||
socket_.domain_name().c_str(), socket_.port(), i);
|
socket_.url().c_str(), socket_.port(), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,9 +121,8 @@ bool UrlRequest::GetResponse(std::string* message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConcatenateChunkedResponse(response, message);
|
ConcatenateChunkedResponse(response, message);
|
||||||
LOGV("HTTP response from %s://%s:%d%s: (%zu): %s", socket_.scheme().c_str(),
|
LOGV("HTTP response from %s: (%zu): %s", socket_.url().c_str(),
|
||||||
socket_.domain_name().c_str(), socket_.port(),
|
message->size(), message->c_str());
|
||||||
socket_.resource_path().c_str(), message->size(), message->c_str());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,10 +130,8 @@ void UrlRequest::AssertOkResponse(std::string* message) {
|
|||||||
ASSERT_TRUE(message);
|
ASSERT_TRUE(message);
|
||||||
ASSERT_TRUE(GetResponse(message));
|
ASSERT_TRUE(GetResponse(message));
|
||||||
const int status_code = GetStatusCode(*message);
|
const int status_code = GetStatusCode(*message);
|
||||||
ASSERT_EQ(kHttpOk, status_code)
|
ASSERT_EQ(kHttpOk, status_code) << "HTTP response from " << socket_.url()
|
||||||
<< "HTTP response from " << socket_.scheme() << "://"
|
<< ": (" << message->size() << ") :\n"
|
||||||
<< socket_.domain_name() << ":" << socket_.port()
|
|
||||||
<< socket_.resource_path() << ": (" << message->size() << ") :\n"
|
|
||||||
<< *message;
|
<< *message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +201,7 @@ bool UrlRequest::PostRequestWithPath(const std::string& path,
|
|||||||
|
|
||||||
request.append("Connection: close\r\n");
|
request.append("Connection: close\r\n");
|
||||||
request.append("User-Agent: Widevine CDM v1.0\r\n");
|
request.append("User-Agent: Widevine CDM v1.0\r\n");
|
||||||
|
request.append("X-Return-Encrypted-Headers: request_and_response\r\n");
|
||||||
|
|
||||||
// buffer to store length of data as a string
|
// buffer to store length of data as a string
|
||||||
char data_size_buffer[32] = {0};
|
char data_size_buffer[32] = {0};
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ struct WvStatus {
|
|||||||
private:
|
private:
|
||||||
AidlDrmStatus mStatus{};
|
AidlDrmStatus mStatus{};
|
||||||
wvcdm::CdmResponseType mCdmErr{};
|
wvcdm::CdmResponseType mCdmErr{};
|
||||||
// WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(WvStatus);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvdrm
|
} // namespace wvdrm
|
||||||
|
|||||||
Reference in New Issue
Block a user