blob: b4535f17b6ec3b22dfadac6758be41b51f827021 [file] [log] [blame]
// Copyright 2022 The Cobalt Authors. All Rights Reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <string>
#include <unordered_map>
#include "base/values.h"
#include "cobalt/base/application_state.h"
#include "cobalt/persistent_storage/persistent_settings.h"
#include "cobalt/watchdog/singleton.h"
#include "starboard/common/mutex.h"
#include "starboard/mutex.h"
#include "starboard/thread.h"
#include "starboard/time.h"
namespace cobalt {
namespace watchdog {
// Client to monitor
typedef struct Client {
std::string name;
std::string description;
// List of strings optionally provided with each Ping.
base::Value ping_infos;
// Application state to continue monitoring client up to. Inclusive.
base::ApplicationState monitor_state;
// Maximum number of microseconds allowed between pings before triggering a
// Watchdog violation.
int64_t time_interval_microseconds;
// Number of microseconds to initially wait before Watchdog violations can be
// triggered. Reapplies after client resumes from idle state due to
// application state changes.
int64_t time_wait_microseconds;
// Epoch time when client was registered.
int64_t time_registered_microseconds;
// Monotonically increasing timestamp when client was registered. Used as the
// start value for time wait calculations.
SbTimeMonotonic time_registered_monotonic_microseconds;
// Epoch time when client was last pinged. Set by Ping() and Register() when
// in PING replace mode or set initially by Register().
int64_t time_last_pinged_microseconds;
// Monotonically increasing timestamp when client was last updated. Set by
// Ping() and Register() when in PING replace mode or set initially by
// Register(). Also reset by Monitor() when in idle states or when a
// violation occurs. Prevents excessive violations as they must occur
// time_interval_microseconds apart rather than smallest_time_interval_
// apart. Used as the start value for time interval calculations.
SbTimeMonotonic time_last_updated_monotonic_microseconds;
} Client;
// Register behavior with previously registered clients of the same name.
enum Replace {
NONE = 0,
PING = 1,
ALL = 2,
class Watchdog : public Singleton<Watchdog> {
bool Initialize(persistent_storage::PersistentSettings* persistent_settings);
bool InitializeStub();
void Uninitialize();
void UpdateState(base::ApplicationState state);
bool Register(std::string name, base::ApplicationState monitor_state,
int64_t time_interval, int64_t time_wait = 0,
Replace replace = NONE);
bool Register(std::string name, std::string description,
base::ApplicationState monitor_state, int64_t time_interval,
int64_t time_wait = 0, Replace replace = NONE);
bool Unregister(const std::string& name, bool lock = true);
bool Ping(const std::string& name);
bool Ping(const std::string& name, const std::string& info);
std::string GetWatchdogViolations();
bool GetPersistentSettingWatchdogEnable();
void SetPersistentSettingWatchdogEnable(bool enable_watchdog);
bool GetPersistentSettingWatchdogCrash();
void SetPersistentSettingWatchdogCrash(bool can_trigger_crash);
#if defined(_DEBUG)
// Sleeps threads based off of environment variables for Watchdog debugging.
void MaybeInjectDebugDelay(const std::string& name);
#endif // defined(_DEBUG)
std::string GetWatchdogFilePath();
static void* Monitor(void* context);
static void InitializeViolationsMap(void* context);
static void WriteWatchdogViolations(void* context);
static void MaybeTriggerCrash(void* context);
// Watchdog violations file path.
std::string watchdog_file_;
// Access to persistent settings.
persistent_storage::PersistentSettings* persistent_settings_;
// Flag to disable Watchdog. When disabled, Watchdog behaves like a stub
// except that persistent settings can still be get/set.
bool is_disabled_;
// Creates a lock which ensures that each loop of monitor is atomic in that
// modifications to is_monitoring_, state_, smallest_time_interval_, and most
// importantly to the dictionaries containing Watchdog clients, client_map_
// and violations_map_, only occur in between loops of monitor. API functions
// like Register(), Unregister(), Ping(), and GetWatchdogViolations() will be
// called by various threads and interact with these class variables.
SbMutex mutex_;
// Tracks application state.
base::ApplicationState state_ = base::kApplicationStateStarted;
// Time interval between monitor loops.
int64_t smallest_time_interval_;
// Dictionary of registered Watchdog clients.
std::unordered_map<std::string, std::unique_ptr<Client>> client_map_;
// Dictionary of lists of Watchdog violations represented as dictionaries.
std::unique_ptr<base::Value> violations_map_;
// Monitor thread.
SbThread watchdog_thread_;
// Flag to stop monitor thread.
bool is_monitoring_;
#if defined(_DEBUG)
starboard::Mutex delay_lock_;
// name of the client to inject delay
std::string delay_name_ = "";
// since (relative)
SbTimeMonotonic time_last_delayed_microseconds_ = 0;
// time in between delays (periodic)
int64_t delay_wait_time_microseconds_ = 0;
// delay duration
int64_t delay_sleep_time_microseconds_ = 0;
} // namespace watchdog
} // namespace cobalt