Add support for PRL update after OMA-DM activation.

BUG=chrome-os-partner:18300
TEST=1. modem factory-reset
     2. modem get-prl  # Note current PRL version
     3. modem activate
     4. Wait until modem fully activated
     5. modem get-prl  # Verify new version

Change-Id: I52e371b5c8073a2aa212c8102df1741b182d36b5
Reviewed-on: https://gerrit.chromium.org/gerrit/50376
Reviewed-by: Ben Chan <benchan@chromium.org>
Tested-by: Thieu Le <thieule@chromium.org>
Commit-Queue: Thieu Le <thieule@chromium.org>
diff --git a/gobi_cdma_modem.cc b/gobi_cdma_modem.cc
index 5673ec5..af84b3d 100644
--- a/gobi_cdma_modem.cc
+++ b/gobi_cdma_modem.cc
@@ -4,8 +4,6 @@
 
 #include "gobi_cdma_modem.h"
 #include "gobi_modem_handler.h"
-#include <cromo/carrier.h>
-#include <mm/mm-modem.h>
 
 extern "C" {
 #include <fcntl.h>
@@ -13,8 +11,20 @@
 #include <sys/types.h>
 };
 
+#include <base/file_path.h>
+#include <base/file_util.h>
+#include <base/stringprintf.h>
+#include <cromo/carrier.h>
+#include <mm/mm-modem.h>
+
+using base::FilePath;
+using base::StringPrintf;
+using std::string;
 using utilities::DBusPropertyMap;
 
+// static
+static const char kExecPostActivationStepsCookieCrumbFormat[] =
+    "/tmp/cromo-modem-exec-post-activation-steps-%s";
 
 //======================================================================
 // Construct and destruct
@@ -33,6 +43,25 @@
 GobiCdmaModem::~GobiCdmaModem() {
 }
 
+void GobiCdmaModem::Init() {
+  GobiModem::Init();
+
+  DBus::Error error;
+  ScopedApiConnection connection(*this);
+  connection.ApiConnect(error);
+  if (error.is_set()) {
+    LOG(ERROR) << "Failed to connect to Gobi modem, "
+               << "skipping post activation steps";
+    return;
+  }
+  int activation_state = GobiCdmaModem::GetMmActivationState();
+  if (activation_state == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED &&
+      ShouldExecPostActivationSteps()) {
+    LOG(INFO) << "Executing post activation steps";
+    PerformPostActivationSteps();
+  }
+}
+
 void GobiCdmaModem::GetCdmaRegistrationState(ULONG* cdma_1x_state,
                                              ULONG* cdma_evdo_state,
                                              ULONG* roaming_state,
@@ -75,7 +104,11 @@
     LOG(ERROR) << "GetActivationState: " << rc;
     return -1;
   }
-  LOG(INFO) << "device activation state: " << device_activation_state;
+  LOG(INFO) << "Device activation state: " << device_activation_state;
+  if (activation_in_progress_ && !force_activated_status_) {
+    LOG(INFO) << "Device activation still in progress";
+    return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
+  }
   if (device_activation_state == 1) {
     return MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED;
   }
@@ -220,9 +253,10 @@
   LOG(INFO) << "OMDADMAlertCallback type " << type << " id " << id;
 }
 
-gboolean GobiCdmaModem::OmadmStateCallback(gpointer data) {
+gboolean GobiCdmaModem::OmadmStateDeviceConfigureCallback(gpointer data) {
   OmadmStateArgs* args = static_cast<OmadmStateArgs*>(data);
-  LOG(INFO) << "OMA-DM State Callback: " << args->session_state;
+  LOG(INFO) << "OMA-DM State Device Configure Callback: "
+            << args->session_state;
   GobiCdmaModem* modem = LookupCdmaModem(handler_, *args->path);
   bool activation_done = true;
   if (modem != NULL) {
@@ -230,9 +264,13 @@
       case gobi::kOmadmComplete:
         modem->SendActivationStateChanged(
             MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
+        // Activation completed successfully, the modem will reset.  Mark the
+        // modem to execute post activation steps when it's next seen.
+        modem->MarkForExecPostActivationStepsAfterReset();
         break;
       case gobi::kOmadmFailed:
-        LOG(INFO) << "OMA-DM failure reason: " << args->failure_reason;
+        LOG(INFO) << "OMA-DM device configuration failure reason: "
+                  << args->failure_reason;
         // fall through
       case gobi::kOmadmUpdateInformationUnavailable:
         modem->SendActivationStateChanged(
@@ -244,12 +282,46 @@
   }
 
   if (activation_done) {
+    modem->sdk_->SetOMADMStateCallback(NULL);
     modem->ActivationFinished();
   }
 
   return FALSE;
 }
 
+gboolean GobiCdmaModem::OmadmStateClientPrlUpdateCallback(gpointer data) {
+  OmadmStateArgs* args = static_cast<OmadmStateArgs*>(data);
+  LOG(INFO) << "OMA-DM State Client PRL Update Callback: "
+            << args->session_state;
+  GobiCdmaModem* modem = LookupCdmaModem(handler_, *args->path);
+  bool done = true;
+  switch (args->session_state) {
+    case gobi::kOmadmComplete:
+      LOG(INFO) << "OMA-DM client initiated PRL completed, "
+                << "information updated.";
+      break;
+    case gobi::kOmadmUpdateInformationUnavailable:
+      LOG(INFO) << "OMA-DM client initiated PRL completed, "
+                << "update information unavailable (PRL up-to-date).";
+      break;
+    case gobi::kOmadmFailed:
+      LOG(INFO) << "OMA-DM client initiated PRL update failure reason: "
+                << args->failure_reason;
+      break;
+    case gobi::kOmadmPrlDownloaded:
+      LOG(INFO) << "OMA-DM client initiated PRL completed, PRL downloaded.";
+      break;
+    default:
+      done = false;
+      break;
+  }
+  if (done) {
+    modem->sdk_->SetOMADMStateCallback(NULL);
+    modem->activation_in_progress_ = false;
+  }
+  return FALSE;
+}
+
 void GobiCdmaModem::SignalStrengthHandler(INT8 signal_strength,
                                           ULONG radio_interface) {
   unsigned long ss_percent = MapDbmToPercent(signal_strength);
@@ -273,7 +345,7 @@
   GobiModem::RegisterCallbacks();
   sdk_->SetOMADMAlertCallback(OMADMAlertCallback);
   sdk_->SetActivationStatusCallback(ActivationStatusCallbackTrampoline);
-  sdk_->SetOMADMStateCallback(OmadmStateCallbackTrampoline);
+  sdk_->SetOMADMStateCallback(NULL);
 }
 
 //======================================================================
@@ -497,16 +569,18 @@
 
 uint32_t GobiCdmaModem::ActivateOmadm() {
   ULONG rc;
-  LOG(INFO) << "Activating OMA-DM";
+  LOG(INFO) << "Activating OMA-DM device configure";
 
   rc = sdk_->OMADMSetPRLUpdateFeature(TRUE);
   if (rc != 0) {
-    LOG(ERROR) << "OMA-DM activation failed to enable PRL update: " << rc;
+    LOG(ERROR) << "OMA-DM device configure activation failed to enable PRL "
+               << "update: " << rc;
     return MM_MODEM_CDMA_ACTIVATION_ERROR_START_FAILED;
   }
+  sdk_->SetOMADMStateCallback(OmadmStateDeviceConfigureCallbackTrampoline);
   rc = sdk_->OMADMStartSession(gobi::kConfigure);
   if (rc != 0) {
-    LOG(ERROR) << "OMA-DM activation failed: " << rc;
+    LOG(ERROR) << "OMA-DM device configure activation failed: " << rc;
     return MM_MODEM_CDMA_ACTIVATION_ERROR_START_FAILED;
   }
   return MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR;
@@ -529,6 +603,29 @@
   activation_in_progress_ = false;
 }
 
+void GobiCdmaModem::PerformPostActivationSteps() {
+  activation_in_progress_ = true;
+  StartClientInitiatedPrlUpdate();
+}
+
+void GobiCdmaModem::StartClientInitiatedPrlUpdate() {
+  LOG(INFO) << "Activating OMA-DM client initiated PRL update";
+  sdk_->SetOMADMStateCallback(OmadmStateClientPrlUpdateCallbackTrampoline);
+  ULONG rc = sdk_->OMADMSetPRLUpdateFeature(TRUE);
+  if (rc != 0) {
+    LOG(ERROR) << "OMA-DM client initiated PRL update failed to enable PRL "
+               << "update: " << rc;
+    sdk_->SetOMADMStateCallback(NULL);
+    return;
+  }
+  rc = sdk_->OMADMStartSession(gobi::kPrlUpdate);
+  if (rc != 0) {
+    LOG(ERROR) << "OMA-DM client initiated PRL update failed to start: "
+               << rc;
+    sdk_->SetOMADMStateCallback(NULL);
+  }
+}
+
 std::string GobiCdmaModem::GetEsn(DBus::Error& error) {
   LOG(INFO) << "GetEsn";
 
@@ -673,7 +770,7 @@
 }
 
 bool GobiCdmaModem::CheckEnableOk(DBus::Error &error) {
-  return true;
+  return !activation_in_progress_;
 }
 
 void GobiCdmaModem::SendActivationStateFailed() {
@@ -736,3 +833,25 @@
                          mm_activation_error,
                          to_send);
 }
+
+FilePath GobiCdmaModem::GetExecPostActivationStepsCookieCrumbPath() const {
+  string path =
+      StringPrintf(kExecPostActivationStepsCookieCrumbFormat,
+                   device_.deviceKey);
+  return FilePath::FromUTF8Unsafe(path);
+}
+
+void GobiCdmaModem::MarkForExecPostActivationStepsAfterReset() {
+  // This is a best effort attempt to write out the cookie crumb so don't
+  // need to check for write failures.
+  file_util::WriteFile(GetExecPostActivationStepsCookieCrumbPath(), "", 0);
+}
+
+bool GobiCdmaModem::ShouldExecPostActivationSteps() const {
+  FilePath cookie_crumb_path = GetExecPostActivationStepsCookieCrumbPath();
+  if (file_util::PathExists(cookie_crumb_path)) {
+    file_util::Delete(cookie_crumb_path, false);
+    return true;
+  }
+  return false;
+}
diff --git a/gobi_cdma_modem.h b/gobi_cdma_modem.h
index a7ca0b8..ffff34a 100644
--- a/gobi_cdma_modem.h
+++ b/gobi_cdma_modem.h
@@ -8,7 +8,9 @@
 #define PLUGIN_GOBI_CDMA_MODEM_H_
 
 #include "gobi_modem.h"
+#include <base/file_path.h>
 #include <cromo/modem-cdma_server_glue.h>
+
 class GobiModem;
 
 class GobiCdmaModem
@@ -23,6 +25,8 @@
                 GobiModemHelper *modem_helper);
   virtual ~GobiCdmaModem();
 
+  virtual void Init();
+
   // Modem methods
   virtual CdmaAdaptor *cdma_adaptor() {
     return static_cast<CdmaAdaptor*>(this);
@@ -94,13 +98,20 @@
     ULONG session_state;
     ULONG failure_reason;
   };
-  static void OmadmStateCallbackTrampoline(ULONG session_state,
-                                           ULONG failure_reason) {
-    PostCallbackRequest(OmadmStateCallback,
+  static void OmadmStateDeviceConfigureCallbackTrampoline(
+      ULONG session_state, ULONG failure_reason) {
+    PostCallbackRequest(OmadmStateDeviceConfigureCallback,
                         new OmadmStateArgs(session_state,
                                            failure_reason));
   }
-  static gboolean OmadmStateCallback(gpointer data);
+  static gboolean OmadmStateDeviceConfigureCallback(gpointer data);
+  static void OmadmStateClientPrlUpdateCallbackTrampoline(
+      ULONG session_state, ULONG failure_reason) {
+    PostCallbackRequest(OmadmStateClientPrlUpdateCallback,
+                        new OmadmStateArgs(session_state,
+                                           failure_reason));
+  }
+  static gboolean OmadmStateClientPrlUpdateCallback(gpointer data);
 
   // ======================================================================
 
@@ -121,8 +132,22 @@
   uint32_t ActivateOtasp(const std::string& number);
   // Perform actions necessary when activation as finished
   void ActivationFinished(void);
+  // Performs actions necessary when a modem is seen for the first time after
+  // it was activated and resetted.
+  void PerformPostActivationSteps();
+  // Starts a client initiated PRL update request.
+  void StartClientInitiatedPrlUpdate();
 
  private:
+  // Returns the path of the cookie crumb file used to indicate that post
+  // activation steps should be executed.
+  base::FilePath GetExecPostActivationStepsCookieCrumbPath() const;
+  // Writes a cookie crumb that signals post activation steps should be
+  // executed next time the modem appears to the system.
+  void MarkForExecPostActivationStepsAfterReset();
+  // Checks to see if post activation steps should be executed.
+  bool ShouldExecPostActivationSteps() const;
+
   DISALLOW_COPY_AND_ASSIGN(GobiCdmaModem);
 };