shill: cellular: monitor ModemManager Pco property updates

ModemManager has introduced a new 'Pco' property in the
org.freedesktop.ModemManager.Modem.Modem3gpp interface. This CL updates
CellularCapabilityUniversal to monitor updates of the Pco property.

BUG=b:112664666
TEST=Run unit tests.

Change-Id: I01336f3090877adcbf9e71b69ffe1e13920b368f
Reviewed-on: https://chromium-review.googlesource.com/1189430
Commit-Ready: Ben Chan <benchan@chromium.org>
Tested-by: Ben Chan <benchan@chromium.org>
Reviewed-by: Brian Norris <briannorris@chromium.org>
diff --git a/cellular/cellular_capability_universal.cc b/cellular/cellular_capability_universal.cc
index 48f27e6..bec7014 100644
--- a/cellular/cellular_capability_universal.cc
+++ b/cellular/cellular_capability_universal.cc
@@ -21,6 +21,7 @@
 
 #include <base/bind.h>
 #include <base/stl_util.h>
+#include <base/strings/string_number_conversions.h>
 #include <base/strings/string_util.h>
 #include <chromeos/dbus/service_constants.h>
 #include <ModemManager/ModemManager.h>
@@ -30,6 +31,7 @@
 
 #include "shill/adaptor_interfaces.h"
 #include "shill/cellular/cellular_bearer.h"
+#include "shill/cellular/cellular_pco.h"
 #include "shill/cellular/cellular_service.h"
 #include "shill/cellular/mobile_operator_info.h"
 #include "shill/control_interface.h"
@@ -1597,6 +1599,11 @@
   if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS))
     OnFacilityLocksChanged(
         properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS));
+
+  if (properties.Contains(MM_MODEM_MODEM3GPP_PROPERTY_PCO)) {
+    OnPcoChanged(
+        properties.Get(MM_MODEM_MODEM3GPP_PROPERTY_PCO).Get<PcoList>());
+  }
 }
 
 void CellularCapabilityUniversal::On3gppRegistrationChanged(
@@ -1713,6 +1720,25 @@
   }
 }
 
+void CellularCapabilityUniversal::OnPcoChanged(const PcoList& pco_list) {
+  SLOG(this, 3) << __func__;
+
+  for (const auto& pco_info : pco_list) {
+    uint32_t session_id = std::get<0>(pco_info);
+    bool is_complete = std::get<1>(pco_info);
+    vector<uint8_t> data = std::get<2>(pco_info);
+
+    SLOG(this, 3) << "PCO: session-id=" << session_id
+                  << ", complete=" << is_complete
+                  << ", data=" << base::HexEncode(data.data(), data.size())
+                  << "";
+
+    std::unique_ptr<CellularPco> pco = CellularPco::CreateFromRawData(data);
+    if (!pco)
+      LOG(WARNING) << "Failed to parse PCO (session-id " << session_id << ")";
+  }
+}
+
 void CellularCapabilityUniversal::OnSimPropertiesChanged(
     const KeyValueStore& props,
     const vector<string>& /* invalidated_properties */) {
diff --git a/cellular/cellular_capability_universal.h b/cellular/cellular_capability_universal.h
index 20a59f3..9346c7a 100644
--- a/cellular/cellular_capability_universal.h
+++ b/cellular/cellular_capability_universal.h
@@ -55,6 +55,7 @@
   using SignalQuality = std::tuple<uint32_t, bool>;
   using ModesData = std::tuple<uint32_t, uint32_t>;
   using SupportedModes = std::vector<ModesData>;
+  using PcoList = std::vector<std::tuple<uint32_t, bool, std::vector<uint8_t>>>;
 
   // Constants used in connect method call.  Make available to test matchers.
   // TODO(jglasgow): Generate from modem manager into
@@ -337,6 +338,7 @@
                                     const std::string& updated_operator_name);
   void OnSubscriptionStateChanged(SubscriptionState updated_subscription_state);
   void OnFacilityLocksChanged(uint32_t locks);
+  void OnPcoChanged(const PcoList& pco_list);
 
   // SIM property change handlers
   // TODO(armansito): Put these methods in a 3GPP-only subclass.