• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2013 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/cros/hardware_chromeos.h"
18 
19 #include <utility>
20 
21 #include <base/files/file_path.h>
22 #include <base/files/file_util.h>
23 #include <base/logging.h>
24 #include <base/strings/string_number_conversions.h>
25 #include <base/strings/string_util.h>
26 #include <brillo/key_value_store.h>
27 #include <debugd/dbus-constants.h>
28 #include <vboot/crossystem.h>
29 
30 extern "C" {
31 #include "vboot/vboot_host.h"
32 }
33 
34 #include "update_engine/common/constants.h"
35 #include "update_engine/common/hardware.h"
36 #include "update_engine/common/hwid_override.h"
37 #include "update_engine/common/platform_constants.h"
38 #include "update_engine/common/subprocess.h"
39 #include "update_engine/common/utils.h"
40 #include "update_engine/cros/dbus_connection.h"
41 #if USE_CFM
42 #include "update_engine/cros/requisition_util.h"
43 #endif
44 
45 using std::string;
46 using std::vector;
47 
48 namespace {
49 
50 const char kOOBECompletedMarker[] = "/home/chronos/.oobe_completed";
51 
52 // The stateful directory used by update_engine to store powerwash-safe files.
53 // The files stored here must be added to the powerwash script allowlist.
54 const char kPowerwashSafeDirectory[] =
55     "/mnt/stateful_partition/unencrypted/preserve";
56 
57 // The powerwash_count marker file contains the number of times the device was
58 // powerwashed. This value is incremented by the clobber-state script when
59 // a powerwash is performed.
60 const char kPowerwashCountMarker[] = "powerwash_count";
61 
62 // The name of the marker file used to trigger powerwash when post-install
63 // completes successfully so that the device is powerwashed on next reboot.
64 const char kPowerwashMarkerFile[] =
65     "/mnt/stateful_partition/factory_install_reset";
66 
67 // The name of the marker file used to trigger a save of rollback data
68 // during the next shutdown.
69 const char kRollbackSaveMarkerFile[] =
70     "/mnt/stateful_partition/.save_rollback_data";
71 
72 // The contents of the powerwash marker file for the non-rollback case.
73 const char kPowerwashCommand[] = "safe fast keepimg reason=update_engine\n";
74 
75 // The contents of the powerwas marker file for the rollback case.
76 const char kRollbackPowerwashCommand[] =
77     "safe fast keepimg rollback reason=update_engine\n";
78 
79 // UpdateManager config path.
80 const char* kConfigFilePath = "/etc/update_manager.conf";
81 
82 // UpdateManager config options:
83 const char* kConfigOptsIsOOBEEnabled = "is_oobe_enabled";
84 
85 const char* kActivePingKey = "first_active_omaha_ping_sent";
86 
87 }  // namespace
88 
89 namespace chromeos_update_engine {
90 
91 namespace hardware {
92 
93 // Factory defined in hardware.h.
CreateHardware()94 std::unique_ptr<HardwareInterface> CreateHardware() {
95   std::unique_ptr<HardwareChromeOS> hardware(new HardwareChromeOS());
96   hardware->Init();
97   return std::move(hardware);
98 }
99 
100 }  // namespace hardware
101 
Init()102 void HardwareChromeOS::Init() {
103   LoadConfig("" /* root_prefix */, IsNormalBootMode());
104   debugd_proxy_.reset(
105       new org::chromium::debugdProxy(DBusConnection::Get()->GetDBus()));
106 }
107 
IsOfficialBuild() const108 bool HardwareChromeOS::IsOfficialBuild() const {
109   return VbGetSystemPropertyInt("debug_build") == 0;
110 }
111 
IsNormalBootMode() const112 bool HardwareChromeOS::IsNormalBootMode() const {
113   bool dev_mode = VbGetSystemPropertyInt("devsw_boot") != 0;
114   return !dev_mode;
115 }
116 
AreDevFeaturesEnabled() const117 bool HardwareChromeOS::AreDevFeaturesEnabled() const {
118   // Even though the debugd tools are also gated on devmode, checking here can
119   // save us a D-Bus call so it's worth doing explicitly.
120   if (IsNormalBootMode())
121     return false;
122 
123   int32_t dev_features = debugd::DEV_FEATURES_DISABLED;
124   brillo::ErrorPtr error;
125   // Some boards may not include debugd so it's expected that this may fail,
126   // in which case we treat it as disabled.
127   if (debugd_proxy_ && debugd_proxy_->QueryDevFeatures(&dev_features, &error) &&
128       !(dev_features & debugd::DEV_FEATURES_DISABLED)) {
129     LOG(INFO) << "Debugd dev tools enabled.";
130     return true;
131   }
132   return false;
133 }
134 
IsOOBEEnabled() const135 bool HardwareChromeOS::IsOOBEEnabled() const {
136   return is_oobe_enabled_;
137 }
138 
IsOOBEComplete(base::Time * out_time_of_oobe) const139 bool HardwareChromeOS::IsOOBEComplete(base::Time* out_time_of_oobe) const {
140   if (!is_oobe_enabled_) {
141     LOG(WARNING) << "OOBE is not enabled but IsOOBEComplete() was called";
142   }
143   struct stat statbuf;
144   if (stat(kOOBECompletedMarker, &statbuf) != 0) {
145     if (errno != ENOENT) {
146       PLOG(ERROR) << "Error getting information about " << kOOBECompletedMarker;
147     }
148     return false;
149   }
150 
151   if (out_time_of_oobe != nullptr)
152     *out_time_of_oobe = base::Time::FromTimeT(statbuf.st_mtime);
153   return true;
154 }
155 
ReadValueFromCrosSystem(const string & key)156 static string ReadValueFromCrosSystem(const string& key) {
157   char value_buffer[VB_MAX_STRING_PROPERTY];
158 
159   const char* rv = VbGetSystemPropertyString(
160       key.c_str(), value_buffer, sizeof(value_buffer));
161   if (rv != nullptr) {
162     string return_value(value_buffer);
163     base::TrimWhitespaceASCII(return_value, base::TRIM_ALL, &return_value);
164     return return_value;
165   }
166 
167   LOG(ERROR) << "Unable to read crossystem key " << key;
168   return "";
169 }
170 
GetHardwareClass() const171 string HardwareChromeOS::GetHardwareClass() const {
172   if (USE_HWID_OVERRIDE) {
173     return HwidOverride::Read(base::FilePath("/"));
174   }
175   return ReadValueFromCrosSystem("hwid");
176 }
177 
GetDeviceRequisition() const178 string HardwareChromeOS::GetDeviceRequisition() const {
179 #if USE_CFM
180   const char* kLocalStatePath = "/home/chronos/Local State";
181   return ReadDeviceRequisition(base::FilePath(kLocalStatePath));
182 #else
183   return "";
184 #endif
185 }
186 
GetMinKernelKeyVersion() const187 int HardwareChromeOS::GetMinKernelKeyVersion() const {
188   return VbGetSystemPropertyInt("tpm_kernver");
189 }
190 
GetMaxFirmwareKeyRollforward() const191 int HardwareChromeOS::GetMaxFirmwareKeyRollforward() const {
192   return VbGetSystemPropertyInt("firmware_max_rollforward");
193 }
194 
SetMaxFirmwareKeyRollforward(int firmware_max_rollforward)195 bool HardwareChromeOS::SetMaxFirmwareKeyRollforward(
196     int firmware_max_rollforward) {
197   // Not all devices have this field yet. So first try to read
198   // it and if there is an error just fail.
199   if (GetMaxFirmwareKeyRollforward() == -1)
200     return false;
201 
202   return VbSetSystemPropertyInt("firmware_max_rollforward",
203                                 firmware_max_rollforward) == 0;
204 }
205 
GetMinFirmwareKeyVersion() const206 int HardwareChromeOS::GetMinFirmwareKeyVersion() const {
207   return VbGetSystemPropertyInt("tpm_fwver");
208 }
209 
SetMaxKernelKeyRollforward(int kernel_max_rollforward)210 bool HardwareChromeOS::SetMaxKernelKeyRollforward(int kernel_max_rollforward) {
211   return VbSetSystemPropertyInt("kernel_max_rollforward",
212                                 kernel_max_rollforward) == 0;
213 }
214 
GetPowerwashCount() const215 int HardwareChromeOS::GetPowerwashCount() const {
216   int powerwash_count;
217   base::FilePath marker_path =
218       base::FilePath(kPowerwashSafeDirectory).Append(kPowerwashCountMarker);
219   string contents;
220   if (!utils::ReadFile(marker_path.value(), &contents))
221     return -1;
222   base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
223   if (!base::StringToInt(contents, &powerwash_count))
224     return -1;
225   return powerwash_count;
226 }
227 
SchedulePowerwash(bool save_rollback_data)228 bool HardwareChromeOS::SchedulePowerwash(bool save_rollback_data) {
229   if (save_rollback_data) {
230     if (!utils::WriteFile(kRollbackSaveMarkerFile, nullptr, 0)) {
231       PLOG(ERROR) << "Error in creating rollback save marker file: "
232                   << kRollbackSaveMarkerFile << ". Rollback will not"
233                   << " preserve any data.";
234     } else {
235       LOG(INFO) << "Rollback data save has been scheduled on next shutdown.";
236     }
237   }
238 
239   const char* powerwash_command =
240       save_rollback_data ? kRollbackPowerwashCommand : kPowerwashCommand;
241   bool result = utils::WriteFile(
242       kPowerwashMarkerFile, powerwash_command, strlen(powerwash_command));
243   if (result) {
244     LOG(INFO) << "Created " << kPowerwashMarkerFile
245               << " to powerwash on next reboot ("
246               << "save_rollback_data=" << save_rollback_data << ")";
247   } else {
248     PLOG(ERROR) << "Error in creating powerwash marker file: "
249                 << kPowerwashMarkerFile;
250   }
251 
252   return result;
253 }
254 
CancelPowerwash()255 bool HardwareChromeOS::CancelPowerwash() {
256   bool result = base::DeleteFile(base::FilePath(kPowerwashMarkerFile));
257 
258   if (result) {
259     LOG(INFO) << "Successfully deleted the powerwash marker file : "
260               << kPowerwashMarkerFile;
261   } else {
262     PLOG(ERROR) << "Could not delete the powerwash marker file : "
263                 << kPowerwashMarkerFile;
264   }
265 
266   // Delete the rollback save marker file if it existed.
267   if (!base::DeleteFile(base::FilePath(kRollbackSaveMarkerFile))) {
268     PLOG(ERROR) << "Could not remove rollback save marker";
269   }
270 
271   return result;
272 }
273 
GetNonVolatileDirectory(base::FilePath * path) const274 bool HardwareChromeOS::GetNonVolatileDirectory(base::FilePath* path) const {
275   *path = base::FilePath(constants::kNonVolatileDirectory);
276   return true;
277 }
278 
GetPowerwashSafeDirectory(base::FilePath * path) const279 bool HardwareChromeOS::GetPowerwashSafeDirectory(base::FilePath* path) const {
280   *path = base::FilePath(kPowerwashSafeDirectory);
281   return true;
282 }
283 
GetBuildTimestamp() const284 int64_t HardwareChromeOS::GetBuildTimestamp() const {
285   // TODO(senj): implement this in Chrome OS.
286   return 0;
287 }
288 
LoadConfig(const string & root_prefix,bool normal_mode)289 void HardwareChromeOS::LoadConfig(const string& root_prefix, bool normal_mode) {
290   brillo::KeyValueStore store;
291 
292   if (normal_mode) {
293     store.Load(base::FilePath(root_prefix + kConfigFilePath));
294   } else {
295     if (store.Load(base::FilePath(root_prefix + kStatefulPartition +
296                                   kConfigFilePath))) {
297       LOG(INFO) << "UpdateManager Config loaded from stateful partition.";
298     } else {
299       store.Load(base::FilePath(root_prefix + kConfigFilePath));
300     }
301   }
302 
303   if (!store.GetBoolean(kConfigOptsIsOOBEEnabled, &is_oobe_enabled_))
304     is_oobe_enabled_ = true;  // Default value.
305 }
306 
GetFirstActiveOmahaPingSent() const307 bool HardwareChromeOS::GetFirstActiveOmahaPingSent() const {
308   string active_ping_str;
309   if (!utils::GetVpdValue(kActivePingKey, &active_ping_str)) {
310     return false;
311   }
312 
313   int active_ping;
314   if (active_ping_str.empty() ||
315       !base::StringToInt(active_ping_str, &active_ping)) {
316     LOG(INFO) << "Failed to parse active_ping value: " << active_ping_str;
317     return false;
318   }
319   return static_cast<bool>(active_ping);
320 }
321 
SetFirstActiveOmahaPingSent()322 bool HardwareChromeOS::SetFirstActiveOmahaPingSent() {
323   int exit_code = 0;
324   string output, error;
325   vector<string> vpd_set_cmd = {
326       "vpd", "-i", "RW_VPD", "-s", string(kActivePingKey) + "=1"};
327   if (!Subprocess::SynchronousExec(vpd_set_cmd, &exit_code, &output, &error) ||
328       exit_code) {
329     LOG(ERROR) << "Failed to set vpd key for " << kActivePingKey
330                << " with exit code: " << exit_code << " with output: " << output
331                << " and error: " << error;
332     return false;
333   } else if (!error.empty()) {
334     LOG(INFO) << "vpd succeeded but with error logs: " << error;
335   }
336 
337   vector<string> vpd_dump_cmd = {"dump_vpd_log", "--force"};
338   if (!Subprocess::SynchronousExec(vpd_dump_cmd, &exit_code, &output, &error) ||
339       exit_code) {
340     LOG(ERROR) << "Failed to cache " << kActivePingKey << " using dump_vpd_log"
341                << " with exit code: " << exit_code << " with output: " << output
342                << " and error: " << error;
343     return false;
344   } else if (!error.empty()) {
345     LOG(INFO) << "dump_vpd_log succeeded but with error logs: " << error;
346   }
347   return true;
348 }
349 
SetWarmReset(bool warm_reset)350 void HardwareChromeOS::SetWarmReset(bool warm_reset) {}
351 
SetVbmetaDigestForInactiveSlot(bool reset)352 void HardwareChromeOS::SetVbmetaDigestForInactiveSlot(bool reset) {}
353 
GetVersionForLogging(const std::string & partition_name) const354 std::string HardwareChromeOS::GetVersionForLogging(
355     const std::string& partition_name) const {
356   // TODO(zhangkelvin) Implement per-partition timestamp for Chrome OS.
357   return "";
358 }
359 
IsPartitionUpdateValid(const std::string & partition_name,const std::string & new_version) const360 ErrorCode HardwareChromeOS::IsPartitionUpdateValid(
361     const std::string& partition_name, const std::string& new_version) const {
362   // TODO(zhangkelvin) Implement per-partition timestamp for Chrome OS.
363   return ErrorCode::kSuccess;
364 }
365 
GetPartitionMountOptions(const std::string & partition_name) const366 const char* HardwareChromeOS::GetPartitionMountOptions(
367     const std::string& partition_name) const {
368   return "";
369 }
370 
371 }  // namespace chromeos_update_engine
372