metricsd: Expose the metrics status through weave.

metrics_daemon will export _metrics._AnalyticsReportingState containing
"enabled"/"disabled" depending on the current state and two weave
commands (_metrics._{enable,disable}AnalyticsReporting) to update it.

BUG: 24386281
TEST: manual. Enabled and disabled metrics reporting.
  `metrics_client -c` reports the correct answer.

Change-Id: Ic4a5ffc1e9f9cbc0b47ee34d3af83584d95da155
diff --git a/Android.mk b/Android.mk
index 9fd27f5..afb45da 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,44 +25,30 @@
 metrics_client_sources := \
   metrics_client.cc
 
-metrics_daemon_sources := \
+metrics_daemon_common := \
   collectors/averaged_statistics_collector.cc \
   collectors/disk_usage_collector.cc \
   metrics_daemon.cc \
-  metrics_daemon_main.cc \
   persistent_integer.cc \
-  uploader/metrics_hashes.cc \
-  uploader/metrics_log_base.cc \
-  uploader/metrics_log.cc \
-  uploader/sender_http.cc \
-  uploader/system_profile_cache.cc \
-  uploader/upload_service.cc \
-  serialization/metric_sample.cc \
-  serialization/serialization_utils.cc
-
-metrics_tests_sources := \
-  collectors/averaged_statistics_collector.cc \
-  collectors/averaged_statistics_collector_test.cc \
-  collectors/disk_usage_collector.cc \
-  metrics_daemon.cc \
-  metrics_daemon_test.cc \
-  metrics_library_test.cc \
-  persistent_integer.cc \
-  persistent_integer_test.cc \
   serialization/metric_sample.cc \
   serialization/serialization_utils.cc \
-  serialization/serialization_utils_unittest.cc \
-  timer.cc \
-  timer_test.cc \
   uploader/metrics_hashes.cc \
-  uploader/metrics_hashes_unittest.cc \
   uploader/metrics_log_base.cc \
-  uploader/metrics_log_base_unittest.cc \
   uploader/metrics_log.cc \
-  uploader/mock/sender_mock.cc \
   uploader/sender_http.cc \
   uploader/system_profile_cache.cc \
   uploader/upload_service.cc \
+
+metrics_tests_sources := \
+  collectors/averaged_statistics_collector_test.cc \
+  metrics_daemon_test.cc \
+  metrics_library_test.cc \
+  persistent_integer_test.cc \
+  serialization/serialization_utils_unittest.cc \
+  timer_test.cc \
+  uploader/metrics_hashes_unittest.cc \
+  uploader/metrics_log_base_unittest.cc \
+  uploader/mock/sender_mock.cc \
   uploader/upload_service_test.cc \
 
 metrics_CFLAGS := -Wall \
@@ -78,7 +64,17 @@
   -fvisibility=default
 metrics_includes := external/gtest/include \
   $(LOCAL_PATH)/include
-metrics_shared_libraries := libchrome libchromeos
+libmetrics_shared_libraries := libchrome libchromeos
+metrics_daemon_shared_libraries := $(libmetrics_shared_libraries) \
+  libchrome-dbus \
+  libchromeos-http \
+  libchromeos-dbus \
+  libcutils \
+  libdbus \
+  libmetrics \
+  libprotobuf-cpp-lite \
+  librootdev \
+  libweaved-client \
 
 # Shared library for metrics.
 # ========================================================
@@ -91,7 +87,7 @@
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
 LOCAL_RTTI_FLAG := -frtti
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries)
+LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries)
 LOCAL_SRC_FILES := $(libmetrics_sources)
 include $(BUILD_SHARED_LIBRARY)
 
@@ -104,7 +100,7 @@
 LOCAL_CLANG := true
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
-LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries) \
+LOCAL_SHARED_LIBRARIES := $(libmetrics_shared_libraries) \
   libmetrics
 LOCAL_SRC_FILES := $(metrics_client_sources)
 include $(BUILD_EXECUTABLE)
@@ -130,18 +126,15 @@
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
 LOCAL_INIT_RC := metrics_daemon.rc
-LOCAL_RTTI_FLAG := -frtti
-LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries) \
-  libmetrics \
-  libprotobuf-cpp-lite \
-  libchromeos-http \
-  libchromeos-dbus \
-  libcutils \
-  libdbus \
-  librootdev
+LOCAL_REQUIRED_MODULES := \
+  metrics.json \
+  metrics.schema.json \
 
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := $(metrics_daemon_shared_libraries)
 LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(metrics_daemon_sources)
+LOCAL_SRC_FILES := $(metrics_daemon_common) \
+  metrics_daemon_main.cc
 LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
 include $(BUILD_EXECUTABLE)
 
@@ -154,15 +147,24 @@
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS) -Wno-sign-compare
 LOCAL_RTTI_FLAG := -frtti
-LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries) \
-  libmetrics \
-  libprotobuf-cpp-lite \
-  libchromeos-http \
-  libchromeos-dbus \
-  libcutils \
-  libdbus \
-
-LOCAL_SRC_FILES := $(metrics_tests_sources)
+LOCAL_SHARED_LIBRARIES := $(metrics_daemon_shared_libraries)
+LOCAL_SRC_FILES := $(metrics_tests_sources) $(metrics_daemon_common)
 LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metrics_daemon_protos
 
 include $(BUILD_NATIVE_TEST)
+
+# Weave schema files
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := metrics.json
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/commands
+LOCAL_SRC_FILES := etc/weaved/commands/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := metrics.schema.json
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/states
+LOCAL_SRC_FILES := etc/weaved/states/$(LOCAL_MODULE)
+include $(BUILD_PREBUILT)
diff --git a/etc/weaved/commands/metrics.json b/etc/weaved/commands/metrics.json
new file mode 100644
index 0000000..b7f32d5
--- /dev/null
+++ b/etc/weaved/commands/metrics.json
@@ -0,0 +1,10 @@
+{
+  "_metrics": {
+    "_enableAnalyticsReporting": {
+      "minimalRole": "manager"
+    },
+    "_disableAnalyticsReporting": {
+      "minimalRole": "manager"
+    }
+  }
+}
diff --git a/etc/weaved/states/metrics.schema.json b/etc/weaved/states/metrics.schema.json
new file mode 100644
index 0000000..130ac46
--- /dev/null
+++ b/etc/weaved/states/metrics.schema.json
@@ -0,0 +1,8 @@
+{
+  "_metrics": {
+    "_AnalyticsReportingState": {
+      "enum": ["enabled", "disabled"],
+      "default": "disabled"
+    }
+  }
+}
diff --git a/metrics_daemon.cc b/metrics_daemon.cc
index 9eb6802..5b80b05 100644
--- a/metrics_daemon.cc
+++ b/metrics_daemon.cc
@@ -41,6 +41,8 @@
 using base::TimeDelta;
 using base::TimeTicks;
 using chromeos_metrics::PersistentInteger;
+using com::android::Weave::CommandProxy;
+using com::android::Weave::ManagerProxy;
 using std::map;
 using std::string;
 using std::vector;
@@ -280,6 +282,12 @@
       LOG(ERROR) << "DBus isn't connected.";
       return EX_UNAVAILABLE;
     }
+
+    weaved_object_mgr_.reset(new com::android::Weave::ObjectManagerProxy{bus_});
+    weaved_object_mgr_->SetCommandAddedCallback(
+        base::Bind(&MetricsDaemon::OnWeaveCommand, base::Unretained(this)));
+    weaved_object_mgr_->SetManagerAddedCallback(
+        base::Bind(&MetricsDaemon::UpdateWeaveState, base::Unretained(this)));
   }
 
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -317,6 +325,60 @@
   chromeos::DBusDaemon::OnShutdown(return_code);
 }
 
+void MetricsDaemon::OnWeaveCommand(CommandProxy* command) {
+  if (command->category() != "metrics" || command->status() != "queued") {
+    return;
+  }
+
+  VLOG(1) << "received weave command: " << command->name();
+  if (command->name() == "_metrics._enableAnalyticsReporting") {
+    OnEnableMetrics(command);
+  } else if (command->name() == "_metrics._disableAnalyticsReporting") {
+    OnDisableMetrics(command);
+  }
+}
+
+void MetricsDaemon::OnEnableMetrics(CommandProxy* command) {
+  if (base::WriteFile(metrics_directory_.Append(metrics::kConsentFileName),
+                      "", 0) != 0) {
+    PLOG(ERROR) << "Could not create the consent file.";
+    command->Abort(nullptr);
+    return;
+  }
+
+  NotifyStateChanged();
+  command->Done(nullptr);
+}
+
+void MetricsDaemon::OnDisableMetrics(CommandProxy* command) {
+  if (!base::DeleteFile(metrics_directory_.Append(metrics::kConsentFileName),
+                        false)) {
+    PLOG(ERROR) << "Cound not delete the consent file.";
+    command->Abort(nullptr);
+    return;
+  }
+
+  NotifyStateChanged();
+  command->Done(nullptr);
+}
+
+void MetricsDaemon::NotifyStateChanged() {
+  ManagerProxy* manager = weaved_object_mgr_->GetManagerProxy();
+  if (manager)
+    UpdateWeaveState(manager);
+}
+
+void MetricsDaemon::UpdateWeaveState(ManagerProxy* manager) {
+  chromeos::VariantDictionary state_change{
+    { "_metrics._AnalyticsReportingState",
+      metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled" }
+  };
+
+  if (!manager->UpdateState(state_change, nullptr)) {
+    LOG(ERROR) << "failed to update weave's state";
+  }
+}
+
 // static
 DBusHandlerResult MetricsDaemon::MessageFilter(DBusConnection* connection,
                                                DBusMessage* message,
diff --git a/metrics_daemon.h b/metrics_daemon.h
index 612dfe2..0a8f6a5 100644
--- a/metrics_daemon.h
+++ b/metrics_daemon.h
@@ -26,6 +26,7 @@
 #include <base/files/file_path.h>
 #include <base/memory/scoped_ptr.h>
 #include <base/time/time.h>
+#include <buffet/dbus-proxies.h>
 #include <chromeos/daemons/dbus_daemon.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
@@ -121,6 +122,21 @@
                                          DBusMessage* message,
                                          void* user_data);
 
+  // Callback for Weave commands.
+  void OnWeaveCommand(com::android::Weave::CommandProxy* command);
+
+  // Enables metrics reporting.
+  void OnEnableMetrics(com::android::Weave::CommandProxy* command);
+
+  // Disables metrics reporting.
+  void OnDisableMetrics(com::android::Weave::CommandProxy* command);
+
+  // Updates the weave device state.
+  void UpdateWeaveState(com::android::Weave::ManagerProxy* manager);
+
+  // Tells Weave that the state has changed.
+  void NotifyStateChanged();
+
   // Updates the active use time and logs time between user-space
   // process crashes.
   void ProcessUserCrash();
@@ -301,6 +317,7 @@
   std::string server_;
 
   scoped_ptr<UploadService> upload_service_;
+  scoped_ptr<com::android::Weave::ObjectManagerProxy> weaved_object_mgr_;
 };
 
 #endif  // METRICS_METRICS_DAEMON_H_