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/hardware_chromeos.h"
18 
19 #include <base/files/file_util.h>
20 #include <base/logging.h>
21 #include <base/strings/string_number_conversions.h>
22 #include <base/strings/string_util.h>
23 #include <brillo/make_unique_ptr.h>
24 #include <vboot/crossystem.h>
25 
26 extern "C" {
27 #include "vboot/vboot_host.h"
28 }
29 
30 #include "update_engine/common/hardware.h"
31 #include "update_engine/common/hwid_override.h"
32 #include "update_engine/common/platform_constants.h"
33 #include "update_engine/common/subprocess.h"
34 #include "update_engine/common/utils.h"
35 
36 using std::string;
37 using std::vector;
38 
39 namespace {
40 
41 const char kOOBECompletedMarker[] = "/home/chronos/.oobe_completed";
42 
43 // The stateful directory used by update_engine to store powerwash-safe files.
44 // The files stored here must be whitelisted in the powerwash scripts.
45 const char kPowerwashSafeDirectory[] =
46     "/mnt/stateful_partition/unencrypted/preserve";
47 
48 // The powerwash_count marker file contains the number of times the device was
49 // powerwashed. This value is incremented by the clobber-state script when
50 // a powerwash is performed.
51 const char kPowerwashCountMarker[] = "powerwash_count";
52 
53 }  // namespace
54 
55 namespace chromeos_update_engine {
56 
57 namespace hardware {
58 
59 // Factory defined in hardware.h.
CreateHardware()60 std::unique_ptr<HardwareInterface> CreateHardware() {
61   return brillo::make_unique_ptr(new HardwareChromeOS());
62 }
63 
64 }  // namespace hardware
65 
IsOfficialBuild() const66 bool HardwareChromeOS::IsOfficialBuild() const {
67   return VbGetSystemPropertyInt("debug_build") == 0;
68 }
69 
IsNormalBootMode() const70 bool HardwareChromeOS::IsNormalBootMode() const {
71   bool dev_mode = VbGetSystemPropertyInt("devsw_boot") != 0;
72   return !dev_mode;
73 }
74 
IsOOBEComplete(base::Time * out_time_of_oobe) const75 bool HardwareChromeOS::IsOOBEComplete(base::Time* out_time_of_oobe) const {
76   struct stat statbuf;
77   if (stat(kOOBECompletedMarker, &statbuf) != 0) {
78     if (errno != ENOENT) {
79       PLOG(ERROR) << "Error getting information about "
80                   << kOOBECompletedMarker;
81     }
82     return false;
83   }
84 
85   if (out_time_of_oobe != nullptr)
86     *out_time_of_oobe = base::Time::FromTimeT(statbuf.st_mtime);
87   return true;
88 }
89 
ReadValueFromCrosSystem(const string & key)90 static string ReadValueFromCrosSystem(const string& key) {
91   char value_buffer[VB_MAX_STRING_PROPERTY];
92 
93   const char* rv = VbGetSystemPropertyString(key.c_str(), value_buffer,
94                                              sizeof(value_buffer));
95   if (rv != nullptr) {
96     string return_value(value_buffer);
97     base::TrimWhitespaceASCII(return_value, base::TRIM_ALL, &return_value);
98     return return_value;
99   }
100 
101   LOG(ERROR) << "Unable to read crossystem key " << key;
102   return "";
103 }
104 
GetHardwareClass() const105 string HardwareChromeOS::GetHardwareClass() const {
106   if (USE_HWID_OVERRIDE) {
107     return HwidOverride::Read(base::FilePath("/"));
108   }
109   return ReadValueFromCrosSystem("hwid");
110 }
111 
GetFirmwareVersion() const112 string HardwareChromeOS::GetFirmwareVersion() const {
113   return ReadValueFromCrosSystem("fwid");
114 }
115 
GetECVersion() const116 string HardwareChromeOS::GetECVersion() const {
117   string input_line;
118   int exit_code = 0;
119   vector<string> cmd = {"/usr/sbin/mosys", "-k", "ec", "info"};
120 
121   bool success = Subprocess::SynchronousExec(cmd, &exit_code, &input_line);
122   if (!success || exit_code) {
123     LOG(ERROR) << "Unable to read ec info from mosys (" << exit_code << ")";
124     return "";
125   }
126 
127   return utils::ParseECVersion(input_line);
128 }
129 
GetPowerwashCount() const130 int HardwareChromeOS::GetPowerwashCount() const {
131   int powerwash_count;
132   base::FilePath marker_path = base::FilePath(kPowerwashSafeDirectory).Append(
133       kPowerwashCountMarker);
134   string contents;
135   if (!utils::ReadFile(marker_path.value(), &contents))
136     return -1;
137   base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
138   if (!base::StringToInt(contents, &powerwash_count))
139     return -1;
140   return powerwash_count;
141 }
142 
GetNonVolatileDirectory(base::FilePath * path) const143 bool HardwareChromeOS::GetNonVolatileDirectory(base::FilePath* path) const {
144   *path = base::FilePath(constants::kNonVolatileDirectory);
145   return true;
146 }
147 
GetPowerwashSafeDirectory(base::FilePath * path) const148 bool HardwareChromeOS::GetPowerwashSafeDirectory(base::FilePath* path) const {
149   *path = base::FilePath(kPowerwashSafeDirectory);
150   return true;
151 }
152 
153 }  // namespace chromeos_update_engine
154