Move Watchdog Timer to L3 Init Only
Merge from Widevine repo of http://go/wvgerrit/31302 This CL moves the oemcrypto watchdog timer so that it only watches the L3 initialization. This will allow L1 initialization to take more than 5 seconds if it needs to. TEST: oemcrypto unit tests, Media GTS tests, Play Movies b/64069544 Merged-In: I7826e4d72eda52ae8b2c9f8b3ac360fb42cbb115 Change-Id: I7826e4d72eda52ae8b2c9f8b3ac360fb42cbb115
This commit is contained in:
committed by
Jeff Tinker
parent
4e53212b0e
commit
1438873443
@@ -377,6 +377,156 @@ void clear_cache_function(void *page, size_t len) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// The WatchDog looks after a worker thread that is trying to initialize L3.
|
||||
// Once in a rare while, the L3 init does not finish and eats up CPU cycles.
|
||||
// If that happens, the watchdog thread will give up and return an error.
|
||||
class WatchDog {
|
||||
public:
|
||||
// Created by main thread.
|
||||
WatchDog() {
|
||||
pthread_mutex_init(&mutex_, NULL);
|
||||
pthread_cond_init(&condition_, NULL);
|
||||
status_ = OEMCrypto_SUCCESS;
|
||||
gave_up_ = false;
|
||||
}
|
||||
|
||||
// Deleted by either thread.
|
||||
~WatchDog() {
|
||||
pthread_cond_destroy(&condition_);
|
||||
}
|
||||
|
||||
// Starts worker thread.
|
||||
void StartThread() {
|
||||
running_ = true;
|
||||
if(pthread_create(&thread_, NULL, RunWatchDog, this)) {
|
||||
LOGE("Could not create watch dog thread.");
|
||||
status_ = OEMCrypto_ERROR_INIT_FAILED;
|
||||
running_ = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Function called by new worker thread in pthread_create.
|
||||
static void *RunWatchDog(void *watcher) {
|
||||
WatchDog* dog = reinterpret_cast<WatchDog *>(watcher);
|
||||
dog->DoInit();
|
||||
dog->SignalDoneAndCleanUp();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Called by worker thread.
|
||||
void DoInit() {
|
||||
std::string base_path;
|
||||
wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&base_path);
|
||||
status_ = Level3_Initialize(clear_cache_function,
|
||||
base_path.c_str());
|
||||
}
|
||||
|
||||
std::string FailureFilename() {
|
||||
std::string path;
|
||||
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&path)) {
|
||||
LOGW("WatchDog::FailureFilename: Unable to get base path");
|
||||
return "/data/l3_failure_file";
|
||||
}
|
||||
path += "l3_failure_file";
|
||||
return path;
|
||||
}
|
||||
|
||||
// Check to see if the failure file was created before that last abort.
|
||||
void CheckForPreviousFailure() {
|
||||
wvcdm::FileSystem file_system;
|
||||
std::string filename = FailureFilename();
|
||||
if (!file_system.Exists(filename)) return;
|
||||
wvcdm::File* file = file_system.Open(filename, file_system.kReadOnly);
|
||||
if (file) {
|
||||
uint32_t flag = 0;
|
||||
ssize_t size = sizeof(flag);
|
||||
ssize_t size_read = file->Read(reinterpret_cast<char*>(&flag), size);
|
||||
file->Close();
|
||||
file_system.Remove(filename);
|
||||
if (size == size_read && flag) {
|
||||
LOGE("Previous L3 Init failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the failure file before we abort.
|
||||
void SaveFailureInformation() {
|
||||
wvcdm::FileSystem file_system;
|
||||
std::string filename = FailureFilename();
|
||||
LOGD("failure filename = %s", filename.c_str());
|
||||
wvcdm::File* file = file_system.Open(
|
||||
filename, file_system.kCreate | file_system.kTruncate);
|
||||
if (!file) {
|
||||
LOGE("Could not create file %s", filename.c_str());
|
||||
return;
|
||||
}
|
||||
uint32_t flag = 0x6261640a; // bad
|
||||
ssize_t size = sizeof(flag);
|
||||
ssize_t size_written = file->Write(reinterpret_cast<char*>(&flag), size);
|
||||
file->Close();
|
||||
if (size != size_written) {
|
||||
LOGE("Wrote %d bytes, not %d, to file %s", size_written, size,
|
||||
filename.c_str());
|
||||
} else {
|
||||
LOGE("I wrote %d to %s", size_written, filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Called by worker thread after DoInit has finshed.
|
||||
void SignalDoneAndCleanUp() {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
running_ = false;
|
||||
pthread_cond_signal(&condition_);
|
||||
// If the main thread gave up, it won't delete this, so we must.
|
||||
bool should_delete = gave_up_;
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
// https://isocpp.org/wiki/faq/freestore-mgmt#delete-this
|
||||
if (should_delete) delete this;
|
||||
}
|
||||
|
||||
// Called by main thread to wait for worker thread.
|
||||
OEMCryptoResult WaitForStatusAndCleanUp() {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
struct timespec time_to_giveup;
|
||||
clock_gettime(CLOCK_REALTIME, &time_to_giveup);
|
||||
time_to_giveup.tv_sec += 5; // wait 5 seconds.
|
||||
if (running_) {
|
||||
pthread_cond_timedwait(&condition_, &mutex_, &time_to_giveup);
|
||||
}
|
||||
if (running_) {
|
||||
gave_up_ = true;
|
||||
status_ = OEMCrypto_ERROR_INIT_FAILED;
|
||||
LOGE("XXX WATCH DOG ERROR XXX");
|
||||
SaveFailureInformation();
|
||||
// This is controversial. The argument for an abort here is that if we
|
||||
// do not abort, we will suck all the life out of the user's battery. By
|
||||
// saving information to the file system, above, we can still track
|
||||
// metrics.
|
||||
abort();
|
||||
}
|
||||
// If we gave up waiting for init thread, we should not delete the mutex
|
||||
// out from under it.
|
||||
bool should_delete = !gave_up_;
|
||||
OEMCryptoResult status = status_;
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
if (should_delete) delete this;
|
||||
return status;
|
||||
}
|
||||
|
||||
OEMCryptoResult status() { return status_; }
|
||||
|
||||
private:
|
||||
OEMCryptoResult status_;
|
||||
pthread_t thread_;
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t condition_;
|
||||
bool running_;
|
||||
bool gave_up_;
|
||||
};
|
||||
|
||||
struct LevelSession {
|
||||
FunctionPointers* fcn;
|
||||
OEMCrypto_SESSION session;
|
||||
@@ -431,11 +581,10 @@ class Adapter {
|
||||
level1_ = FunctionPointers(); // start with all null pointers.
|
||||
level3_ = FunctionPointers(); // start with all null pointers.
|
||||
LoadLevel3();
|
||||
std::string base_path;
|
||||
wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&base_path);
|
||||
OEMCryptoResult result = Level3_Initialize(clear_cache_function,
|
||||
base_path.c_str());
|
||||
WatchDog *watcher = new WatchDog();
|
||||
watcher->CheckForPreviousFailure();
|
||||
watcher->StartThread();
|
||||
OEMCryptoResult result = watcher->WaitForStatusAndCleanUp();
|
||||
if (Level3_IsInApp()) {
|
||||
M_RECORD(
|
||||
&metrics,
|
||||
@@ -844,159 +993,6 @@ class Adapter {
|
||||
|
||||
static Adapter* kAdapter = 0;
|
||||
|
||||
void *RunWatchDog(void *watcher);
|
||||
|
||||
// The WatchDog looks after a worker thread that is trying to initialize L3.
|
||||
// Once in a rare while, the L3 init does not finish and eats up CPU cycles.
|
||||
// If that happens, the watchdog thread will give up and return an error.
|
||||
class WatchDog {
|
||||
public:
|
||||
// Created by main thread.
|
||||
WatchDog() {
|
||||
pthread_mutex_init(&mutex_, NULL);
|
||||
pthread_cond_init(&condition_, NULL);
|
||||
status_ = OEMCrypto_SUCCESS;
|
||||
gave_up_ = false;
|
||||
}
|
||||
|
||||
// Deleted by either thread.
|
||||
~WatchDog() {
|
||||
pthread_cond_destroy(&condition_);
|
||||
}
|
||||
|
||||
// Starts worker thread.
|
||||
void StartThread() {
|
||||
running_ = true;
|
||||
if(pthread_create(&thread_, NULL, RunWatchDog, this)) {
|
||||
LOGE("Could not create watch dog thread.");
|
||||
status_ = OEMCrypto_ERROR_INIT_FAILED;
|
||||
running_ = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Called by worker thread.
|
||||
void DoInit() {
|
||||
if (kAdapter) {
|
||||
kAdapter->Terminate();
|
||||
delete kAdapter;
|
||||
}
|
||||
kAdapter = new Adapter();
|
||||
status_ = kAdapter->Initialize();
|
||||
}
|
||||
|
||||
std::string FailureFilename() {
|
||||
std::string path;
|
||||
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||
&path)) {
|
||||
LOGW("DeviceFiles::StoreFileRaw: Unable to get base path");
|
||||
return "/data/l3_failure_file";
|
||||
}
|
||||
path += "l3_failure_file";
|
||||
return path;
|
||||
}
|
||||
|
||||
// Check to see if the failure file was created before that last abort.
|
||||
void CheckForPreviousFailure() {
|
||||
wvcdm::FileSystem file_system;
|
||||
std::string filename = FailureFilename();
|
||||
if (!file_system.Exists(filename)) return;
|
||||
wvcdm::File* file = file_system.Open(filename, file_system.kReadOnly);
|
||||
if (file) {
|
||||
uint32_t flag = 0;
|
||||
ssize_t size = sizeof(flag);
|
||||
ssize_t size_read = file->Read(reinterpret_cast<char*>(&flag), size);
|
||||
file->Close();
|
||||
file_system.Remove(filename);
|
||||
if (size == size_read && flag) {
|
||||
LOGE("Previous L3 Init failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the failure file before we abort.
|
||||
void SaveFailureInformation() {
|
||||
wvcdm::FileSystem file_system;
|
||||
std::string filename = FailureFilename();
|
||||
LOGD("failure filename = %s", filename.c_str());
|
||||
wvcdm::File* file = file_system.Open(
|
||||
filename, file_system.kCreate | file_system.kTruncate);
|
||||
if (!file) {
|
||||
LOGE("Could not create file %s", filename.c_str());
|
||||
return;
|
||||
}
|
||||
uint32_t flag = 0x6261640a; // bad
|
||||
ssize_t size = sizeof(flag);
|
||||
ssize_t size_written = file->Write(reinterpret_cast<char*>(&flag), size);
|
||||
file->Close();
|
||||
if (size != size_written) {
|
||||
LOGE("Wrote %d bytes, not %d, to file %s", size_written, size,
|
||||
filename.c_str());
|
||||
} else {
|
||||
LOGE("I wrote %d to %s", size_written, filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Called by worker thread after DoInit has finshed.
|
||||
void SignalDoneAndCleanUp() {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
running_ = false;
|
||||
pthread_cond_signal(&condition_);
|
||||
// If the main thread gave up, it won't delete this, so we must.
|
||||
bool should_delete = gave_up_;
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
// https://isocpp.org/wiki/faq/freestore-mgmt#delete-this
|
||||
if (should_delete) delete this;
|
||||
}
|
||||
|
||||
// Called by main thread to wait for worker thread.
|
||||
OEMCryptoResult WaitForStatusAndCleanUp() {
|
||||
pthread_mutex_lock(&mutex_);
|
||||
struct timespec time_to_giveup;
|
||||
clock_gettime(CLOCK_REALTIME, &time_to_giveup);
|
||||
time_to_giveup.tv_sec += 5; // wait 5 seconds.
|
||||
if (running_) {
|
||||
pthread_cond_timedwait(&condition_, &mutex_, &time_to_giveup);
|
||||
}
|
||||
if (running_) {
|
||||
gave_up_ = true;
|
||||
status_ = OEMCrypto_ERROR_INIT_FAILED;
|
||||
LOGE("XXX WATCH DOG ERROR XXX");
|
||||
SaveFailureInformation();
|
||||
// This is controversial. The argument for an abort here is that if we
|
||||
// do not abort, we will suck all the life out of the user's battery. By
|
||||
// saving information to the file system, above, we can still track
|
||||
// metrics.
|
||||
abort();
|
||||
}
|
||||
// If we gave up waiting for init thread, we should not delete the mutex
|
||||
// out from under it.
|
||||
bool should_delete = !gave_up_;
|
||||
OEMCryptoResult status = status_;
|
||||
pthread_mutex_unlock(&mutex_);
|
||||
if (should_delete) delete this;
|
||||
return status;
|
||||
}
|
||||
|
||||
OEMCryptoResult status() { return status_; }
|
||||
|
||||
private:
|
||||
OEMCryptoResult status_;
|
||||
pthread_t thread_;
|
||||
pthread_mutex_t mutex_;
|
||||
pthread_cond_t condition_;
|
||||
bool running_;
|
||||
bool gave_up_;
|
||||
};
|
||||
|
||||
// Function called by new worker thread in pthread_create.
|
||||
void *RunWatchDog(void *watcher) {
|
||||
WatchDog* dog = reinterpret_cast<WatchDog *>(watcher);
|
||||
dog->DoInit();
|
||||
dog->SignalDoneAndCleanUp();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -1217,10 +1213,12 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
|
||||
} // namespace wvcdm
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
|
||||
WatchDog *watcher = new WatchDog();
|
||||
watcher->CheckForPreviousFailure();
|
||||
watcher->StartThread();
|
||||
return watcher->WaitForStatusAndCleanUp();
|
||||
if (kAdapter) {
|
||||
kAdapter->Terminate();
|
||||
delete kAdapter;
|
||||
}
|
||||
kAdapter = new Adapter();
|
||||
return kAdapter->Initialize();
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_Terminate(void) {
|
||||
|
||||
Reference in New Issue
Block a user