AU: Include a bit flag (bit 31) in error codes to indicate non-normal boot mode.

BUG=chromium-os:10320
TEST=unit test, tested on device in normal and dev mode

Change-Id: I67d695bc167a4cc1a638711f047e2b86f8eaa8f1

Review URL: http://codereview.chromium.org/6098008
diff --git a/SConstruct b/SConstruct
index 615d18c..f75b256 100644
--- a/SConstruct
+++ b/SConstruct
@@ -195,6 +195,7 @@
 
 env['LIBS'] = Split("""base
                        bz2
+                       cros_boot_mode
                        crypto
                        curl
                        ext2fs
diff --git a/action_processor.h b/action_processor.h
index 0cf6ff6..124fe00 100644
--- a/action_processor.h
+++ b/action_processor.h
@@ -46,6 +46,9 @@
   kActionCodeOmahaRequestNoUpdateCheckStatus = 203,
   kActionCodeOmahaRequestBadUpdateCheckStatus = 204,
   kActionCodeOmahaRequestHTTPResponseBase = 2000,  // + HTTP response code
+
+  // Bit flags.
+  kActionCodeBootModeFlag = 1 << 31,  // Set if boot mode not normal.
 };
 
 class AbstractAction;
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index bb2275d..b8495c8 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -119,11 +119,15 @@
           << "Unable to reset the previous version.";
     }
   } else {
-    // The error code is an optional attribute so append it only if
-    // the result is not success.
+    // The error code is an optional attribute so append it only if the result
+    // is not success.
     string error_code;
     if (event->result != OmahaEvent::kResultSuccess) {
-      error_code = StringPrintf(" errorcode=\"%d\"", event->error_code);
+      int code = event->error_code;
+      if (!utils::IsNormalBootMode()) {
+        code |= kActionCodeBootModeFlag;
+      }
+      error_code = StringPrintf(" errorcode=\"%d\"", code);
     }
     body = StringPrintf(
         "        <o:event eventtype=\"%d\" eventresult=\"%d\"%s></o:event>\n",
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index 4ac2b74..8082e15 100755
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -603,27 +603,7 @@
       "errorcode=\"%d\"></o:event>\n",
       OmahaEvent::kTypeDownloadComplete,
       OmahaEvent::kResultError,
-      kActionCodeError);
-  EXPECT_NE(post_str.find(expected_event), string::npos);
-  EXPECT_EQ(post_str.find("o:updatecheck"), string::npos);
-}
-
-TEST(OmahaRequestActionTest, FormatEventOutputTest) {
-  vector<char> post_data;
-  TestEvent(kDefaultTestParams,
-            new OmahaEvent(OmahaEvent::kTypeDownloadComplete,
-                           OmahaEvent::kResultError,
-                           kActionCodeError),
-            "invalid xml>",
-            &post_data);
-  // convert post_data to string
-  string post_str(&post_data[0], post_data.size());
-  string expected_event = StringPrintf(
-      "        <o:event eventtype=\"%d\" eventresult=\"%d\" "
-      "errorcode=\"%d\"></o:event>\n",
-      OmahaEvent::kTypeDownloadComplete,
-      OmahaEvent::kResultError,
-      kActionCodeError);
+      kActionCodeError | kActionCodeBootModeFlag);
   EXPECT_NE(post_str.find(expected_event), string::npos);
   EXPECT_EQ(post_str.find("o:updatecheck"), string::npos);
 }
diff --git a/setup_dev_packages b/setup_dev_packages
index d5ddcc7..8a9182c 100755
--- a/setup_dev_packages
+++ b/setup_dev_packages
@@ -7,6 +7,7 @@
 set -ex
 
 sudo USE="-crash cros-debug" emerge -DNauv1 \
+  chromeos-base/cros_boot_mode \
   chromeos-base/hard-host-depends \
   chromeos-base/libchrome \
   chromeos-base/metrics \
diff --git a/utils.cc b/utils.cc
index 95b5ec9..7206171 100644
--- a/utils.cc
+++ b/utils.cc
@@ -25,6 +25,7 @@
 #include <base/rand_util.h>
 #include <base/string_util.h>
 #include <base/logging.h>
+#include <cros_boot_mode/boot_mode.h>
 #include <rootdev/rootdev.h>
 
 #include "update_engine/file_writer.h"
@@ -50,6 +51,15 @@
   return file_util::PathExists(FilePath(kOOBECompletedMarker));
 }
 
+bool IsNormalBootMode() {
+  cros_boot_mode::BootMode mode;
+  mode.Initialize(false,  // unsupported_is_developer
+                  true);  // use_bootloader
+  bool normal = mode.mode() == cros_boot_mode::BootMode::kNormal;
+  LOG_IF(INFO, !normal) << "Boot mode not normal: " << mode.mode_text();
+  return normal;
+}
+
 bool WriteFile(const char* path, const char* data, int data_len) {
   DirectFileWriter writer;
   TEST_AND_RETURN_FALSE_ERRNO(0 == writer.Open(path,
diff --git a/utils.h b/utils.h
index 776fc22..86ccfb7 100644
--- a/utils.h
+++ b/utils.h
@@ -29,6 +29,10 @@
 // otherwise.
 bool IsOOBEComplete();
 
+// Returns true if the boot mode is normal, false otherwise (e.g., developer or
+// recovery).
+bool IsNormalBootMode();
+
 // Writes the data passed to path. The file at path will be overwritten if it
 // exists. Returns true on success, false otherwise.
 bool WriteFile(const char* path, const char* data, int data_len);
diff --git a/utils_unittest.cc b/utils_unittest.cc
index 185ab9a..0fda08f 100644
--- a/utils_unittest.cc
+++ b/utils_unittest.cc
@@ -29,6 +29,11 @@
   EXPECT_TRUE(utils::IsOfficialBuild());
 }
 
+TEST(UtilsTest, IsNormalBootMode) {
+  // Pretty lame test...
+  EXPECT_FALSE(utils::IsNormalBootMode());
+}
+
 TEST(UtilsTest, NormalizePathTest) {
   EXPECT_EQ("", utils::NormalizePath("", false));
   EXPECT_EQ("", utils::NormalizePath("", true));