hermes: Implement method to install pending profiles

A call to RequestPendingProfiles on dbus gets pending profiles from the
SMDS. This CL implements the method that installs one of those pending
profiles.

BUG=b:169946381
TEST=modem esim request_pending_profiles ${EUICC} ${ROOT_SMDS};modem esim install_pending_profile ${EUICC} ${ICCID}

Change-Id: If6b55052ed9f105c6343d57df75a11b3df16561e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2567647
Tested-by: Pavan Holla <pholla@google.com>
Reviewed-by: Srikanth Oruganti <srikanthkumar@google.com>
Reviewed-by: Eric Caruso <ejcaruso@chromium.org>
Commit-Queue: Pavan Holla <pholla@google.com>
diff --git a/hermes/dbus_bindings/org.chromium.Hermes.Euicc.xml b/hermes/dbus_bindings/org.chromium.Hermes.Euicc.xml
index e3c0cfd..68ad11c 100644
--- a/hermes/dbus_bindings/org.chromium.Hermes.Euicc.xml
+++ b/hermes/dbus_bindings/org.chromium.Hermes.Euicc.xml
@@ -44,6 +44,12 @@
           Confirmation code of the profile to install, or "" if none.
         </tp:docstring>
       </arg>
+      <arg name="profile" type="o" direction="out">
+        <tp:docstring>
+          Profile object representing the newly-installed profile.
+          Same as the input "pending_profile"
+        </tp:docstring>
+      </arg>
     </method>
     <method name="UninstallProfile">
       <tp:docstring>
diff --git a/hermes/euicc.cc b/hermes/euicc.cc
index afaf7f4..e33ecea 100644
--- a/hermes/euicc.cc
+++ b/hermes/euicc.cc
@@ -46,6 +46,7 @@
                         lpa::proto::ProfileInfo& info, int error) mutable {
     OnProfileInstalled(info, error, std::move(result_callback));
   };
+  context_->modem_control()->StoreAndSetActiveSlot(physical_slot_);
   if (activation_code.empty()) {
     context_->lpa()->GetDefaultProfileFromSmdp("", context_->executor(),
                                                std::move(profile_cb));
@@ -56,11 +57,31 @@
   options.enable_profile = false;
   options.allow_policy_rules = false;
   options.confirmation_code = confirmation_code;
-  context_->modem_control()->StoreAndSetActiveSlot(physical_slot_);
   context_->lpa()->DownloadProfile(activation_code, std::move(options),
                                    context_->executor(), std::move(profile_cb));
 }
 
+void Euicc::InstallPendingProfile(
+    const dbus::ObjectPath& profile_path,
+    const std::string& confirmation_code,
+    ResultCallback<dbus::ObjectPath> result_callback) {
+  auto iter = find_if(pending_profiles_.begin(), pending_profiles_.end(),
+                      [&profile_path](const std::unique_ptr<Profile>& profile) {
+                        return profile->object_path() == profile_path;
+                      });
+
+  if (iter == pending_profiles_.end()) {
+    result_callback.Error(brillo::Error::Create(
+        FROM_HERE, brillo::errors::dbus::kDomain, kErrorInvalidParameter,
+        "Could not find Profile " + profile_path.value()));
+    return;
+  }
+
+  std::string activation_code = iter->get()->GetActivationCode();
+  InstallProfileFromActivationCode(activation_code, confirmation_code,
+                                   std::move(result_callback));
+}
+
 void Euicc::UninstallProfile(const dbus::ObjectPath& profile_path,
                              ResultCallback<> result_callback) {
   const Profile* matching_profile = nullptr;
@@ -112,7 +133,22 @@
     return;
   }
 
-  auto profile = Profile::Create(profile_info, physical_slot_);
+  auto iter = find_if(pending_profiles_.begin(), pending_profiles_.end(),
+                      [&profile_info](const std::unique_ptr<Profile>& profile) {
+                        return profile->GetIccid() == profile_info.iccid();
+                      });
+
+  std::unique_ptr<Profile> profile;
+  if (iter != pending_profiles_.end()) {
+    // Remove the profile from pending_profiles_ so that it can become an
+    // installed profile
+    profile = std::move(*iter);
+    pending_profiles_.erase(iter);
+    UpdatePendingProfilesProperty();
+  } else {
+    profile = Profile::Create(profile_info, physical_slot_);
+  }
+
   if (!profile) {
     result_callback.Error(brillo::Error::Create(
         FROM_HERE, brillo::errors::dbus::kDomain, kErrorInternalLpaFailure,
diff --git a/hermes/euicc.h b/hermes/euicc.h
index 0aa608b..40c3ed8 100644
--- a/hermes/euicc.h
+++ b/hermes/euicc.h
@@ -39,6 +39,9 @@
   // Request the eUICC to provide all installed profiles.
   void RequestInstalledProfiles(ResultCallback<> result_callback);
 
+  void InstallPendingProfile(const dbus::ObjectPath& profile_path,
+                             const std::string& confirmation_code,
+                             ResultCallback<dbus::ObjectPath> result_callback);
   void RequestPendingProfiles(ResultCallback<> result_callback,
                               const std::string& root_smds);
 
diff --git a/hermes/euicc_dbus_adaptor.cc b/hermes/euicc_dbus_adaptor.cc
index ee0976c..ff83b6c 100644
--- a/hermes/euicc_dbus_adaptor.cc
+++ b/hermes/euicc_dbus_adaptor.cc
@@ -45,12 +45,12 @@
 }
 
 void EuiccDBusAdaptor::InstallPendingProfile(
-    std::unique_ptr<DBusResponse<>> response,
-    const dbus::ObjectPath& /*in_pending_profile*/,
-    const std::string& /*in_confirmation_code*/) {
-  response->ReplyWithError(
-      FROM_HERE, brillo::errors::dbus::kDomain, kErrorUnsupported,
-      "This method is not supported until crbug.com/1071470 is implemented");
+    std::unique_ptr<DBusResponse<dbus::ObjectPath>> response,
+    const dbus::ObjectPath& in_pending_profile,
+    const std::string& in_confirmation_code) {
+  ResultCallback<dbus::ObjectPath> result_callback(std::move(response));
+  euicc_->InstallPendingProfile(in_pending_profile, in_confirmation_code,
+                                std::move(result_callback));
 }
 
 void EuiccDBusAdaptor::UninstallProfile(
diff --git a/hermes/euicc_dbus_adaptor.h b/hermes/euicc_dbus_adaptor.h
index 4ab97e7..630766c 100644
--- a/hermes/euicc_dbus_adaptor.h
+++ b/hermes/euicc_dbus_adaptor.h
@@ -31,9 +31,10 @@
       std::unique_ptr<DBusResponse<dbus::ObjectPath>> response,
       const std::string& in_activation_code,
       const std::string& in_confirmation_code) override;
-  void InstallPendingProfile(std::unique_ptr<DBusResponse<>> response,
-                             const dbus::ObjectPath& in_pending_profile,
-                             const std::string& in_confirmation_code) override;
+  void InstallPendingProfile(
+      std::unique_ptr<DBusResponse<dbus::ObjectPath>> response,
+      const dbus::ObjectPath& in_pending_profile,
+      const std::string& in_confirmation_code) override;
   void UninstallProfile(std::unique_ptr<DBusResponse<>> response,
                         const dbus::ObjectPath& in_profile) override;
   // Update the PendingProfiles property.