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.
WriteBootloaderRecoveryMessage(const string & message)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.
CreateHardware()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
IsOfficialBuild() const115 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
IsNormalBootMode() const127 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
AreDevFeaturesEnabled() const135 bool HardwareAndroid::AreDevFeaturesEnabled() const {
136 return !IsNormalBootMode();
137 }
138
IsOOBEEnabled() const139 bool HardwareAndroid::IsOOBEEnabled() const {
140 // No OOBE flow blocking updates for Android-based boards.
141 return false;
142 }
143
IsOOBEComplete(base::Time * out_time_of_oobe) const144 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
GetHardwareClass() const151 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
GetFirmwareVersion() const162 string HardwareAndroid::GetFirmwareVersion() const {
163 char bootloader[PROPERTY_VALUE_MAX];
164 property_get(kPropBootBootloader, bootloader, "");
165 return bootloader;
166 }
167
GetECVersion() const168 string HardwareAndroid::GetECVersion() const {
169 char baseband[PROPERTY_VALUE_MAX];
170 property_get(kPropBootBaseband, baseband, "");
171 return baseband;
172 }
173
GetPowerwashCount() const174 int HardwareAndroid::GetPowerwashCount() const {
175 LOG(WARNING) << "STUB: Assuming no factory reset was performed.";
176 return 0;
177 }
178
SchedulePowerwash()179 bool HardwareAndroid::SchedulePowerwash() {
180 LOG(INFO) << "Scheduling a powerwash to BCB.";
181 return WriteBootloaderRecoveryMessage(kAndroidRecoveryPowerwashCommand);
182 }
183
CancelPowerwash()184 bool HardwareAndroid::CancelPowerwash() {
185 return WriteBootloaderRecoveryMessage("");
186 }
187
GetNonVolatileDirectory(base::FilePath * path) const188 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
GetPowerwashSafeDirectory(base::FilePath * path) const198 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