New DBus methods to enable/disable P2P update sharing.

This patch adds two new methods to enable/disable sharing updates
over P2P in the local network. This allows a crosh command to set
and get this flag to enable or disable this feature.

BUG=chromium:260441
TEST=Manual test. See below.

Manual test procedure.
1. Enable P2P:
update_engine_client -p2p_update yes -show_p2p_update

[0829/141039:INFO:update_engine_client.cc(433)] Current update using P2P setting: ENABLED
[0829/141039:INFO:update_engine_client.cc(500)] Done.

2. Start the p2p server (this will be done by the p2p_manager
   as part of the update_engine procedure).

3. Run an update check
update_engine_client -check_for_update

The /var/log/update_engine.log shows the following line confirming
p2p is enabled.
[0829/141317:INFO:p2p_manager.cc(194)] Returning value 1 for whether p2p is enabled.

4. Disable p2p and verify the p2p server is not running.
update_engine_client -p2p_update no -show_p2p_update

[0829/141039:INFO:update_engine_client.cc(433)] Current update using P2P setting: ENABLED
[0829/141039:INFO:update_engine_client.cc(500)] Done.

5. Verify p2p server is not running (ps aux | grep p2p doesn't show
p2p-server)

Change-Id: I3215e2961be440c491f669d4c580bbf87f7fec25
Reviewed-on: https://chromium-review.googlesource.com/62505
Reviewed-by: David Zeuthen <zeuthen@chromium.org>
Commit-Queue: Alejandro Deymo <deymo@chromium.org>
Tested-by: Alejandro Deymo <deymo@chromium.org>
diff --git a/UpdateEngine.conf b/UpdateEngine.conf
index 5c259b4..a89bcac 100644
--- a/UpdateEngine.conf
+++ b/UpdateEngine.conf
@@ -36,6 +36,12 @@
            send_member="GetChannel"/>
     <allow send_destination="org.chromium.UpdateEngine"
            send_interface="org.chromium.UpdateEngineInterface"
+           send_member="SetP2PUpdatePermission"/>
+    <allow send_destination="org.chromium.UpdateEngine"
+           send_interface="org.chromium.UpdateEngineInterface"
+           send_member="GetP2PUpdatePermission"/>
+    <allow send_destination="org.chromium.UpdateEngine"
+           send_interface="org.chromium.UpdateEngineInterface"
            send_member="SetUpdateOverCellularPermission"/>
     <allow send_destination="org.chromium.UpdateEngine"
            send_interface="org.chromium.UpdateEngineInterface"
diff --git a/dbus_service.cc b/dbus_service.cc
index cf6bbae..65023e9 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -13,6 +13,7 @@
 #include "update_engine/connection_manager.h"
 #include "update_engine/marshal.glibmarshal.h"
 #include "update_engine/omaha_request_params.h"
+#include "update_engine/p2p_manager.h"
 #include "update_engine/update_attempter.h"
 #include "update_engine/prefs.h"
 #include "update_engine/utils.h"
@@ -207,6 +208,54 @@
   return TRUE;
 }
 
+gboolean update_engine_service_set_p2p_update_permission(
+    UpdateEngineService* self,
+    gboolean enabled,
+    GError **error) {
+  chromeos_update_engine::PrefsInterface* prefs = self->system_state_->prefs();
+  chromeos_update_engine::P2PManager* p2p_manager =
+      self->system_state_->p2p_manager();
+
+  bool p2p_was_enabled = p2p_manager && p2p_manager->IsP2PEnabled();
+
+  if (!prefs->SetBoolean(chromeos_update_engine::kPrefsP2PEnabled, enabled)) {
+    LOG(ERROR) << "Error setting the update over cellular to "
+               << (enabled ? "true" : "false");
+    *error = NULL;
+    return FALSE;
+  }
+
+  // If P2P is being effectively disabled (IsP2PEnabled() reports the change)
+  // then we need to shutdown the service.
+  if (p2p_was_enabled && !p2p_manager->IsP2PEnabled())
+    p2p_manager->EnsureP2PNotRunning();
+
+  return TRUE;
+}
+
+gboolean update_engine_service_get_p2p_update_permission(
+    UpdateEngineService* self,
+    gboolean* enabled,
+    GError **error) {
+  chromeos_update_engine::PrefsInterface* prefs = self->system_state_->prefs();
+
+  // The default for not present setting is false.
+  if (!prefs->Exists(chromeos_update_engine::kPrefsP2PEnabled)) {
+    *enabled = false;
+    return TRUE;
+  }
+
+  bool p2p_pref = false;
+  if (!prefs->GetBoolean(chromeos_update_engine::kPrefsP2PEnabled, &p2p_pref)) {
+    LOG(ERROR) << "Error getting the P2PEnabled setting.";
+    *error = NULL;
+    return FALSE;
+  }
+
+  *enabled = p2p_pref;
+  return TRUE;
+}
+
 gboolean update_engine_service_set_update_over_cellular_permission(
     UpdateEngineService* self,
     bool allowed,
diff --git a/dbus_service.h b/dbus_service.h
index 8349622..27210f6 100644
--- a/dbus_service.h
+++ b/dbus_service.h
@@ -91,6 +91,20 @@
                                            gchar** channel,
                                            GError **error);
 
+// Enables or disables the sharing and consuming updates over P2P feature
+// according to the |enabled| argument passed.
+gboolean update_engine_service_set_p2p_update_permission(
+    UpdateEngineService* self,
+    gboolean enabled,
+    GError **error);
+
+// Returns in |enabled| the current value for the P2P enabled setting. This
+// involves both sharing and consuming updates over P2P.
+gboolean update_engine_service_get_p2p_update_permission(
+    UpdateEngineService* self,
+    gboolean* enabled,
+    GError **error);
+
 // If there's no device policy installed, sets the update over cellular networks
 // permission to the |allowed| value. Otherwise, this method returns with an
 // error since this setting is overridden by the applied policy.
diff --git a/update_engine.xml b/update_engine.xml
index eada639..0d9f895 100644
--- a/update_engine.xml
+++ b/update_engine.xml
@@ -33,6 +33,16 @@
       <arg type="b" name="get_current_channel" />
       <arg type="s" name="channel" direction="out" />
     </method>
+    <method name="SetP2PUpdatePermission">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol"
+        value="update_engine_service_set_p2p_update_permission"/>
+      <arg type="b" name="enabled" />
+    </method>
+    <method name="GetP2PUpdatePermission">
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol"
+        value="update_engine_service_get_p2p_update_permission"/>
+      <arg type="b" name="enabled" direction="out" />
+    </method>
     <method name="SetUpdateOverCellularPermission">
       <arg type="b" name="allowed" />
     </method>
diff --git a/update_engine_client.cc b/update_engine_client.cc
index e959534..d904d71 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -45,6 +45,11 @@
 DEFINE_string(update_over_cellular, "",
               "Enables (\"yes\") or disables (\"no\") the updates over "
               "cellular networks.");
+DEFINE_bool(show_p2p_update, false,
+            "Show the current setting for peer-to-peer update sharing.");
+DEFINE_string(p2p_update, "",
+              "Enables (\"yes\") or disables (\"no\") the peer-to-peer update "
+              "sharing.");
 
 namespace {
 
@@ -266,7 +271,7 @@
   return output;
 }
 
-bool SetUpdateOverCellularPermission(gboolean allowed) {
+void SetUpdateOverCellularPermission(gboolean allowed) {
   DBusGProxy* proxy;
   GError* error = NULL;
 
@@ -279,7 +284,6 @@
           &error);
   CHECK_EQ(rc, true) << "Error setting the update over cellular setting: "
                      << GetAndFreeGError(&error);
-  return true;
 }
 
 bool GetUpdateOverCellularPermission() {
@@ -299,6 +303,38 @@
   return allowed;
 }
 
+void SetP2PUpdatePermission(gboolean enabled) {
+  DBusGProxy* proxy;
+  GError* error = NULL;
+
+  CHECK(GetProxy(&proxy));
+
+  gboolean rc =
+      org_chromium_UpdateEngineInterface_set_p2_pupdate_permission(
+          proxy,
+          enabled,
+          &error);
+  CHECK_EQ(rc, true) << "Error setting the peer-to-peer update setting: "
+                     << GetAndFreeGError(&error);
+}
+
+bool GetP2PUpdatePermission() {
+  DBusGProxy* proxy;
+  GError* error = NULL;
+
+  CHECK(GetProxy(&proxy));
+
+  gboolean enabled;
+  gboolean rc =
+      org_chromium_UpdateEngineInterface_get_p2_pupdate_permission(
+          proxy,
+          &enabled,
+          &error);
+  CHECK_EQ(rc, true) << "Error getting the peer-to-peer update setting: "
+                     << GetAndFreeGError(&error);
+  return enabled;
+}
+
 static gboolean CompleteUpdateSource(gpointer data) {
   string current_op;
   if (!GetStatus(&current_op) || current_op == "UPDATE_STATUS_IDLE") {
@@ -378,6 +414,24 @@
     return 1;
   }
 
+  // Change the P2P enabled setting.
+  if (!FLAGS_p2p_update.empty()) {
+    gboolean enabled = FLAGS_p2p_update == "yes";
+    if (!enabled && FLAGS_p2p_update != "no") {
+      LOG(ERROR) << "Unknown option: \"" << FLAGS_p2p_update
+                 << "\". Please specify \"yes\" or \"no\".";
+    } else {
+      SetP2PUpdatePermission(enabled);
+    }
+  }
+
+  // Show the current P2P enabled setting.
+  if (FLAGS_show_p2p_update) {
+    bool enabled = GetP2PUpdatePermission();
+    LOG(INFO) << "Current update using P2P setting: "
+              << (enabled ? "ENABLED" : "DISABLED");
+  }
+
   // First, update the target channel if requested.
   if (!FLAGS_channel.empty())
     SetTargetChannel(FLAGS_channel, FLAGS_powerwash);