Merge "adb: run reverse_service() in main thread."
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index eff9876..37bd777 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -439,7 +439,7 @@
 
     adb_thread_setname("stdin reader");
 
-#ifndef __WIN32
+#ifndef _WIN32
     // Mask SIGTTIN in case we're in a backgrounded process
     sigset_t sigset;
     sigemptyset(&sigset);
diff --git a/base/include/base/parseint.h b/base/include/base/parseint.h
index 9ecbfbc..0543795 100644
--- a/base/include/base/parseint.h
+++ b/base/include/base/parseint.h
@@ -31,9 +31,10 @@
 template <typename T>
 bool ParseUint(const char* s, T* out,
                T max = std::numeric_limits<T>::max()) {
+  int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
   errno = 0;
   char* end;
-  unsigned long long int result = strtoull(s, &end, 10);
+  unsigned long long int result = strtoull(s, &end, base);
   if (errno != 0 || s == end || *end != '\0') {
     return false;
   }
@@ -52,9 +53,10 @@
 bool ParseInt(const char* s, T* out,
               T min = std::numeric_limits<T>::min(),
               T max = std::numeric_limits<T>::max()) {
+  int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
   errno = 0;
   char* end;
-  long long int result = strtoll(s, &end, 10);
+  long long int result = strtoll(s, &end, base);
   if (errno != 0 || s == end || *end != '\0') {
     return false;
   }
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
index 638f845..20da144 100644
--- a/base/include/base/strings.h
+++ b/base/include/base/strings.h
@@ -36,8 +36,8 @@
 std::string Trim(const std::string& s);
 
 // Joins a container of things into a single string, using the given separator.
-template <typename ContainerT>
-std::string Join(const ContainerT& things, char separator) {
+template <typename ContainerT, typename SeparatorT>
+std::string Join(const ContainerT& things, SeparatorT separator) {
   if (things.empty()) {
     return "";
   }
@@ -53,6 +53,8 @@
 // We instantiate the common cases in strings.cpp.
 extern template std::string Join(const std::vector<std::string>&, char);
 extern template std::string Join(const std::vector<const char*>&, char);
+extern template std::string Join(const std::vector<std::string>&, const std::string&);
+extern template std::string Join(const std::vector<const char*>&, const std::string&);
 
 // Tests whether 's' starts with 'prefix'.
 bool StartsWith(const std::string& s, const char* prefix);
diff --git a/base/parseint_test.cpp b/base/parseint_test.cpp
index e19c6e3..8a11d29 100644
--- a/base/parseint_test.cpp
+++ b/base/parseint_test.cpp
@@ -66,3 +66,13 @@
   ASSERT_TRUE(android::base::ParseUint("0123", &u));
   ASSERT_EQ(123u, u);
 }
+
+TEST(parseint, explicit_hex) {
+  int i;
+  ASSERT_TRUE(android::base::ParseInt("0x123", &i));
+  ASSERT_EQ(0x123, i);
+
+  unsigned int u;
+  ASSERT_TRUE(android::base::ParseUint("0x123", &u));
+  ASSERT_EQ(0x123u, u);
+}
diff --git a/base/strings.cpp b/base/strings.cpp
index bac983b..d687e3c 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -83,6 +83,8 @@
 // aid compile time and binary size.
 template std::string Join(const std::vector<std::string>&, char);
 template std::string Join(const std::vector<const char*>&, char);
+template std::string Join(const std::vector<std::string>&, const std::string&);
+template std::string Join(const std::vector<const char*>&, const std::string&);
 
 bool StartsWith(const std::string& s, const char* prefix) {
   return s.compare(0, strlen(prefix), prefix) == 0;
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7bf4b31..6b845a0 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -571,11 +571,13 @@
 static int64_t get_target_sparse_limit(usb_handle* usb) {
     std::string max_download_size;
     if (!fb_getvar(usb, "max-download-size", &max_download_size)) {
+        fprintf(stderr, "target didn't report max-download-size\n");
         return 0;
     }
 
     uint64_t limit;
     if (!android::base::ParseUint(max_download_size.c_str(), &limit)) {
+        fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
         return 0;
     }
     if (limit > 0) {
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 970b386..2a178aa 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -125,6 +125,8 @@
     { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
     { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest/*" },
+    { 00750, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/*" },
 
     /* the following four files are INTENTIONALLY set-uid, but they
      * are NOT included on user builds. */
diff --git a/metricsd/constants.h b/metricsd/constants.h
index 7e1e116..3a7569b 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -30,6 +30,10 @@
 // Build time properties name.
 static const char kProductId[] = "product_id";
 static const char kProductVersion[] = "product_version";
+
+// Weave configuration.
+static const char kWeaveConfigurationFile[] = "/system/etc/weaved/weaved.conf";
+static const char kModelManifestId[] = "model_id";
 }  // namespace metrics
 
 #endif  // METRICS_CONSTANTS_H_
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 1995510..f7060a2 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -108,7 +108,18 @@
   profile_.client_id = testing_ ?
       "client_id_test" :
       GetPersistentGUID(guid_path);
-  profile_.hardware_class = "unknown";
+  profile_.model_manifest_id = "unknown";
+  if (!testing_) {
+    brillo::KeyValueStore weave_config;
+    if (!weave_config.Load(base::FilePath(metrics::kWeaveConfigurationFile))) {
+      LOG(ERROR) << "Failed to load the weave configuration file.";
+    } else if (!weave_config.GetString(metrics::kModelManifestId,
+                                       &profile_.model_manifest_id)) {
+      LOG(ERROR) << "The model manifest id (model_id) is undefined in "
+                 << metrics::kWeaveConfigurationFile;
+    }
+  }
+
   profile_.channel = ProtoChannelFromString(channel);
 
   // Increment the session_id everytime we initialize this. If metrics_daemon
@@ -143,7 +154,7 @@
   metrics::SystemProfileProto* profile_proto =
       metrics_proto->mutable_system_profile();
   profile_proto->mutable_hardware()->set_hardware_class(
-      profile_.hardware_class);
+      profile_.model_manifest_id);
   profile_proto->set_app_version(profile_.version);
   profile_proto->set_channel(profile_.channel);
   metrics::SystemProfileProto_BrilloDeviceData* device_data =
diff --git a/metricsd/uploader/system_profile_cache.h b/metricsd/uploader/system_profile_cache.h
index 97fb33a..ae54a2a 100644
--- a/metricsd/uploader/system_profile_cache.h
+++ b/metricsd/uploader/system_profile_cache.h
@@ -35,7 +35,7 @@
 
 struct SystemProfile {
   std::string version;
-  std::string hardware_class;
+  std::string model_manifest_id;
   std::string client_id;
   int session_id;
   metrics::SystemProfileProto::Channel channel;
diff --git a/metricsd/uploader/upload_service.h b/metricsd/uploader/upload_service.h
index a4d0a1e..77df74b 100644
--- a/metricsd/uploader/upload_service.h
+++ b/metricsd/uploader/upload_service.h
@@ -46,8 +46,8 @@
 //
 // The two states are the presence or not of a staged log.
 // A staged log is a compressed protobuffer containing both the aggregated
-// metrics and event and information about the client. (product, hardware id,
-// etc...).
+// metrics and event and information about the client. (product,
+// model_manifest_id, etc...).
 //
 // At regular intervals, the upload event will be triggered and the following
 // will happen: