merge in pi-release history after reset to master
diff --git a/image_properties.h b/image_properties.h
index f8fe095..49fe82f 100644
--- a/image_properties.h
+++ b/image_properties.h
@@ -58,6 +58,10 @@
   // The release channel this image was obtained from.
   std::string current_channel;
 
+  // Whether we allow arbitrary channels instead of just the ones listed in
+  // kChannelsByStability.
+  bool allow_arbitrary_channels = false;
+
   // The Omaha URL this image should get updates from.
   std::string omaha_url;
 };
diff --git a/image_properties_android.cc b/image_properties_android.cc
index 1ec425d..fa25683 100644
--- a/image_properties_android.cc
+++ b/image_properties_android.cc
@@ -16,10 +16,13 @@
 
 #include "update_engine/image_properties.h"
 
+#include <fcntl.h>
+
 #include <string>
 
 #include <android-base/properties.h>
 #include <base/logging.h>
+#include <bootloader.h>
 #include <brillo/osrelease_reader.h>
 #include <brillo/strings/string_utils.h>
 
@@ -29,6 +32,7 @@
 #include "update_engine/common/prefs_interface.h"
 #include "update_engine/common/utils.h"
 #include "update_engine/system_state.h"
+#include "update_engine/utils_android.h"
 
 using android::base::GetProperty;
 using std::string;
@@ -47,8 +51,7 @@
 // components in OEM partition.
 const char kProductComponentsPath[] = "/oem/os-release.d/product_components";
 
-// Prefs used to store the target channel and powerwash settings.
-const char kPrefsImgPropChannelName[] = "img-prop-channel-name";
+// Prefs used to store the powerwash settings.
 const char kPrefsImgPropPowerwashAllowed[] = "img-prop-powerwash-allowed";
 
 // System properties that identifies the "board".
@@ -56,6 +59,9 @@
 const char kPropBuildFingerprint[] = "ro.build.fingerprint";
 const char kPropBuildType[] = "ro.build.type";
 
+// Default channel from factory.prop
+const char kPropDefaultChannel[] = "ro.update.default_channel";
+
 // A prefix added to the path, used for testing.
 const char* root_prefix = nullptr;
 
@@ -70,6 +76,81 @@
   return default_value;
 }
 
+// Open misc partition for read or write and output the fd in |out_fd|.
+bool OpenMisc(bool write, int* out_fd) {
+  base::FilePath misc_device;
+  int flags = write ? O_WRONLY | O_SYNC : O_RDONLY;
+  if (root_prefix) {
+    // Use a file for unittest and create one if doesn't exist.
+    misc_device = base::FilePath(root_prefix).Append("misc");
+    if (write)
+      flags |= O_CREAT;
+  } else if (!utils::DeviceForMountPoint("/misc", &misc_device)) {
+    return false;
+  }
+
+  int fd = HANDLE_EINTR(open(misc_device.value().c_str(), flags, 0600));
+  if (fd < 0) {
+    PLOG(ERROR) << "Opening misc failed";
+    return false;
+  }
+  *out_fd = fd;
+  return true;
+}
+
+// The offset and size of the channel field in misc partition.
+constexpr size_t kChannelOffset =
+    BOOTLOADER_MESSAGE_OFFSET_IN_MISC +
+    offsetof(bootloader_message_ab, update_channel);
+constexpr size_t kChannelSize = sizeof(bootloader_message_ab::update_channel);
+
+// Read channel from misc partition to |out_channel|, return false if unable to
+// read misc or no channel is set in misc.
+bool ReadChannelFromMisc(string* out_channel) {
+  int fd;
+  TEST_AND_RETURN_FALSE(OpenMisc(false, &fd));
+  ScopedFdCloser fd_closer(&fd);
+  char channel[kChannelSize] = {0};
+  ssize_t bytes_read = 0;
+  if (!utils::PReadAll(
+          fd, channel, kChannelSize - 1, kChannelOffset, &bytes_read) ||
+      bytes_read != kChannelSize - 1) {
+    PLOG(ERROR) << "Reading update channel from misc failed";
+    return false;
+  }
+  if (channel[0] == '\0') {
+    LOG(INFO) << "No channel set in misc.";
+    return false;
+  }
+  out_channel->assign(channel);
+  return true;
+}
+
+// Write |in_channel| to misc partition, return false if failed to write.
+bool WriteChannelToMisc(const string& in_channel) {
+  int fd;
+  TEST_AND_RETURN_FALSE(OpenMisc(true, &fd));
+  ScopedFdCloser fd_closer(&fd);
+  if (in_channel.size() >= kChannelSize) {
+    LOG(ERROR) << "Channel name is too long: " << in_channel
+               << ", the maximum length is " << kChannelSize - 1;
+    return false;
+  }
+  char channel[kChannelSize] = {0};
+  memcpy(channel, in_channel.data(), in_channel.size());
+  if (!utils::PWriteAll(fd, channel, kChannelSize, kChannelOffset)) {
+    PLOG(ERROR) << "Writing update channel to misc failed";
+    return false;
+  }
+  return true;
+}
+
+string GetTargetChannel() {
+  string channel;
+  if (!ReadChannelFromMisc(&channel))
+    channel = GetProperty(kPropDefaultChannel, "stable-channel");
+  return channel;
+}
 }  // namespace
 
 namespace test {
@@ -109,18 +190,18 @@
   result.build_fingerprint = GetProperty(kPropBuildFingerprint, "none");
   result.build_type = GetProperty(kPropBuildType, "");
 
-  // Brillo images don't have a channel assigned. We stored the name of the
-  // channel where we got the image from in prefs at the time of the update, so
-  // we use that as the current channel if available. During provisioning, there
-  // is no value assigned, so we default to the "stable-channel".
+  // Android doesn't have channel information in system image, we try to read
+  // the channel of current slot from prefs and then fallback to use the
+  // persisted target channel as current channel.
   string current_channel_key =
       kPrefsChannelOnSlotPrefix +
       std::to_string(system_state->boot_control()->GetCurrentSlot());
   string current_channel;
   if (!system_state->prefs()->Exists(current_channel_key) ||
       !system_state->prefs()->GetString(current_channel_key, &current_channel))
-    current_channel = "stable-channel";
+    current_channel = GetTargetChannel();
   result.current_channel = current_channel;
+  result.allow_arbitrary_channels = true;
 
   // Brillo only supports the official omaha URL.
   result.omaha_url = constants::kOmahaDefaultProductionURL;
@@ -130,11 +211,9 @@
 
 MutableImageProperties LoadMutableImageProperties(SystemState* system_state) {
   MutableImageProperties result;
-  PrefsInterface* const prefs = system_state->prefs();
-  if (!prefs->GetString(kPrefsImgPropChannelName, &result.target_channel))
-    result.target_channel.clear();
-  if (!prefs->GetBoolean(kPrefsImgPropPowerwashAllowed,
-                         &result.is_powerwash_allowed)) {
+  result.target_channel = GetTargetChannel();
+  if (!system_state->prefs()->GetBoolean(kPrefsImgPropPowerwashAllowed,
+                                         &result.is_powerwash_allowed)) {
     result.is_powerwash_allowed = false;
   }
   return result;
@@ -142,11 +221,13 @@
 
 bool StoreMutableImageProperties(SystemState* system_state,
                                  const MutableImageProperties& properties) {
-  PrefsInterface* const prefs = system_state->prefs();
-  return (
-      prefs->SetString(kPrefsImgPropChannelName, properties.target_channel) &&
-      prefs->SetBoolean(kPrefsImgPropPowerwashAllowed,
-                        properties.is_powerwash_allowed));
+  bool ret = true;
+  if (!WriteChannelToMisc(properties.target_channel))
+    ret = false;
+  if (!system_state->prefs()->SetBoolean(kPrefsImgPropPowerwashAllowed,
+                                         properties.is_powerwash_allowed))
+    ret = false;
+  return ret;
 }
 
 void LogImageProperties() {
diff --git a/image_properties_android_unittest.cc b/image_properties_android_unittest.cc
index 7327554..607284a 100644
--- a/image_properties_android_unittest.cc
+++ b/image_properties_android_unittest.cc
@@ -23,6 +23,7 @@
 #include <gtest/gtest.h>
 
 #include "update_engine/common/constants.h"
+#include "update_engine/common/fake_prefs.h"
 #include "update_engine/common/test_utils.h"
 #include "update_engine/fake_system_state.h"
 
@@ -45,6 +46,14 @@
     ASSERT_TRUE(WriteFileString(osrelease_dir_.Append(key).value(), value));
   }
 
+  void WriteChannel(const string& channel) {
+    string misc(2080, '\0');
+    misc += channel;
+    misc.resize(4096);
+    ASSERT_TRUE(
+        WriteFileString(tempdir_.GetPath().Append("misc").value(), misc));
+  }
+
   FakeSystemState fake_system_state_;
 
   base::ScopedTempDir tempdir_;
@@ -87,4 +96,28 @@
   EXPECT_EQ("bar", props.system_id);
 }
 
+TEST_F(ImagePropertiesTest, LoadChannelTest) {
+  WriteChannel("unittest-channel");
+  ImageProperties props = LoadImageProperties(&fake_system_state_);
+  EXPECT_EQ("unittest-channel", props.current_channel);
+}
+
+TEST_F(ImagePropertiesTest, DefaultStableChannelTest) {
+  WriteChannel("");
+  ImageProperties props = LoadImageProperties(&fake_system_state_);
+  EXPECT_EQ("stable-channel", props.current_channel);
+}
+
+TEST_F(ImagePropertiesTest, StoreLoadMutableChannelTest) {
+  FakePrefs prefs;
+  fake_system_state_.set_prefs(&prefs);
+  WriteChannel("previous-channel");
+  MutableImageProperties props;
+  props.target_channel = "new-channel";
+  EXPECT_TRUE(StoreMutableImageProperties(&fake_system_state_, props));
+  MutableImageProperties loaded_props =
+      LoadMutableImageProperties(&fake_system_state_);
+  EXPECT_EQ(props.target_channel, loaded_props.target_channel);
+}
+
 }  // namespace chromeos_update_engine
diff --git a/image_properties_chromeos.cc b/image_properties_chromeos.cc
index 39ddeb3..87c32f0 100644
--- a/image_properties_chromeos.cc
+++ b/image_properties_chromeos.cc
@@ -118,6 +118,7 @@
                            constants::kOmahaDefaultProductionURL);
   // Build fingerprint not used in Chrome OS.
   result.build_fingerprint = "";
+  result.allow_arbitrary_channels = false;
 
   return result;
 }
diff --git a/main.cc b/main.cc
index 0b96307..0612c54 100644
--- a/main.cc
+++ b/main.cc
@@ -14,15 +14,19 @@
 // limitations under the License.
 //
 
+#include <inttypes.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <xz.h>
 
+#include <algorithm>
 #include <string>
+#include <vector>
 
 #include <base/at_exit.h>
 #include <base/command_line.h>
+#include <base/files/dir_reader_posix.h>
 #include <base/files/file_util.h>
 #include <base/logging.h>
 #include <base/strings/string_util.h>
@@ -38,7 +42,65 @@
 namespace chromeos_update_engine {
 namespace {
 
-#ifndef __ANDROID__
+string GetTimeAsString(time_t utime) {
+  struct tm tm;
+  CHECK_EQ(localtime_r(&utime, &tm), &tm);
+  char str[16];
+  CHECK_EQ(strftime(str, sizeof(str), "%Y%m%d-%H%M%S", &tm), 15u);
+  return str;
+}
+
+#ifdef __ANDROID__
+constexpr char kSystemLogsRoot[] = "/data/misc/update_engine_log";
+constexpr size_t kLogCount = 5;
+
+// Keep the most recent |kLogCount| logs but remove the old ones in
+// "/data/misc/update_engine_log/".
+void DeleteOldLogs(const string& kLogsRoot) {
+  base::DirReaderPosix reader(kLogsRoot.c_str());
+  if (!reader.IsValid()) {
+    LOG(ERROR) << "Failed to read " << kLogsRoot;
+    return;
+  }
+
+  std::vector<string> old_logs;
+  while (reader.Next()) {
+    if (reader.name()[0] == '.')
+      continue;
+
+    // Log files are in format "update_engine.%Y%m%d-%H%M%S",
+    // e.g. update_engine.20090103-231425
+    uint64_t date;
+    uint64_t local_time;
+    if (sscanf(reader.name(),
+               "update_engine.%" PRIu64 "-%" PRIu64 "",
+               &date,
+               &local_time) == 2) {
+      old_logs.push_back(reader.name());
+    } else {
+      LOG(WARNING) << "Unrecognized log file " << reader.name();
+    }
+  }
+
+  std::sort(old_logs.begin(), old_logs.end(), std::greater<string>());
+  for (size_t i = kLogCount; i < old_logs.size(); i++) {
+    string log_path = kLogsRoot + "/" + old_logs[i];
+    if (unlink(log_path.c_str()) == -1) {
+      PLOG(WARNING) << "Failed to unlink " << log_path;
+    }
+  }
+}
+
+string SetupLogFile(const string& kLogsRoot) {
+  DeleteOldLogs(kLogsRoot);
+
+  return base::StringPrintf("%s/update_engine.%s",
+                            kLogsRoot.c_str(),
+                            GetTimeAsString(::time(nullptr)).c_str());
+}
+#else
+constexpr char kSystemLogsRoot[] = "/var/log";
+
 void SetupLogSymlink(const string& symlink_path, const string& log_path) {
   // TODO(petkov): To ensure a smooth transition between non-timestamped and
   // timestamped logs, move an existing log to start the first timestamped
@@ -57,14 +119,6 @@
   }
 }
 
-string GetTimeAsString(time_t utime) {
-  struct tm tm;
-  CHECK_EQ(localtime_r(&utime, &tm), &tm);
-  char str[16];
-  CHECK_EQ(strftime(str, sizeof(str), "%Y%m%d-%H%M%S", &tm), 15u);
-  return str;
-}
-
 string SetupLogFile(const string& kLogsRoot) {
   const string kLogSymlink = kLogsRoot + "/update_engine.log";
   const string kLogsDir = kLogsRoot + "/update_engine";
@@ -88,13 +142,8 @@
 
   string log_file;
   if (log_to_file) {
-#ifdef __ANDROID__
-    log_file = "/data/misc/update_engine_log/update_engine.log";
-    log_settings.delete_old = logging::DELETE_OLD_LOG_FILE;
-#else
-    log_file = SetupLogFile("/var/log");
+    log_file = SetupLogFile(kSystemLogsRoot);
     log_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
-#endif  // __ANDROID__
     log_settings.log_file = log_file.c_str();
   }
   logging::InitLogging(log_settings);
diff --git a/omaha_request_params.cc b/omaha_request_params.cc
index 3ba7037..641032b 100644
--- a/omaha_request_params.cc
+++ b/omaha_request_params.cc
@@ -192,7 +192,7 @@
 }
 
 bool OmahaRequestParams::IsValidChannel(const string& channel) const {
-  return GetChannelIndex(channel) >= 0;
+  return image_props_.allow_arbitrary_channels || GetChannelIndex(channel) >= 0;
 }
 
 void OmahaRequestParams::set_root(const string& root) {
diff --git a/omaha_request_params.h b/omaha_request_params.h
index 73edd6f..9e41716 100644
--- a/omaha_request_params.h
+++ b/omaha_request_params.h
@@ -253,10 +253,11 @@
   }
 
  private:
-  FRIEND_TEST(OmahaRequestParamsTest, IsValidChannelTest);
   FRIEND_TEST(OmahaRequestParamsTest, ChannelIndexTest);
-  FRIEND_TEST(OmahaRequestParamsTest, ToMoreStableChannelFlagTest);
   FRIEND_TEST(OmahaRequestParamsTest, CollectECFWVersionsTest);
+  FRIEND_TEST(OmahaRequestParamsTest, IsValidChannelTest);
+  FRIEND_TEST(OmahaRequestParamsTest, SetTargetChannelInvalidTest);
+  FRIEND_TEST(OmahaRequestParamsTest, ToMoreStableChannelFlagTest);
 
   // Returns true if |channel| is a valid channel, false otherwise.
   bool IsValidChannel(const std::string& channel) const;
diff --git a/omaha_request_params_unittest.cc b/omaha_request_params_unittest.cc
index 57ecf24..6705c71 100644
--- a/omaha_request_params_unittest.cc
+++ b/omaha_request_params_unittest.cc
@@ -145,6 +145,7 @@
     params.set_root(tempdir_.GetPath().value());
     SetLockDown(true);
     EXPECT_TRUE(params.Init("", "", false));
+    params.image_props_.allow_arbitrary_channels = false;
     string error_message;
     EXPECT_FALSE(
         params.SetTargetChannel("dogfood-channel", true, &error_message));
@@ -167,6 +168,8 @@
   EXPECT_FALSE(params_.IsValidChannel("dogfood-channel"));
   EXPECT_FALSE(params_.IsValidChannel("some-channel"));
   EXPECT_FALSE(params_.IsValidChannel(""));
+  params_.image_props_.allow_arbitrary_channels = true;
+  EXPECT_TRUE(params_.IsValidChannel("some-channel"));
 }
 
 TEST_F(OmahaRequestParamsTest, SetTargetChannelWorks) {
diff --git a/omaha_response_handler_action_unittest.cc b/omaha_response_handler_action_unittest.cc
index 568d11d..4e9c03f 100644
--- a/omaha_response_handler_action_unittest.cc
+++ b/omaha_response_handler_action_unittest.cc
@@ -388,8 +388,6 @@
   params.set_current_channel("canary-channel");
   // The ImageProperties in Android uses prefs to store MutableImageProperties.
 #ifdef __ANDROID__
-  EXPECT_CALL(*fake_system_state_.mock_prefs(), SetString(_, "stable-channel"))
-      .WillOnce(Return(true));
   EXPECT_CALL(*fake_system_state_.mock_prefs(), SetBoolean(_, true))
       .WillOnce(Return(true));
 #endif  // __ANDROID__
@@ -423,8 +421,6 @@
   params.set_current_channel("stable-channel");
   // The ImageProperties in Android uses prefs to store MutableImageProperties.
 #ifdef __ANDROID__
-  EXPECT_CALL(*fake_system_state_.mock_prefs(), SetString(_, "canary-channel"))
-      .WillOnce(Return(true));
   EXPECT_CALL(*fake_system_state_.mock_prefs(), SetBoolean(_, false))
       .WillOnce(Return(true));
 #endif  // __ANDROID__