Home | History | Annotate | Download | only in update_engine
      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/hardware_android.h"
     18 
     19 #include <fcntl.h>
     20 #include <sys/stat.h>
     21 #include <sys/types.h>
     22 
     23 #include <algorithm>
     24 
     25 #include <bootloader.h>
     26 
     27 #include <base/files/file_util.h>
     28 #include <base/strings/stringprintf.h>
     29 #include <brillo/make_unique_ptr.h>
     30 #include <cutils/properties.h>
     31 
     32 #include "update_engine/common/hardware.h"
     33 #include "update_engine/common/platform_constants.h"
     34 #include "update_engine/common/utils.h"
     35 #include "update_engine/utils_android.h"
     36 
     37 using std::string;
     38 
     39 namespace chromeos_update_engine {
     40 
     41 namespace {
     42 
     43 // The powerwash arguments passed to recovery. Arguments are separated by \n.
     44 const char kAndroidRecoveryPowerwashCommand[] =
     45     "recovery\n"
     46     "--wipe_data\n"
     47     "--reason=wipe_data_from_ota\n";
     48 
     49 // Android properties that identify the hardware and potentially non-updatable
     50 // parts of the bootloader (such as the bootloader version and the baseband
     51 // version).
     52 const char kPropBootBootloader[] = "ro.boot.bootloader";
     53 const char kPropBootBaseband[] = "ro.boot.baseband";
     54 const char kPropProductManufacturer[] = "ro.product.manufacturer";
     55 const char kPropBootHardwareSKU[] = "ro.boot.hardware.sku";
     56 const char kPropBootRevision[] = "ro.boot.revision";
     57 
     58 // Write a recovery command line |message| to the BCB. The arguments to recovery
     59 // must be separated by '\n'. An empty string will erase the BCB.
     60 bool WriteBootloaderRecoveryMessage(const string& message) {
     61   base::FilePath misc_device;
     62   if (!utils::DeviceForMountPoint("/misc", &misc_device))
     63     return false;
     64 
     65   // Setup a bootloader_message with just the command and recovery fields set.
     66   bootloader_message boot = {};
     67   if (!message.empty()) {
     68     strncpy(boot.command, "boot-recovery", sizeof(boot.command) - 1);
     69     memcpy(boot.recovery,
     70            message.data(),
     71            std::min(message.size(), sizeof(boot.recovery) - 1));
     72   }
     73 
     74   int fd =
     75       HANDLE_EINTR(open(misc_device.value().c_str(), O_WRONLY | O_SYNC, 0600));
     76   if (fd < 0) {
     77     PLOG(ERROR) << "Opening misc";
     78     return false;
     79   }
     80   ScopedFdCloser fd_closer(&fd);
     81   // We only re-write the first part of the bootloader_message, up to and
     82   // including the recovery message.
     83   size_t boot_size =
     84       offsetof(bootloader_message, recovery) + sizeof(boot.recovery);
     85   if (!utils::WriteAll(fd, &boot, boot_size)) {
     86     PLOG(ERROR) << "Writing recovery command to misc";
     87     return false;
     88   }
     89   return true;
     90 }
     91 
     92 }  // namespace
     93 
     94 namespace hardware {
     95 
     96 // Factory defined in hardware.h.
     97 std::unique_ptr<HardwareInterface> CreateHardware() {
     98   return brillo::make_unique_ptr(new HardwareAndroid());
     99 }
    100 
    101 }  // namespace hardware
    102 
    103 // In Android there are normally three kinds of builds: eng, userdebug and user.
    104 // These builds target respectively a developer build, a debuggable version of
    105 // the final product and the pristine final product the end user will run.
    106 // Apart from the ro.build.type property name, they differ in the following
    107 // properties that characterize the builds:
    108 // * eng builds: ro.secure=0 and ro.debuggable=1
    109 // * userdebug builds: ro.secure=1 and ro.debuggable=1
    110 // * user builds: ro.secure=1 and ro.debuggable=0
    111 //
    112 // See IsOfficialBuild() and IsNormalMode() for the meaning of these options in
    113 // Android.
    114 
    115 bool HardwareAndroid::IsOfficialBuild() const {
    116   // We run an official build iff ro.secure == 1, because we expect the build to
    117   // behave like the end user product and check for updates. Note that while
    118   // developers are able to build "official builds" by just running "make user",
    119   // that will only result in a more restrictive environment. The important part
    120   // is that we don't produce and push "non-official" builds to the end user.
    121   //
    122   // In case of a non-bool value, we take the most restrictive option and
    123   // assume we are in an official-build.
    124   return property_get_bool("ro.secure", 1) != 0;
    125 }
    126 
    127 bool HardwareAndroid::IsNormalBootMode() const {
    128   // We are running in "dev-mode" iff ro.debuggable == 1. In dev-mode the
    129   // update_engine will allow extra developers options, such as providing a
    130   // different update URL. In case of error, we assume the build is in
    131   // normal-mode.
    132   return property_get_bool("ro.debuggable", 0) != 1;
    133 }
    134 
    135 bool HardwareAndroid::AreDevFeaturesEnabled() const {
    136   return !IsNormalBootMode();
    137 }
    138 
    139 bool HardwareAndroid::IsOOBEEnabled() const {
    140   // No OOBE flow blocking updates for Android-based boards.
    141   return false;
    142 }
    143 
    144 bool HardwareAndroid::IsOOBEComplete(base::Time* out_time_of_oobe) const {
    145   LOG(WARNING) << "OOBE is not enabled but IsOOBEComplete() called.";
    146   if (out_time_of_oobe)
    147     *out_time_of_oobe = base::Time();
    148   return true;
    149 }
    150 
    151 string HardwareAndroid::GetHardwareClass() const {
    152   char manufacturer[PROPERTY_VALUE_MAX];
    153   char sku[PROPERTY_VALUE_MAX];
    154   char revision[PROPERTY_VALUE_MAX];
    155   property_get(kPropBootHardwareSKU, sku, "");
    156   property_get(kPropProductManufacturer, manufacturer, "");
    157   property_get(kPropBootRevision, revision, "");
    158 
    159   return base::StringPrintf("%s:%s:%s", manufacturer, sku, revision);
    160 }
    161 
    162 string HardwareAndroid::GetFirmwareVersion() const {
    163   char bootloader[PROPERTY_VALUE_MAX];
    164   property_get(kPropBootBootloader, bootloader, "");
    165   return bootloader;
    166 }
    167 
    168 string HardwareAndroid::GetECVersion() const {
    169   char baseband[PROPERTY_VALUE_MAX];
    170   property_get(kPropBootBaseband, baseband, "");
    171   return baseband;
    172 }
    173 
    174 int HardwareAndroid::GetPowerwashCount() const {
    175   LOG(WARNING) << "STUB: Assuming no factory reset was performed.";
    176   return 0;
    177 }
    178 
    179 bool HardwareAndroid::SchedulePowerwash() {
    180   LOG(INFO) << "Scheduling a powerwash to BCB.";
    181   return WriteBootloaderRecoveryMessage(kAndroidRecoveryPowerwashCommand);
    182 }
    183 
    184 bool HardwareAndroid::CancelPowerwash() {
    185   return WriteBootloaderRecoveryMessage("");
    186 }
    187 
    188 bool HardwareAndroid::GetNonVolatileDirectory(base::FilePath* path) const {
    189   base::FilePath local_path(constants::kNonVolatileDirectory);
    190   if (!base::PathExists(local_path)) {
    191     LOG(ERROR) << "Non-volatile directory not found: " << local_path.value();
    192     return false;
    193   }
    194   *path = local_path;
    195   return true;
    196 }
    197 
    198 bool HardwareAndroid::GetPowerwashSafeDirectory(base::FilePath* path) const {
    199   // On Android, we don't have a directory persisted across powerwash.
    200   return false;
    201 }
    202 
    203 }  // namespace chromeos_update_engine
    204