diff --git a/cobalt/watchdog/watchdog.cc b/cobalt/watchdog/watchdog.cc index 7178cd948765..20cb0dc027c1 100644 --- a/cobalt/watchdog/watchdog.cc +++ b/cobalt/watchdog/watchdog.cc @@ -208,39 +208,24 @@ void* Watchdog::Monitor(void* context) { starboard::ScopedLock scoped_lock(static_cast(context)->mutex_); while (1) { SbTimeMonotonic current_monotonic_time = SbTimeGetMonotonicNow(); - - // Iterates through client map to monitor all registered clients. bool watchdog_violation = false; + + // Iterates through client map to monitor all name registered clients. for (auto& it : static_cast(context)->client_map_) { Client* client = it.second.get(); - // Ignores and resets clients in idle states, clients whose monitor_state - // is below the current application state. Resets time_wait_microseconds - // and time_interval_microseconds start values. - if (static_cast(context)->state_ > client->monitor_state) { - client->time_registered_monotonic_microseconds = current_monotonic_time; - client->time_last_updated_monotonic_microseconds = - current_monotonic_time; - continue; + if (MonitorClient(context, client, current_monotonic_time)) { + watchdog_violation = true; } + } - SbTimeMonotonic time_delta = - current_monotonic_time - - client->time_last_updated_monotonic_microseconds; - SbTimeMonotonic time_wait = - current_monotonic_time - - client->time_registered_monotonic_microseconds; - - // Watchdog violation - if (time_delta > client->time_interval_microseconds && - time_wait > client->time_wait_microseconds) { + // Iterates through client list to monitor all client registered clients. + for (auto& it : static_cast(context)->client_list_) { + Client* client = it.get(); + if (MonitorClient(context, client, current_monotonic_time)) { watchdog_violation = true; - UpdateViolationsMap(context, client, time_delta); - - // Resets time last updated. - client->time_last_updated_monotonic_microseconds = - current_monotonic_time; } } + if (static_cast(context)->pending_write_) MaybeWriteWatchdogViolations(context); if (watchdog_violation) MaybeTriggerCrash(context); @@ -255,6 +240,33 @@ void* Watchdog::Monitor(void* context) { return nullptr; } +bool Watchdog::MonitorClient(void* context, Client* client, + SbTimeMonotonic current_monotonic_time) { + // Ignores and resets clients in idle states, clients whose monitor_state + // is below the current application state. Resets time_wait_microseconds + // and time_interval_microseconds start values. + if (static_cast(context)->state_ > client->monitor_state) { + client->time_registered_monotonic_microseconds = current_monotonic_time; + client->time_last_updated_monotonic_microseconds = current_monotonic_time; + return false; + } + + SbTimeMonotonic time_delta = + current_monotonic_time - client->time_last_updated_monotonic_microseconds; + SbTimeMonotonic time_wait = + current_monotonic_time - client->time_registered_monotonic_microseconds; + + // Watchdog violation + if (time_delta > client->time_interval_microseconds && + time_wait > client->time_wait_microseconds) { + UpdateViolationsMap(context, client, time_delta); + // Resets time last updated. + client->time_last_updated_monotonic_microseconds = current_monotonic_time; + return true; + } + return false; +} + void Watchdog::UpdateViolationsMap(void* context, Client* client, SbTimeMonotonic time_delta) { // Gets violation dictionary with key client name from violations map. @@ -309,6 +321,9 @@ void Watchdog::UpdateViolationsMap(void* context, Client* client, for (auto& it : static_cast(context)->client_map_) { registered_clients.GetList().emplace_back(base::Value(it.first)); } + for (auto& it : static_cast(context)->client_list_) { + registered_clients.GetList().emplace_back(base::Value(it->name)); + } violation.SetKey("registeredClients", registered_clients.Clone()); // Adds new violation to violations map. @@ -423,19 +438,6 @@ bool Watchdog::Register(std::string name, std::string description, int64_t time_wait_microseconds, Replace replace) { if (is_disabled_) return true; - // Validates parameters. - if (time_interval_microseconds < watchdog_monitor_frequency_ || - time_wait_microseconds < 0) { - SB_DLOG(ERROR) << "[Watchdog] Unable to Register: " << name; - if (time_interval_microseconds < watchdog_monitor_frequency_) { - SB_DLOG(ERROR) << "[Watchdog] Time interval less than min: " - << watchdog_monitor_frequency_; - } else { - SB_DLOG(ERROR) << "[Watchdog] Time wait is negative."; - } - return false; - } - starboard::ScopedLock scoped_lock(mutex_); int64_t current_time = SbTimeToPosix(SbTimeGetNow()); @@ -457,6 +459,65 @@ bool Watchdog::Register(std::string name, std::string description, } } + // Creates new client. + std::unique_ptr client = CreateClient( + name, description, monitor_state, time_interval_microseconds, + time_wait_microseconds, current_time, current_monotonic_time); + if (client == nullptr) return false; + + // Registers. + auto result = client_map_.emplace(name, std::move(client)); + + if (result.second) { + SB_DLOG(INFO) << "[Watchdog] Registered: " << name; + } else { + SB_DLOG(ERROR) << "[Watchdog] Unable to Register: " << name; + } + return result.second; +} + +std::shared_ptr Watchdog::RegisterByClient( + std::string name, std::string description, + base::ApplicationState monitor_state, int64_t time_interval_microseconds, + int64_t time_wait_microseconds) { + if (is_disabled_) return nullptr; + + starboard::ScopedLock scoped_lock(mutex_); + + int64_t current_time = SbTimeToPosix(SbTimeGetNow()); + SbTimeMonotonic current_monotonic_time = SbTimeGetMonotonicNow(); + + // Creates new client. + std::shared_ptr client = CreateClient( + name, description, monitor_state, time_interval_microseconds, + time_wait_microseconds, current_time, current_monotonic_time); + if (client == nullptr) return nullptr; + + // Registers. + client_list_.emplace_back(client); + + SB_DLOG(INFO) << "[Watchdog] Registered: " << name; + return client; +} + +std::unique_ptr Watchdog::CreateClient( + std::string name, std::string description, + base::ApplicationState monitor_state, int64_t time_interval_microseconds, + int64_t time_wait_microseconds, int64_t current_time, + SbTimeMonotonic current_monotonic_time) { + // Validates parameters. + if (time_interval_microseconds < watchdog_monitor_frequency_ || + time_wait_microseconds < 0) { + SB_DLOG(ERROR) << "[Watchdog] Unable to Register: " << name; + if (time_interval_microseconds < watchdog_monitor_frequency_) { + SB_DLOG(ERROR) << "[Watchdog] Time interval less than min: " + << watchdog_monitor_frequency_; + } else { + SB_DLOG(ERROR) << "[Watchdog] Time wait is negative."; + } + return nullptr; + } + // Creates new Client. std::unique_ptr client(new Client); client->name = name; @@ -470,15 +531,7 @@ bool Watchdog::Register(std::string name, std::string description, client->time_last_pinged_microseconds = current_time; client->time_last_updated_monotonic_microseconds = current_monotonic_time; - // Registers. - auto result = client_map_.emplace(name, std::move(client)); - - if (result.second) { - SB_DLOG(INFO) << "[Watchdog] Registered: " << name; - } else { - SB_DLOG(ERROR) << "[Watchdog] Unable to Register: " << name; - } - return result.second; + return std::move(client); } bool Watchdog::Unregister(const std::string& name, bool lock) { @@ -497,11 +550,68 @@ bool Watchdog::Unregister(const std::string& name, bool lock) { return result; } +bool Watchdog::UnregisterByClient(std::shared_ptr client) { + if (is_disabled_) return true; + + starboard::ScopedLock scoped_lock(mutex_); + + std::string name = ""; + if (client) name = client->name; + + // Unregisters. + for (auto it = client_list_.begin(); it != client_list_.end(); it++) { + if (client == *it) { + client_list_.erase(it); + SB_DLOG(INFO) << "[Watchdog] Unregistered: " << name; + return true; + } + } + SB_DLOG(ERROR) << "[Watchdog] Unable to Unregister: " << name; + return false; +} + bool Watchdog::Ping(const std::string& name) { return Ping(name, ""); } bool Watchdog::Ping(const std::string& name, const std::string& info) { if (is_disabled_) return true; + starboard::ScopedLock scoped_lock(mutex_); + + auto it = client_map_.find(name); + bool client_exists = it != client_map_.end(); + + if (client_exists) { + Client* client = it->second.get(); + return PingHelper(client, name, info); + } + SB_DLOG(ERROR) << "[Watchdog] Unable to Ping: " << name; + return false; +} + +bool Watchdog::PingByClient(std::shared_ptr client) { + return PingByClient(client, ""); +} + +bool Watchdog::PingByClient(std::shared_ptr client, + const std::string& info) { + if (is_disabled_) return true; + + std::string name = ""; + if (client) name = client->name; + + starboard::ScopedLock scoped_lock(mutex_); + + for (auto it = client_list_.begin(); it != client_list_.end(); it++) { + if (client == *it) { + return PingHelper(client.get(), name, info); + } + } + SB_DLOG(ERROR) << "[Watchdog] Unable to Ping: " << name; + return false; +} + +bool Watchdog::PingHelper(Client* client, const std::string& name, + const std::string& info) { // Validates parameters. if (info.length() > kWatchdogMaxPingInfoLength) { SB_DLOG(ERROR) << "[Watchdog] Unable to Ping: " << name; @@ -510,36 +620,25 @@ bool Watchdog::Ping(const std::string& name, const std::string& info) { return false; } - starboard::ScopedLock scoped_lock(mutex_); - - auto it = client_map_.find(name); - bool client_exists = it != client_map_.end(); + int64_t current_time = SbTimeToPosix(SbTimeGetNow()); + SbTimeMonotonic current_monotonic_time = SbTimeGetMonotonicNow(); - if (client_exists) { - int64_t current_time = SbTimeToPosix(SbTimeGetNow()); - SbTimeMonotonic current_monotonic_time = SbTimeGetMonotonicNow(); + // Updates last ping. + client->time_last_pinged_microseconds = current_time; + client->time_last_updated_monotonic_microseconds = current_monotonic_time; - Client* client = it->second.get(); - // Updates last ping. - client->time_last_pinged_microseconds = current_time; - client->time_last_updated_monotonic_microseconds = current_monotonic_time; + if (info != "") { + // Creates new ping_info. + base::Value ping_info(base::Value::Type::DICTIONARY); + ping_info.SetKey("timestampMilliseconds", + base::Value(std::to_string(current_time / 1000))); + ping_info.SetKey("info", base::Value(info)); - if (info != "") { - // Creates new ping_info. - base::Value ping_info(base::Value::Type::DICTIONARY); - ping_info.SetKey("timestampMilliseconds", - base::Value(std::to_string(current_time / 1000))); - ping_info.SetKey("info", base::Value(info)); - - client->ping_infos.GetList().emplace_back(ping_info.Clone()); - if (client->ping_infos.GetList().size() > kWatchdogMaxPingInfos) - client->ping_infos.GetList().erase( - client->ping_infos.GetList().begin()); - } - } else { - SB_DLOG(ERROR) << "[Watchdog] Unable to Ping: " << name; + client->ping_infos.GetList().emplace_back(ping_info.Clone()); + if (client->ping_infos.GetList().size() > kWatchdogMaxPingInfos) + client->ping_infos.GetList().erase(client->ping_infos.GetList().begin()); } - return client_exists; + return true; } std::string Watchdog::GetWatchdogViolations( diff --git a/cobalt/watchdog/watchdog.h b/cobalt/watchdog/watchdog.h index 14b0c10744f2..aed2ec1db177 100644 --- a/cobalt/watchdog/watchdog.h +++ b/cobalt/watchdog/watchdog.h @@ -88,9 +88,19 @@ class Watchdog : public Singleton { base::ApplicationState monitor_state, int64_t time_interval_microseconds, int64_t time_wait_microseconds = 0, Replace replace = NONE); + std::shared_ptr RegisterByClient(std::string name, + std::string description, + base::ApplicationState monitor_state, + int64_t time_interval_microseconds, + int64_t time_wait_microseconds = 0); bool Unregister(const std::string& name, bool lock = true); + bool UnregisterByClient(std::shared_ptr client); bool Ping(const std::string& name); bool Ping(const std::string& name, const std::string& info); + bool PingByClient(std::shared_ptr client); + bool PingByClient(std::shared_ptr client, const std::string& info); + bool PingHelper(Client* client, const std::string& name, + const std::string& info); std::string GetWatchdogViolations( const std::vector& clients = {}, bool clear = true); bool GetPersistentSettingWatchdogEnable(); @@ -107,7 +117,16 @@ class Watchdog : public Singleton { std::shared_ptr GetViolationsMap(); void WriteWatchdogViolations(); void EvictOldWatchdogViolations(); + std::unique_ptr CreateClient(std::string name, + std::string description, + base::ApplicationState monitor_state, + int64_t time_interval_microseconds, + int64_t time_wait_microseconds, + int64_t current_time, + SbTimeMonotonic current_monotonic_time); static void* Monitor(void* context); + static bool MonitorClient(void* context, Client* client, + SbTimeMonotonic current_monotonic_time); static void UpdateViolationsMap(void* context, Client* client, SbTimeMonotonic time_delta); static void EvictWatchdogViolation(void* context); @@ -139,8 +158,11 @@ class Watchdog : public Singleton { SbTimeMonotonic time_last_written_microseconds_ = 0; // Number of microseconds between writes. int64_t write_wait_time_microseconds_; - // Dictionary of registered Watchdog clients. + // Dictionary of name registered Watchdog clients. std::unordered_map> client_map_; + // List of client registered Watchdog clients, parallel data structure to + // client_map_. + std::vector> client_list_; // Dictionary of lists of Watchdog violations represented as dictionaries. std::shared_ptr violations_map_; // Monitor thread. diff --git a/cobalt/watchdog/watchdog_test.cc b/cobalt/watchdog/watchdog_test.cc index 7b4d740b96f6..ec3116cf3f95 100644 --- a/cobalt/watchdog/watchdog_test.cc +++ b/cobalt/watchdog/watchdog_test.cc @@ -86,7 +86,6 @@ TEST_F(WatchdogTest, RedundantRegistersShouldFail) { ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted, kWatchdogMonitorFrequency)); - ASSERT_FALSE(watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted, kWatchdogMonitorFrequency)); @@ -100,10 +99,6 @@ TEST_F(WatchdogTest, RedundantRegistersShouldFail) { } TEST_F(WatchdogTest, RegisterOnlyAcceptsValidParameters) { - ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", - base::kApplicationStateStarted, - kWatchdogMonitorFrequency, 0)); - ASSERT_TRUE(watchdog_->Unregister("test-name")); ASSERT_FALSE(watchdog_->Register("test-name-1", "test-desc-1", base::kApplicationStateStarted, 1, 0)); ASSERT_FALSE(watchdog_->Unregister("test-name-1")); @@ -127,7 +122,37 @@ TEST_F(WatchdogTest, RegisterOnlyAcceptsValidParameters) { ASSERT_FALSE(watchdog_->Unregister("test-name-6")); } -TEST_F(WatchdogTest, UnmatchedUnregistersShouldFail) { +TEST_F(WatchdogTest, RegisterByClientOnlyAcceptsValidParameters) { + std::shared_ptr client = watchdog_->RegisterByClient( + "test-name", "test-desc", base::kApplicationStateStarted, 1, 0); + ASSERT_EQ(client, nullptr); + ASSERT_FALSE(watchdog_->UnregisterByClient(client)); + client = watchdog_->RegisterByClient("test-name", "test-desc", + base::kApplicationStateStarted, 0, 0); + ASSERT_EQ(client, nullptr); + ASSERT_FALSE(watchdog_->UnregisterByClient(client)); + client = watchdog_->RegisterByClient("test-name", "test-desc", + base::kApplicationStateStarted, -1, 0); + ASSERT_EQ(client, nullptr); + ASSERT_FALSE(watchdog_->UnregisterByClient(client)); + client = watchdog_->RegisterByClient("test-name", "test-desc", + base::kApplicationStateStarted, + kWatchdogMonitorFrequency, 1); + ASSERT_NE(client, nullptr); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); + client = watchdog_->RegisterByClient("test-name", "test-desc", + base::kApplicationStateStarted, + kWatchdogMonitorFrequency, 0); + ASSERT_NE(client, nullptr); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); + client = watchdog_->RegisterByClient("test-name", "test-desc", + base::kApplicationStateStarted, + kWatchdogMonitorFrequency, -1); + ASSERT_EQ(client, nullptr); + ASSERT_FALSE(watchdog_->UnregisterByClient(client)); +} + +TEST_F(WatchdogTest, UnmatchedUnregisterShouldFail) { ASSERT_FALSE(watchdog_->Unregister("test-name")); ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted, @@ -136,17 +161,39 @@ TEST_F(WatchdogTest, UnmatchedUnregistersShouldFail) { ASSERT_FALSE(watchdog_->Unregister("test-name")); } -TEST_F(WatchdogTest, UnmatchedPingsShouldFail) { +TEST_F(WatchdogTest, UnmatchedUnregisterByClientShouldFail) { + std::shared_ptr client_test(new Client); + ASSERT_FALSE(watchdog_->UnregisterByClient(client_test)); + std::shared_ptr client = watchdog_->RegisterByClient( + "test-name", "test-desc", base::kApplicationStateStarted, + kWatchdogMonitorFrequency); + ASSERT_NE(client, nullptr); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); + ASSERT_FALSE(watchdog_->UnregisterByClient(client)); +} + +TEST_F(WatchdogTest, UnmatchedPingShouldFail) { ASSERT_FALSE(watchdog_->Ping("test-name")); ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted, kWatchdogMonitorFrequency)); ASSERT_TRUE(watchdog_->Ping("test-name")); - ASSERT_TRUE(watchdog_->Ping("test-name")); ASSERT_TRUE(watchdog_->Unregister("test-name")); ASSERT_FALSE(watchdog_->Ping("test-name")); } +TEST_F(WatchdogTest, UnmatchedPingByClientShouldFail) { + std::shared_ptr client_test(new Client); + ASSERT_FALSE(watchdog_->PingByClient(client_test)); + std::shared_ptr client = watchdog_->RegisterByClient( + "test-name", "test-desc", base::kApplicationStateStarted, + kWatchdogMonitorFrequency); + ASSERT_NE(client, nullptr); + ASSERT_TRUE(watchdog_->PingByClient(client)); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); + ASSERT_FALSE(watchdog_->PingByClient(client)); +} + TEST_F(WatchdogTest, PingOnlyAcceptsValidParameters) { ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted, @@ -160,6 +207,20 @@ TEST_F(WatchdogTest, PingOnlyAcceptsValidParameters) { ASSERT_TRUE(watchdog_->Unregister("test-name")); } +TEST_F(WatchdogTest, PingByClientOnlyAcceptsValidParameters) { + std::shared_ptr client = watchdog_->RegisterByClient( + "test-name", "test-desc", base::kApplicationStateStarted, + kWatchdogMonitorFrequency); + ASSERT_NE(client, nullptr); + ASSERT_TRUE(watchdog_->PingByClient(client, "42")); + ASSERT_FALSE(watchdog_->PingByClient( + client, + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxx")); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); +} + TEST_F(WatchdogTest, ViolationsJsonShouldPersistAndBeValid) { ASSERT_EQ(watchdog_->GetWatchdogViolations(), ""); ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", @@ -281,11 +342,12 @@ TEST_F(WatchdogTest, ViolationsShouldResetAfterFetch) { std::string json = watchdog_->GetWatchdogViolations(); ASSERT_NE(json.find("test-name-1"), std::string::npos); ASSERT_EQ(json.find("test-name-2"), std::string::npos); - ASSERT_TRUE(watchdog_->Register("test-name-2", "test-desc-2", - base::kApplicationStateStarted, - kWatchdogMonitorFrequency)); + std::shared_ptr client = watchdog_->RegisterByClient( + "test-name-2", "test-desc-2", base::kApplicationStateStarted, + kWatchdogMonitorFrequency); + ASSERT_NE(client, nullptr); SbThreadSleep(kWatchdogSleepDuration); - ASSERT_TRUE(watchdog_->Unregister("test-name-2")); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); json = watchdog_->GetWatchdogViolations(); ASSERT_EQ(json.find("test-name-1"), std::string::npos); ASSERT_NE(json.find("test-name-2"), std::string::npos); @@ -408,7 +470,7 @@ TEST_F(WatchdogTest, TimeWaitShouldPreventViolations) { ASSERT_TRUE(watchdog_->Unregister("test-name")); } -TEST_F(WatchdogTest, PingsShouldPreventViolations) { +TEST_F(WatchdogTest, PingShouldPreventViolations) { ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted, kWatchdogMonitorFrequency)); @@ -438,6 +500,20 @@ TEST_F(WatchdogTest, PingsShouldPreventViolations) { ASSERT_TRUE(watchdog_->Unregister("test-name")); } +TEST_F(WatchdogTest, PingByClientShouldPreventViolations) { + std::shared_ptr client = watchdog_->RegisterByClient( + "test-name", "test-desc", base::kApplicationStateStarted, + kWatchdogMonitorFrequency); + SbThreadSleep(kWatchdogMonitorFrequency / 2); + ASSERT_TRUE(watchdog_->PingByClient(client)); + SbThreadSleep(kWatchdogMonitorFrequency / 2); + ASSERT_TRUE(watchdog_->PingByClient(client)); + ASSERT_EQ(watchdog_->GetWatchdogViolations(), ""); + SbThreadSleep(kWatchdogSleepDuration); + ASSERT_NE(watchdog_->GetWatchdogViolations(), ""); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); +} + TEST_F(WatchdogTest, UnregisterShouldPreventViolations) { ASSERT_TRUE(watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted, @@ -447,6 +523,15 @@ TEST_F(WatchdogTest, UnregisterShouldPreventViolations) { ASSERT_EQ(watchdog_->GetWatchdogViolations(), ""); } +TEST_F(WatchdogTest, UnregisterByClientShouldPreventViolations) { + std::shared_ptr client = watchdog_->RegisterByClient( + "test-name", "test-desc", base::kApplicationStateStarted, + kWatchdogMonitorFrequency); + ASSERT_TRUE(watchdog_->UnregisterByClient(client)); + SbThreadSleep(kWatchdogSleepDuration); + ASSERT_EQ(watchdog_->GetWatchdogViolations(), ""); +} + TEST_F(WatchdogTest, KillSwitchShouldPreventViolations) { TearDown(); watchdog_ = new watchdog::Watchdog(); @@ -502,14 +587,13 @@ TEST_F(WatchdogTest, GetViolationClientNames) { SbThreadSleep(kWatchdogSleepDuration); ASSERT_TRUE(watchdog_->Unregister("test-name-1")); ASSERT_TRUE(watchdog_->Unregister("test-name-2")); + std::vector names = watchdog_->GetWatchdogViolationClientNames(); ASSERT_EQ(names.size(), 2); - std::set expected_names = {"test-name-1", "test-name-2"}; - for (std::vector::const_iterator it = names.begin(); - it != names.end(); ++it) { - const std::string name = *it; - ASSERT_TRUE((expected_names.find(name) != expected_names.end())); - } + ASSERT_TRUE(std::find(names.begin(), names.end(), "test-name-1") != + names.end()); + ASSERT_TRUE(std::find(names.begin(), names.end(), "test-name-2") != + names.end()); watchdog_->GetWatchdogViolations(); names = watchdog_->GetWatchdogViolationClientNames(); ASSERT_EQ(names.size(), 0);