Skip to content

Commit

Permalink
Add application state to crash reports. (#580)
Browse files Browse the repository at this point in the history
Add application state to crash reports by using the crash handler
extension and falling back to the crash log dictionary if the extension
is not supported.

Refactors the h5vcc crash log dictionary singleton to support this.

b/261773222

(cherry picked from commit 4eb9bbc)
  • Loading branch information
briantting authored and anonymous1-me committed Jun 22, 2023
1 parent 9d5e39e commit 8e9d9db
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 54 deletions.
35 changes: 35 additions & 0 deletions cobalt/browser/application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,12 @@
#include "cobalt/browser/user_agent_string.h"
#include "cobalt/cache/cache.h"
#include "cobalt/configuration/configuration.h"
<<<<<<< HEAD
#include "cobalt/extension/crash_handler.h"
#include "cobalt/extension/installation_manager.h"
=======
#include "cobalt/h5vcc/h5vcc_crash_log.h"
>>>>>>> 4eb9bbc7fbc (Add application state to crash reports. (#580))
#include "cobalt/loader/image/image_decoder.h"
#include "cobalt/math/size.h"
#include "cobalt/script/javascript_engine.h"
Expand Down Expand Up @@ -589,6 +593,29 @@ void AddCrashHandlerAnnotations() {
}
}

<<<<<<< HEAD
=======
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 && 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;
}

// Crash handler is not supported, fallback to crash log dictionary.
h5vcc::CrashLogDictionary::GetInstance()->SetString("application_state",
application_state);
}

>>>>>>> 4eb9bbc7fbc (Add application state to crash reports. (#580))
} // namespace

// Helper stub to disable histogram tracking in StatisticsRecorder
Expand Down Expand Up @@ -1198,6 +1225,10 @@ void Application::OnApplicationEvent(SbEventType event_type,
case kSbEventTypeStop:
LOG(INFO) << "Got quit event.";
if (watchdog) watchdog->UpdateState(base::kApplicationStateStopped);
<<<<<<< HEAD
=======
AddCrashLogApplicationState(base::kApplicationStateStopped);
>>>>>>> 4eb9bbc7fbc (Add application state to crash reports. (#580))
Quit();
LOG(INFO) << "Finished quitting.";
break;
Expand Down Expand Up @@ -1316,6 +1347,10 @@ void Application::OnApplicationEvent(SbEventType event_type,
return;
}
if (watchdog) watchdog->UpdateState(browser_module_->GetApplicationState());
<<<<<<< HEAD
=======
AddCrashLogApplicationState(browser_module_->GetApplicationState());
>>>>>>> 4eb9bbc7fbc (Add application state to crash reports. (#580))
}

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

0 comments on commit 8e9d9db

Please sign in to comment.