image_properties_android.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. //
  2. // Copyright (C) 2015 The Android Open Source Project
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #include "update_engine/image_properties.h"
  17. #include <fcntl.h>
  18. #include <string>
  19. #include <android-base/properties.h>
  20. #include <base/logging.h>
  21. #include <base/strings/string_util.h>
  22. #include <bootloader_message/bootloader_message.h>
  23. #include <brillo/osrelease_reader.h>
  24. #include <brillo/strings/string_utils.h>
  25. #include "update_engine/common/boot_control_interface.h"
  26. #include "update_engine/common/constants.h"
  27. #include "update_engine/common/platform_constants.h"
  28. #include "update_engine/common/prefs_interface.h"
  29. #include "update_engine/common/utils.h"
  30. #include "update_engine/system_state.h"
  31. using android::base::GetProperty;
  32. using std::string;
  33. namespace chromeos_update_engine {
  34. namespace {
  35. // Build time properties name used in Android Things.
  36. const char kProductId[] = "product_id";
  37. const char kProductVersion[] = "product_version";
  38. const char kSystemId[] = "system_id";
  39. const char kSystemVersion[] = "system_version";
  40. // The path to the product_components file which stores the version of each
  41. // components in OEM partition.
  42. const char kProductComponentsPath[] = "/oem/os-release.d/product_components";
  43. // Prefs used to store the powerwash settings.
  44. const char kPrefsImgPropPowerwashAllowed[] = "img-prop-powerwash-allowed";
  45. // System properties that identifies the "board".
  46. const char kPropProductName[] = "ro.product.name";
  47. const char kPropBuildFingerprint[] = "ro.build.fingerprint";
  48. const char kPropBuildType[] = "ro.build.type";
  49. // Default channel from factory.prop
  50. const char kPropDefaultChannel[] = "ro.update.default_channel";
  51. // A prefix added to the path, used for testing.
  52. const char* root_prefix = nullptr;
  53. string GetStringWithDefault(const brillo::OsReleaseReader& osrelease,
  54. const string& key,
  55. const string& default_value) {
  56. string result;
  57. if (osrelease.GetString(key, &result))
  58. return result;
  59. LOG(INFO) << "Cannot load ImageProperty " << key << ", using default value "
  60. << default_value;
  61. return default_value;
  62. }
  63. // Open misc partition for read or write and output the fd in |out_fd|.
  64. bool OpenMisc(bool write, int* out_fd) {
  65. string misc_device;
  66. int flags = write ? O_WRONLY | O_SYNC : O_RDONLY;
  67. if (root_prefix) {
  68. // Use a file for unittest and create one if doesn't exist.
  69. misc_device = base::FilePath(root_prefix).Append("misc").value();
  70. if (write)
  71. flags |= O_CREAT;
  72. } else {
  73. string err;
  74. misc_device = get_bootloader_message_blk_device(&err);
  75. if (misc_device.empty()) {
  76. LOG(ERROR) << "Unable to get misc block device: " << err;
  77. return false;
  78. }
  79. }
  80. int fd = HANDLE_EINTR(open(misc_device.c_str(), flags, 0600));
  81. if (fd < 0) {
  82. PLOG(ERROR) << "Opening misc failed";
  83. return false;
  84. }
  85. *out_fd = fd;
  86. return true;
  87. }
  88. // The offset and size of the channel field in misc partition.
  89. constexpr size_t kChannelOffset =
  90. BOOTLOADER_MESSAGE_OFFSET_IN_MISC +
  91. offsetof(bootloader_message_ab, update_channel);
  92. constexpr size_t kChannelSize = sizeof(bootloader_message_ab::update_channel);
  93. // Read channel from misc partition to |out_channel|, return false if unable to
  94. // read misc or no channel is set in misc.
  95. bool ReadChannelFromMisc(string* out_channel) {
  96. int fd;
  97. TEST_AND_RETURN_FALSE(OpenMisc(false, &fd));
  98. ScopedFdCloser fd_closer(&fd);
  99. char channel[kChannelSize] = {0};
  100. ssize_t bytes_read = 0;
  101. if (!utils::PReadAll(
  102. fd, channel, kChannelSize - 1, kChannelOffset, &bytes_read) ||
  103. bytes_read != kChannelSize - 1) {
  104. PLOG(ERROR) << "Reading update channel from misc failed";
  105. return false;
  106. }
  107. if (channel[0] == '\0') {
  108. LOG(INFO) << "No channel set in misc.";
  109. return false;
  110. }
  111. if (!base::EndsWith(channel, "-channel", base::CompareCase::SENSITIVE)) {
  112. LOG(ERROR) << "Channel " << channel << " doesn't end with -channel.";
  113. return false;
  114. }
  115. out_channel->assign(channel);
  116. return true;
  117. }
  118. // Write |in_channel| to misc partition, return false if failed to write.
  119. bool WriteChannelToMisc(const string& in_channel) {
  120. int fd;
  121. TEST_AND_RETURN_FALSE(OpenMisc(true, &fd));
  122. ScopedFdCloser fd_closer(&fd);
  123. if (in_channel.size() >= kChannelSize) {
  124. LOG(ERROR) << "Channel name is too long: " << in_channel
  125. << ", the maximum length is " << kChannelSize - 1;
  126. return false;
  127. }
  128. char channel[kChannelSize] = {0};
  129. memcpy(channel, in_channel.data(), in_channel.size());
  130. if (!utils::PWriteAll(fd, channel, kChannelSize, kChannelOffset)) {
  131. PLOG(ERROR) << "Writing update channel to misc failed";
  132. return false;
  133. }
  134. return true;
  135. }
  136. string GetTargetChannel() {
  137. string channel;
  138. if (!ReadChannelFromMisc(&channel))
  139. channel = GetProperty(kPropDefaultChannel, "stable-channel");
  140. return channel;
  141. }
  142. } // namespace
  143. namespace test {
  144. void SetImagePropertiesRootPrefix(const char* test_root_prefix) {
  145. root_prefix = test_root_prefix;
  146. }
  147. } // namespace test
  148. ImageProperties LoadImageProperties(SystemState* system_state) {
  149. ImageProperties result;
  150. brillo::OsReleaseReader osrelease;
  151. if (root_prefix)
  152. osrelease.LoadTestingOnly(base::FilePath(root_prefix));
  153. else
  154. osrelease.Load();
  155. result.product_id =
  156. GetStringWithDefault(osrelease, kProductId, "invalid-product");
  157. result.system_id = GetStringWithDefault(
  158. osrelease, kSystemId, "developer-boards:brillo-starter-board");
  159. // Update the system id to match the prefix of product id for testing.
  160. string prefix, not_used, system_id;
  161. if (brillo::string_utils::SplitAtFirst(
  162. result.product_id, ":", &prefix, &not_used, false) &&
  163. brillo::string_utils::SplitAtFirst(
  164. result.system_id, ":", &not_used, &system_id, false)) {
  165. result.system_id = prefix + ":" + system_id;
  166. }
  167. result.canary_product_id = result.product_id;
  168. result.version = GetStringWithDefault(osrelease, kProductVersion, "0.0.0.0");
  169. result.system_version =
  170. GetStringWithDefault(osrelease, kSystemVersion, "0.0.0.0");
  171. // Can't read it with OsReleaseReader because it has multiple lines.
  172. utils::ReadFile(kProductComponentsPath, &result.product_components);
  173. result.board = GetProperty(kPropProductName, "brillo");
  174. result.build_fingerprint = GetProperty(kPropBuildFingerprint, "none");
  175. result.build_type = GetProperty(kPropBuildType, "");
  176. // Android doesn't have channel information in system image, we try to read
  177. // the channel of current slot from prefs and then fallback to use the
  178. // persisted target channel as current channel.
  179. string current_channel_key =
  180. kPrefsChannelOnSlotPrefix +
  181. std::to_string(system_state->boot_control()->GetCurrentSlot());
  182. string current_channel;
  183. if (!system_state->prefs()->Exists(current_channel_key) ||
  184. !system_state->prefs()->GetString(current_channel_key, &current_channel))
  185. current_channel = GetTargetChannel();
  186. result.current_channel = current_channel;
  187. result.allow_arbitrary_channels = true;
  188. // Brillo only supports the official omaha URL.
  189. result.omaha_url = constants::kOmahaDefaultProductionURL;
  190. return result;
  191. }
  192. MutableImageProperties LoadMutableImageProperties(SystemState* system_state) {
  193. MutableImageProperties result;
  194. result.target_channel = GetTargetChannel();
  195. if (!system_state->prefs()->GetBoolean(kPrefsImgPropPowerwashAllowed,
  196. &result.is_powerwash_allowed)) {
  197. result.is_powerwash_allowed = false;
  198. }
  199. return result;
  200. }
  201. bool StoreMutableImageProperties(SystemState* system_state,
  202. const MutableImageProperties& properties) {
  203. bool ret = true;
  204. if (!WriteChannelToMisc(properties.target_channel))
  205. ret = false;
  206. if (!system_state->prefs()->SetBoolean(kPrefsImgPropPowerwashAllowed,
  207. properties.is_powerwash_allowed))
  208. ret = false;
  209. return ret;
  210. }
  211. void LogImageProperties() {
  212. // TODO(*): Implement this.
  213. }
  214. } // namespace chromeos_update_engine