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