Home | History | Annotate | Download | only in update_engine
      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_path.h>
     20 #include <base/files/file_util.h>
     21 #include <base/logging.h>
     22 #include <base/strings/string_number_conversions.h>
     23 #include <base/strings/string_util.h>
     24 #include <brillo/key_value_store.h>
     25 #include <brillo/make_unique_ptr.h>
     26 #include <debugd/dbus-constants.h>
     27 #include <vboot/crossystem.h>
     28 
     29 extern "C" {
     30 #include "vboot/vboot_host.h"
     31 }
     32 
     33 #include "update_engine/common/constants.h"
     34 #include "update_engine/common/hardware.h"
     35 #include "update_engine/common/hwid_override.h"
     36 #include "update_engine/common/platform_constants.h"
     37 #include "update_engine/common/subprocess.h"
     38 #include "update_engine/common/utils.h"
     39 #include "update_engine/dbus_connection.h"
     40 
     41 using std::string;
     42 using std::vector;
     43 
     44 namespace {
     45 
     46 const char kOOBECompletedMarker[] = "/home/chronos/.oobe_completed";
     47 
     48 // The stateful directory used by update_engine to store powerwash-safe files.
     49 // The files stored here must be whitelisted in the powerwash scripts.
     50 const char kPowerwashSafeDirectory[] =
     51     "/mnt/stateful_partition/unencrypted/preserve";
     52 
     53 // The powerwash_count marker file contains the number of times the device was
     54 // powerwashed. This value is incremented by the clobber-state script when
     55 // a powerwash is performed.
     56 const char kPowerwashCountMarker[] = "powerwash_count";
     57 
     58 // The name of the marker file used to trigger powerwash when post-install
     59 // completes successfully so that the device is powerwashed on next reboot.
     60 const char kPowerwashMarkerFile[] =
     61     "/mnt/stateful_partition/factory_install_reset";
     62 
     63 // The contents of the powerwash marker file.
     64 const char kPowerwashCommand[] = "safe fast keepimg reason=update_engine\n";
     65 
     66 // UpdateManager config path.
     67 const char* kConfigFilePath = "/etc/update_manager.conf";
     68 
     69 // UpdateManager config options:
     70 const char* kConfigOptsIsOOBEEnabled = "is_oobe_enabled";
     71 
     72 }  // namespace
     73 
     74 namespace chromeos_update_engine {
     75 
     76 namespace hardware {
     77 
     78 // Factory defined in hardware.h.
     79 std::unique_ptr<HardwareInterface> CreateHardware() {
     80   std::unique_ptr<HardwareChromeOS> hardware(new HardwareChromeOS());
     81   hardware->Init();
     82   return std::move(hardware);
     83 }
     84 
     85 }  // namespace hardware
     86 
     87 void HardwareChromeOS::Init() {
     88   LoadConfig("" /* root_prefix */, IsNormalBootMode());
     89   debugd_proxy_.reset(
     90       new org::chromium::debugdProxy(DBusConnection::Get()->GetDBus()));
     91 }
     92 
     93 bool HardwareChromeOS::IsOfficialBuild() const {
     94   return VbGetSystemPropertyInt("debug_build") == 0;
     95 }
     96 
     97 bool HardwareChromeOS::IsNormalBootMode() const {
     98   bool dev_mode = VbGetSystemPropertyInt("devsw_boot") != 0;
     99   return !dev_mode;
    100 }
    101 
    102 bool HardwareChromeOS::AreDevFeaturesEnabled() const {
    103   // Even though the debugd tools are also gated on devmode, checking here can
    104   // save us a D-Bus call so it's worth doing explicitly.
    105   if (IsNormalBootMode())
    106     return false;
    107 
    108   int32_t dev_features = debugd::DEV_FEATURES_DISABLED;
    109   brillo::ErrorPtr error;
    110   // Some boards may not include debugd so it's expected that this may fail,
    111   // in which case we treat it as disabled.
    112   if (debugd_proxy_ && debugd_proxy_->QueryDevFeatures(&dev_features, &error) &&
    113       !(dev_features & debugd::DEV_FEATURES_DISABLED)) {
    114     LOG(INFO) << "Debugd dev tools enabled.";
    115     return true;
    116   }
    117   return false;
    118 }
    119 
    120 bool HardwareChromeOS::IsOOBEEnabled() const {
    121   return is_oobe_enabled_;
    122 }
    123 
    124 bool HardwareChromeOS::IsOOBEComplete(base::Time* out_time_of_oobe) const {
    125   if (!is_oobe_enabled_) {
    126     LOG(WARNING) << "OOBE is not enabled but IsOOBEComplete() was called";
    127   }
    128   struct stat statbuf;
    129   if (stat(kOOBECompletedMarker, &statbuf) != 0) {
    130     if (errno != ENOENT) {
    131       PLOG(ERROR) << "Error getting information about "
    132                   << kOOBECompletedMarker;
    133     }
    134     return false;
    135   }
    136 
    137   if (out_time_of_oobe != nullptr)
    138     *out_time_of_oobe = base::Time::FromTimeT(statbuf.st_mtime);
    139   return true;
    140 }
    141 
    142 static string ReadValueFromCrosSystem(const string& key) {
    143   char value_buffer[VB_MAX_STRING_PROPERTY];
    144 
    145   const char* rv = VbGetSystemPropertyString(key.c_str(), value_buffer,
    146                                              sizeof(value_buffer));
    147   if (rv != nullptr) {
    148     string return_value(value_buffer);
    149     base::TrimWhitespaceASCII(return_value, base::TRIM_ALL, &return_value);
    150     return return_value;
    151   }
    152 
    153   LOG(ERROR) << "Unable to read crossystem key " << key;
    154   return "";
    155 }
    156 
    157 string HardwareChromeOS::GetHardwareClass() const {
    158   if (USE_HWID_OVERRIDE) {
    159     return HwidOverride::Read(base::FilePath("/"));
    160   }
    161   return ReadValueFromCrosSystem("hwid");
    162 }
    163 
    164 string HardwareChromeOS::GetFirmwareVersion() const {
    165   return ReadValueFromCrosSystem("fwid");
    166 }
    167 
    168 string HardwareChromeOS::GetECVersion() const {
    169   string input_line;
    170   int exit_code = 0;
    171   vector<string> cmd = {"/usr/sbin/mosys", "-k", "ec", "info"};
    172 
    173   bool success = Subprocess::SynchronousExec(cmd, &exit_code, &input_line);
    174   if (!success || exit_code) {
    175     LOG(ERROR) << "Unable to read ec info from mosys (" << exit_code << ")";
    176     return "";
    177   }
    178 
    179   return utils::ParseECVersion(input_line);
    180 }
    181 
    182 int HardwareChromeOS::GetPowerwashCount() const {
    183   int powerwash_count;
    184   base::FilePath marker_path = base::FilePath(kPowerwashSafeDirectory).Append(
    185       kPowerwashCountMarker);
    186   string contents;
    187   if (!utils::ReadFile(marker_path.value(), &contents))
    188     return -1;
    189   base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
    190   if (!base::StringToInt(contents, &powerwash_count))
    191     return -1;
    192   return powerwash_count;
    193 }
    194 
    195 bool HardwareChromeOS::SchedulePowerwash() {
    196   bool result = utils::WriteFile(
    197       kPowerwashMarkerFile, kPowerwashCommand, strlen(kPowerwashCommand));
    198   if (result) {
    199     LOG(INFO) << "Created " << kPowerwashMarkerFile
    200               << " to powerwash on next reboot";
    201   } else {
    202     PLOG(ERROR) << "Error in creating powerwash marker file: "
    203                 << kPowerwashMarkerFile;
    204   }
    205 
    206   return result;
    207 }
    208 
    209 bool HardwareChromeOS::CancelPowerwash() {
    210   bool result = base::DeleteFile(base::FilePath(kPowerwashMarkerFile), false);
    211 
    212   if (result) {
    213     LOG(INFO) << "Successfully deleted the powerwash marker file : "
    214               << kPowerwashMarkerFile;
    215   } else {
    216     PLOG(ERROR) << "Could not delete the powerwash marker file : "
    217                 << kPowerwashMarkerFile;
    218   }
    219 
    220   return result;
    221 }
    222 
    223 bool HardwareChromeOS::GetNonVolatileDirectory(base::FilePath* path) const {
    224   *path = base::FilePath(constants::kNonVolatileDirectory);
    225   return true;
    226 }
    227 
    228 bool HardwareChromeOS::GetPowerwashSafeDirectory(base::FilePath* path) const {
    229   *path = base::FilePath(kPowerwashSafeDirectory);
    230   return true;
    231 }
    232 
    233 void HardwareChromeOS::LoadConfig(const string& root_prefix, bool normal_mode) {
    234   brillo::KeyValueStore store;
    235 
    236   if (normal_mode) {
    237     store.Load(base::FilePath(root_prefix + kConfigFilePath));
    238   } else {
    239     if (store.Load(base::FilePath(root_prefix + kStatefulPartition +
    240                                   kConfigFilePath))) {
    241       LOG(INFO) << "UpdateManager Config loaded from stateful partition.";
    242     } else {
    243       store.Load(base::FilePath(root_prefix + kConfigFilePath));
    244     }
    245   }
    246 
    247   if (!store.GetBoolean(kConfigOptsIsOOBEEnabled, &is_oobe_enabled_))
    248     is_oobe_enabled_ = true;  // Default value.
    249 }
    250 
    251 }  // namespace chromeos_update_engine
    252