shill: Implement a basic DiagnosticsReporter.
Currently the reporter is disabled. When enabled, it will trigger a
crash to upload diagnostics when its Report method is invoked. The
upload mimics the update_engine implementation.
BUG=chromium-os:35948
TEST=unit tests, gmerged shill, ensured connectivity
Change-Id: I0353e7d694dc3bc1b5b24d27856c3b9aeda43232
Reviewed-on: https://gerrit.chromium.org/gerrit/37525
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
diff --git a/Makefile b/Makefile
index 6e3ee18..3d6198a 100644
--- a/Makefile
+++ b/Makefile
@@ -178,6 +178,7 @@
dhcp_config.o \
dhcp_provider.o \
dhcpcd_proxy.o \
+ diagnostics_reporter.o \
dns_client.o \
endpoint.o \
ephemeral_profile.o \
@@ -308,6 +309,7 @@
device_unittest.o \
dhcp_config_unittest.o \
dhcp_provider_unittest.o \
+ diagnostics_reporter_unittest.o \
dns_client_unittest.o \
error_unittest.o \
ethernet_service_unittest.o \
diff --git a/diagnostics_reporter.cc b/diagnostics_reporter.cc
new file mode 100644
index 0000000..2c09ad0
--- /dev/null
+++ b/diagnostics_reporter.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/diagnostics_reporter.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <base/bind.h>
+
+#include "shill/event_dispatcher.h"
+
+using base::Bind;
+
+namespace shill {
+
+namespace {
+
+base::LazyInstance<DiagnosticsReporter> g_reporter = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+DiagnosticsReporter::DiagnosticsReporter()
+ : dispatcher_(NULL),
+ weak_ptr_factory_(this) {}
+
+DiagnosticsReporter::~DiagnosticsReporter() {}
+
+// static
+DiagnosticsReporter *DiagnosticsReporter::GetInstance() {
+ return g_reporter.Pointer();
+}
+
+void DiagnosticsReporter::Init(EventDispatcher *dispatcher) {
+ dispatcher_ = dispatcher;
+}
+
+void DiagnosticsReporter::Report() {
+ // Trigger the crash from the main event loop to try to ensure minimal and
+ // consistent stack trace. TODO(petkov): Look into invoking crash_reporter
+ // directly without actually triggering a crash.
+ dispatcher_->PostTask(Bind(&DiagnosticsReporter::TriggerCrash,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+bool DiagnosticsReporter::IsReportingEnabled() {
+ // TODO(petkov): Implement this when there's a way to control reporting
+ // through policy. crosbug.com/35946.
+ return false;
+}
+
+void DiagnosticsReporter::TriggerCrash() {
+ if (!IsReportingEnabled()) {
+ return;
+ }
+ pid_t pid = fork();
+ if (pid < 0) {
+ PLOG(ERROR) << "fork() failed.";
+ NOTREACHED();
+ return;
+ }
+ if (pid == 0) {
+ // Crash the child.
+ abort();
+ }
+ // The parent waits for the child to terminate.
+ pid_t result = waitpid(pid, NULL, 0);
+ PLOG_IF(ERROR, result < 0) << "waitpid() failed.";
+}
+
+} // namespace shill
diff --git a/diagnostics_reporter.h b/diagnostics_reporter.h
new file mode 100644
index 0000000..94ec9d8
--- /dev/null
+++ b/diagnostics_reporter.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_DIAGNOSTICS_REPORTER_H_
+#define SHILL_DIAGNOSTICS_REPORTER_H_
+
+#include <base/lazy_instance.h>
+#include <base/memory/weak_ptr.h>
+
+namespace shill {
+
+class EventDispatcher;
+
+class DiagnosticsReporter {
+ public:
+ virtual ~DiagnosticsReporter();
+
+ // This is a singleton -- use DiagnosticsReporter::GetInstance()->Foo()
+ static DiagnosticsReporter *GetInstance();
+
+ void Init(EventDispatcher *dispatcher);
+
+ void Report();
+
+ protected:
+ DiagnosticsReporter();
+
+ virtual bool IsReportingEnabled();
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<DiagnosticsReporter>;
+ friend class DiagnosticsReporterTest;
+
+ void TriggerCrash();
+
+ EventDispatcher *dispatcher_;
+ base::WeakPtrFactory<DiagnosticsReporter> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiagnosticsReporter);
+};
+
+} // namespace shill
+
+#endif // SHILL_DIAGNOSTICS_REPORTER_H_
diff --git a/diagnostics_reporter_unittest.cc b/diagnostics_reporter_unittest.cc
new file mode 100644
index 0000000..3445571
--- /dev/null
+++ b/diagnostics_reporter_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/diagnostics_reporter.h"
+
+#include <base/message_loop.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "shill/event_dispatcher.h"
+
+using testing::Return;
+
+namespace shill {
+
+class DiagnosticsReporterTest : public testing::Test {
+ public:
+ DiagnosticsReporterTest() {}
+
+ protected:
+ bool IsReportingEnabled() {
+ return DiagnosticsReporter::GetInstance()->IsReportingEnabled();
+ }
+};
+
+namespace {
+
+class ReporterUnderTest : public DiagnosticsReporter {
+ public:
+ ReporterUnderTest() {}
+
+ MOCK_METHOD0(IsReportingEnabled, bool());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ReporterUnderTest);
+};
+
+} // namespace
+
+TEST_F(DiagnosticsReporterTest, Report) {
+ // The test is pretty basic but covers the main flow and ensures that the main
+ // process doesn't crash.
+ ReporterUnderTest reporter;
+ EXPECT_CALL(reporter, IsReportingEnabled())
+ .WillOnce(Return(false))
+ .WillOnce(Return(true));
+ EventDispatcher dispatcher;
+ reporter.Init(&dispatcher);
+ reporter.Report();
+ reporter.Report();
+ dispatcher.PostTask(MessageLoop::QuitClosure());
+ dispatcher.DispatchForever();
+}
+
+TEST_F(DiagnosticsReporterTest, IsReportingEnabled) {
+ EXPECT_FALSE(IsReportingEnabled());
+}
+
+} // namespace shill
diff --git a/shill_daemon.cc b/shill_daemon.cc
index be82903..b8a09ae 100644
--- a/shill_daemon.cc
+++ b/shill_daemon.cc
@@ -15,6 +15,7 @@
#include "shill/callback80211_metrics.h"
#include "shill/config80211.h"
#include "shill/dhcp_provider.h"
+#include "shill/diagnostics_reporter.h"
#include "shill/error.h"
#include "shill/logging.h"
#include "shill/nss.h"
@@ -99,6 +100,7 @@
rtnl_handler_->Start(&dispatcher_, &sockets_);
routing_table_->Start();
dhcp_provider_->Init(control_, &dispatcher_, &glib_);
+ DiagnosticsReporter::GetInstance()->Init(&dispatcher_);
if (config80211_) {
config80211_->Init(&dispatcher_);