Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry pick PR #580: Add application state to crash reports. #691

Merged
merged 2 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions cobalt/browser/application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
#include "cobalt/configuration/configuration.h"
#include "cobalt/extension/crash_handler.h"
#include "cobalt/extension/installation_manager.h"
#include "cobalt/h5vcc/h5vcc_crash_log.h"
#include "cobalt/loader/image/image_decoder.h"
#include "cobalt/math/size.h"
#include "cobalt/script/javascript_engine.h"
Expand Down Expand Up @@ -589,26 +590,24 @@ void AddCrashHandlerAnnotations() {
}
}

void AddCrashHandlerApplicationState(base::ApplicationState state) {
void AddCrashLogApplicationState(base::ApplicationState state) {
std::string application_state = std::string(GetApplicationStateString(state));
application_state.push_back('\0');

auto crash_handler_extension =
static_cast<const CobaltExtensionCrashHandlerApi*>(
SbSystemGetExtension(kCobaltExtensionCrashHandlerName));
if (!crash_handler_extension) {
DLOG(INFO) << "No crash handler extension, not sending application state.";
if (crash_handler_extension && crash_handler_extension->version >= 2) {
if (!crash_handler_extension->SetString("application_state",
application_state.c_str())) {
LOG(ERROR) << "Could not send application state to crash handler.";
}
return;
}

std::string application_state = std::string(GetApplicationStateString(state));
application_state.push_back('\0');

if (crash_handler_extension->version > 1) {
if (crash_handler_extension->SetString("application_state",
application_state.c_str())) {
DLOG(INFO) << "Sent application state to crash handler.";
return;
}
}
DLOG(ERROR) << "Could not send application state to crash handler.";
// Crash handler is not supported, fallback to crash log dictionary.
h5vcc::CrashLogDictionary::GetInstance()->SetString("application_state",
application_state);
}

} // namespace
Expand Down Expand Up @@ -1220,7 +1219,7 @@ void Application::OnApplicationEvent(SbEventType event_type,
case kSbEventTypeStop:
LOG(INFO) << "Got quit event.";
if (watchdog) watchdog->UpdateState(base::kApplicationStateStopped);
AddCrashHandlerApplicationState(base::kApplicationStateStopped);
AddCrashLogApplicationState(base::kApplicationStateStopped);
Quit();
LOG(INFO) << "Finished quitting.";
break;
Expand Down Expand Up @@ -1339,7 +1338,7 @@ void Application::OnApplicationEvent(SbEventType event_type,
return;
}
if (watchdog) watchdog->UpdateState(browser_module_->GetApplicationState());
AddCrashHandlerApplicationState(browser_module_->GetApplicationState());
AddCrashLogApplicationState(browser_module_->GetApplicationState());
}

void Application::OnWindowSizeChangedEvent(const base::Event* event) {
Expand Down
87 changes: 33 additions & 54 deletions cobalt/h5vcc/h5vcc_crash_log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,70 +31,49 @@
namespace cobalt {
namespace h5vcc {

// We keep a global mapping of all registered logs. When a crash occurs, we
// will iterate through the mapping in this dictionary to extract all
// logged entries and write them to the system's crash logger via Starboard.
class CrashLogDictionary {
public:
static CrashLogDictionary* GetInstance() {
return base::Singleton<CrashLogDictionary, base::DefaultSingletonTraits<
CrashLogDictionary> >::get();
}
CrashLogDictionary* CrashLogDictionary::GetInstance() {
return base::Singleton<CrashLogDictionary, base::DefaultSingletonTraits<
CrashLogDictionary>>::get();
}

void SetString(const std::string& key, const std::string& value) {
base::AutoLock lock(mutex_);
// While the lock prevents contention between other calls to SetString(),
// the atomics guard against OnCrash(), which doesn't acquire |mutex_|, from
// accessing the data at the same time. In the case that OnCrash() is
// being called, we give up and skip adding the data.
if (base::subtle::Acquire_CompareAndSwap(&accessing_log_data_, 0, 1) == 0) {
string_log_map_[key] = value;
base::subtle::Release_Store(&accessing_log_data_, 0);
}
void CrashLogDictionary::SetString(const std::string& key,
const std::string& value) {
base::AutoLock lock(mutex_);
// While the lock prevents contention between other calls to SetString(),
// the atomics guard against OnCrash(), which doesn't acquire |mutex_|, from
// accessing the data at the same time. In the case that OnCrash() is
// being called, we give up and skip adding the data.
if (base::subtle::Acquire_CompareAndSwap(&accessing_log_data_, 0, 1) == 0) {
string_log_map_[key] = value;
base::subtle::Release_Store(&accessing_log_data_, 0);
}
}

private:
CrashLogDictionary() : accessing_log_data_(0) {
CrashLogDictionary::CrashLogDictionary() : accessing_log_data_(0) {
#if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
SbCoreDumpRegisterHandler(&CoreDumpHandler, this);
SbCoreDumpRegisterHandler(&CoreDumpHandler, this);
#endif
}
}

static void CoreDumpHandler(void* context) {
CrashLogDictionary* crash_log_dictionary =
static_cast<CrashLogDictionary*>(context);
crash_log_dictionary->OnCrash();
}
void CrashLogDictionary::CoreDumpHandler(void* context) {
CrashLogDictionary* crash_log_dictionary =
static_cast<CrashLogDictionary*>(context);
crash_log_dictionary->OnCrash();
}

void OnCrash() {
void CrashLogDictionary::OnCrash() {
#if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
// Check that we're not already updating log data. If we are, we just
// give up and skip recording any crash data, but hopefully this is rare.
if (base::subtle::Acquire_CompareAndSwap(&accessing_log_data_, 0, 1) == 0) {
for (StringMap::const_iterator iter = string_log_map_.begin();
iter != string_log_map_.end(); ++iter) {
SbCoreDumpLogString(iter->first.c_str(), iter->second.c_str());
}
base::subtle::Release_Store(&accessing_log_data_, 0);
// Check that we're not already updating log data. If we are, we just
// give up and skip recording any crash data, but hopefully this is rare.
if (base::subtle::Acquire_CompareAndSwap(&accessing_log_data_, 0, 1) == 0) {
for (StringMap::const_iterator iter = string_log_map_.begin();
iter != string_log_map_.end(); ++iter) {
SbCoreDumpLogString(iter->first.c_str(), iter->second.c_str());
}
#endif
base::subtle::Release_Store(&accessing_log_data_, 0);
}

friend struct base::DefaultSingletonTraits<CrashLogDictionary>;

base::subtle::Atomic32 accessing_log_data_;

// It is possible for multiple threads to call the H5VCC interface at the
// same time, and they will all forward to this global singleton, so we
// use this mutex to protect against concurrent access.
base::Lock mutex_;

typedef std::map<std::string, std::string> StringMap;
// Keeps track of all string values to be logged when a crash occurs.
StringMap string_log_map_;

DISALLOW_COPY_AND_ASSIGN(CrashLogDictionary);
};
#endif
}

bool H5vccCrashLog::SetString(const std::string& key,
const std::string& value) {
Expand Down
34 changes: 34 additions & 0 deletions cobalt/h5vcc/h5vcc_crash_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
#ifndef COBALT_H5VCC_H5VCC_CRASH_LOG_H_
#define COBALT_H5VCC_H5VCC_CRASH_LOG_H_

#include <map>
#include <string>

#include "base/memory/singleton.h"
#include "cobalt/h5vcc/h5vcc_crash_type.h"
#include "cobalt/h5vcc/watchdog_replace.h"
#include "cobalt/h5vcc/watchdog_state.h"
Expand All @@ -26,6 +28,38 @@
namespace cobalt {
namespace h5vcc {

// We keep a global mapping of all registered logs. When a crash occurs, we
// will iterate through the mapping in this dictionary to extract all
// logged entries and write them to the system's crash logger via Starboard.
class CrashLogDictionary {
public:
static CrashLogDictionary* GetInstance();

void SetString(const std::string& key, const std::string& value);

private:
CrashLogDictionary();

static void CoreDumpHandler(void* context);

void OnCrash();

friend struct base::DefaultSingletonTraits<CrashLogDictionary>;

base::subtle::Atomic32 accessing_log_data_;

// It is possible for multiple threads to call the H5VCC interface at the
// same time, and they will all forward to this global singleton, so we
// use this mutex to protect against concurrent access.
base::Lock mutex_;

typedef std::map<std::string, std::string> StringMap;
// Keeps track of all string values to be logged when a crash occurs.
StringMap string_log_map_;

DISALLOW_COPY_AND_ASSIGN(CrashLogDictionary);
};

class H5vccCrashLog : public script::Wrappable {
public:
H5vccCrashLog() {}
Expand Down
Loading