Move Watchdog Timer to L3 Init Only
am: 1438873443
Change-Id: I424b5606f1b0fd4bd5cdee45085c6843a65818ee
This commit is contained in:
@@ -377,6 +377,156 @@ void clear_cache_function(void *page, size_t len) {
|
|||||||
#endif
|
#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 {
|
struct LevelSession {
|
||||||
FunctionPointers* fcn;
|
FunctionPointers* fcn;
|
||||||
OEMCrypto_SESSION session;
|
OEMCrypto_SESSION session;
|
||||||
@@ -431,11 +581,10 @@ class Adapter {
|
|||||||
level1_ = FunctionPointers(); // start with all null pointers.
|
level1_ = FunctionPointers(); // start with all null pointers.
|
||||||
level3_ = FunctionPointers(); // start with all null pointers.
|
level3_ = FunctionPointers(); // start with all null pointers.
|
||||||
LoadLevel3();
|
LoadLevel3();
|
||||||
std::string base_path;
|
WatchDog *watcher = new WatchDog();
|
||||||
wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
watcher->CheckForPreviousFailure();
|
||||||
&base_path);
|
watcher->StartThread();
|
||||||
OEMCryptoResult result = Level3_Initialize(clear_cache_function,
|
OEMCryptoResult result = watcher->WaitForStatusAndCleanUp();
|
||||||
base_path.c_str());
|
|
||||||
if (Level3_IsInApp()) {
|
if (Level3_IsInApp()) {
|
||||||
M_RECORD(
|
M_RECORD(
|
||||||
&metrics,
|
&metrics,
|
||||||
@@ -844,159 +993,6 @@ class Adapter {
|
|||||||
|
|
||||||
static Adapter* kAdapter = 0;
|
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
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
@@ -1217,10 +1213,12 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
|
|||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
|
extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
|
||||||
WatchDog *watcher = new WatchDog();
|
if (kAdapter) {
|
||||||
watcher->CheckForPreviousFailure();
|
kAdapter->Terminate();
|
||||||
watcher->StartThread();
|
delete kAdapter;
|
||||||
return watcher->WaitForStatusAndCleanUp();
|
}
|
||||||
|
kAdapter = new Adapter();
|
||||||
|
return kAdapter->Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_Terminate(void) {
|
extern "C" OEMCryptoResult OEMCrypto_Terminate(void) {
|
||||||
|
|||||||
Reference in New Issue
Block a user