blob: 51585b3c22d07ad75ce228f25f9b3ed37dd6bc44 [file] [log] [blame]
Hridya Valsarajudea91b42018-07-17 11:14:01 -07001/*
2 * Copyright (C) 2018 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 "commands.h"
18
19#include <sys/socket.h>
20#include <sys/un.h>
21
22#include <android-base/logging.h>
23#include <android-base/parseint.h>
24#include <android-base/properties.h>
25#include <android-base/stringprintf.h>
26#include <android-base/strings.h>
27#include <android-base/unique_fd.h>
28#include <cutils/android_reboot.h>
David Anderson12211d12018-07-24 15:21:20 -070029#include <ext4_utils/wipe.h>
David Anderson0d4277d2018-07-31 13:27:37 -070030#include <liblp/builder.h>
31#include <liblp/liblp.h>
32#include <uuid/uuid.h>
Hridya Valsarajudea91b42018-07-17 11:14:01 -070033
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070034#include "constants.h"
Hridya Valsarajudea91b42018-07-17 11:14:01 -070035#include "fastboot_device.h"
David Anderson12211d12018-07-24 15:21:20 -070036#include "flashing.h"
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070037#include "utility.h"
38
39using ::android::hardware::hidl_string;
40using ::android::hardware::boot::V1_0::BoolResult;
41using ::android::hardware::boot::V1_0::CommandResult;
42using ::android::hardware::boot::V1_0::Slot;
Hridya Valsarajua15fe312018-09-14 13:58:21 -070043using ::android::hardware::fastboot::V1_0::Result;
44using ::android::hardware::fastboot::V1_0::Status;
45
David Anderson0d4277d2018-07-31 13:27:37 -070046using namespace android::fs_mgr;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070047
David Anderson0f626632018-08-31 16:44:25 -070048struct VariableHandlers {
49 // Callback to retrieve the value of a single variable.
50 std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)> get;
51 // Callback to retrieve all possible argument combinations, for getvar all.
52 std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args;
53};
54
55static void GetAllVars(FastbootDevice* device, const std::string& name,
56 const VariableHandlers& handlers) {
57 if (!handlers.get_all_args) {
58 std::string message;
59 if (!handlers.get(device, std::vector<std::string>(), &message)) {
60 return;
61 }
62 device->WriteInfo(android::base::StringPrintf("%s:%s", name.c_str(), message.c_str()));
63 return;
64 }
65
66 auto all_args = handlers.get_all_args(device);
67 for (const auto& args : all_args) {
68 std::string message;
69 if (!handlers.get(device, args, &message)) {
70 continue;
71 }
72 std::string arg_string = android::base::Join(args, ":");
73 device->WriteInfo(android::base::StringPrintf("%s:%s:%s", name.c_str(), arg_string.c_str(),
74 message.c_str()));
75 }
76}
77
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070078bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
David Anderson0f626632018-08-31 16:44:25 -070079 const std::unordered_map<std::string, VariableHandlers> kVariableMap = {
80 {FB_VAR_VERSION, {GetVersion, nullptr}},
81 {FB_VAR_VERSION_BOOTLOADER, {GetBootloaderVersion, nullptr}},
82 {FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}},
83 {FB_VAR_PRODUCT, {GetProduct, nullptr}},
84 {FB_VAR_SERIALNO, {GetSerial, nullptr}},
Hridya Valsaraju4af80902018-09-26 13:08:16 -070085 {FB_VAR_VARIANT, {GetVariant, nullptr}},
David Anderson0f626632018-08-31 16:44:25 -070086 {FB_VAR_SECURE, {GetSecure, nullptr}},
87 {FB_VAR_UNLOCKED, {GetUnlocked, nullptr}},
88 {FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}},
89 {FB_VAR_CURRENT_SLOT, {::GetCurrentSlot, nullptr}},
90 {FB_VAR_SLOT_COUNT, {GetSlotCount, nullptr}},
91 {FB_VAR_HAS_SLOT, {GetHasSlot, GetAllPartitionArgsNoSlot}},
92 {FB_VAR_SLOT_SUCCESSFUL, {GetSlotSuccessful, nullptr}},
93 {FB_VAR_SLOT_UNBOOTABLE, {GetSlotUnbootable, nullptr}},
94 {FB_VAR_PARTITION_SIZE, {GetPartitionSize, GetAllPartitionArgsWithSlot}},
Hridya Valsarajubf9f8d12018-09-05 16:57:24 -070095 {FB_VAR_PARTITION_TYPE, {GetPartitionType, GetAllPartitionArgsWithSlot}},
David Anderson0f626632018-08-31 16:44:25 -070096 {FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}},
David Andersonc091c172018-09-04 18:11:03 -070097 {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}},
Hridya Valsaraju7c9bbe92018-09-27 10:41:01 -070098 {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}},
Hridya Valsaraju47658ca2018-09-28 11:41:22 -070099 {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
Hridya Valsarajua534a5a2018-10-03 15:53:22 -0700100 {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}},
David Andersonc091c172018-09-04 18:11:03 -0700101 {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}};
David Anderson0f626632018-08-31 16:44:25 -0700102
103 if (args.size() < 2) {
104 return device->WriteFail("Missing argument");
105 }
106
107 // Special case: return all variables that we can.
108 if (args[1] == "all") {
109 for (const auto& [name, handlers] : kVariableMap) {
110 GetAllVars(device, name, handlers);
111 }
112 return device->WriteOkay("");
113 }
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700114
115 // args[0] is command name, args[1] is variable.
116 auto found_variable = kVariableMap.find(args[1]);
117 if (found_variable == kVariableMap.end()) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700118 return device->WriteFail("Unknown variable");
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700119 }
120
David Anderson1fb3fd72018-08-31 14:40:22 -0700121 std::string message;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700122 std::vector<std::string> getvar_args(args.begin() + 2, args.end());
David Anderson0f626632018-08-31 16:44:25 -0700123 if (!found_variable->second.get(device, getvar_args, &message)) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700124 return device->WriteFail(message);
125 }
126 return device->WriteOkay(message);
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700127}
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700128
David Anderson12211d12018-07-24 15:21:20 -0700129bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
130 if (args.size() < 2) {
131 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
132 }
133 PartitionHandle handle;
134 if (!OpenPartition(device, args[1], &handle)) {
135 return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
136 }
137 if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
138 return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
139 }
140 return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
141}
142
Hridya Valsarajua15fe312018-09-14 13:58:21 -0700143bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args) {
144 auto fastboot_hal = device->fastboot_hal();
145 if (!fastboot_hal) {
146 return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL");
147 }
148
149 Result ret;
150 auto ret_val = fastboot_hal->doOemCommand(args[0], [&](Result result) { ret = result; });
151 if (!ret_val.isOk()) {
152 return device->WriteStatus(FastbootResult::FAIL, "Unable to do OEM command");
153 }
154 if (ret.status != Status::SUCCESS) {
155 return device->WriteStatus(FastbootResult::FAIL, ret.message);
156 }
157
158 return device->WriteStatus(FastbootResult::OKAY, ret.message);
159}
160
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700161bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
162 if (args.size() < 2) {
163 return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
164 }
165 // arg[0] is the command name, arg[1] contains size of data to be downloaded
166 unsigned int size;
167 if (!android::base::ParseUint("0x" + args[1], &size, UINT_MAX)) {
168 return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
169 }
David Anderson12211d12018-07-24 15:21:20 -0700170 device->download_data().resize(size);
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700171 if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
172 return false;
173 }
174
David Anderson12211d12018-07-24 15:21:20 -0700175 if (device->HandleData(true, &device->download_data())) {
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700176 return device->WriteStatus(FastbootResult::OKAY, "");
177 }
178
179 PLOG(ERROR) << "Couldn't download data";
180 return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
181}
182
David Anderson12211d12018-07-24 15:21:20 -0700183bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args) {
184 if (args.size() < 2) {
185 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
186 }
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700187
188 if (GetDeviceLockStatus()) {
189 return device->WriteStatus(FastbootResult::FAIL,
190 "Flashing is not allowed on locked devices");
191 }
192
David Anderson12211d12018-07-24 15:21:20 -0700193 int ret = Flash(device, args[1]);
194 if (ret < 0) {
195 return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
196 }
197 return device->WriteStatus(FastbootResult::OKAY, "Flashing succeeded");
198}
199
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700200bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args) {
201 if (args.size() < 2) {
202 return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
203 }
204
205 // Slot suffix needs to be between 'a' and 'z'.
206 Slot slot;
207 if (!GetSlotNumber(args[1], &slot)) {
208 return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
209 }
210
211 // Non-A/B devices will not have a boot control HAL.
212 auto boot_control_hal = device->boot_control_hal();
213 if (!boot_control_hal) {
214 return device->WriteStatus(FastbootResult::FAIL,
215 "Cannot set slot: boot control HAL absent");
216 }
217 if (slot >= boot_control_hal->getNumberSlots()) {
218 return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
219 }
220 CommandResult ret;
221 auto cb = [&ret](CommandResult result) { ret = result; };
222 auto result = boot_control_hal->setActiveBootSlot(slot, cb);
223 if (result.isOk() && ret.success) return device->WriteStatus(FastbootResult::OKAY, "");
224 return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700225}
226
227bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
228 auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
229 android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
230 device->CloseDevice();
231 TEMP_FAILURE_RETRY(pause());
232 return result;
233}
234
235bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
236 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
237 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
238 device->CloseDevice();
239 TEMP_FAILURE_RETRY(pause());
240 return result;
241}
242
243bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
244 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
245 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
246 device->CloseDevice();
247 TEMP_FAILURE_RETRY(pause());
248 return result;
249}
250
251bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
252 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
253 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
254 device->CloseDevice();
255 TEMP_FAILURE_RETRY(pause());
256 return result;
257}
258
259static bool EnterRecovery() {
260 const char msg_switch_to_recovery = 'r';
261
262 android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
263 if (sock < 0) {
264 PLOG(ERROR) << "Couldn't create sock";
265 return false;
266 }
267
268 struct sockaddr_un addr = {.sun_family = AF_UNIX};
269 strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
270 if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
271 PLOG(ERROR) << "Couldn't connect to recovery";
272 return false;
273 }
274 // Switch to recovery will not update the boot reason since it does not
275 // require a reboot.
276 auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
277 if (ret != sizeof(msg_switch_to_recovery)) {
278 PLOG(ERROR) << "Couldn't write message to switch to recovery";
279 return false;
280 }
281
282 return true;
283}
284
285bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
286 auto status = true;
287 if (EnterRecovery()) {
288 status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
289 } else {
290 status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
291 }
292 device->CloseDevice();
293 TEMP_FAILURE_RETRY(pause());
294 return status;
295}
David Anderson0d4277d2018-07-31 13:27:37 -0700296
297// Helper class for opening a handle to a MetadataBuilder and writing the new
298// partition table to the same place it was read.
299class PartitionBuilder {
300 public:
301 explicit PartitionBuilder(FastbootDevice* device);
302
303 bool Write();
304 bool Valid() const { return !!builder_; }
305 MetadataBuilder* operator->() const { return builder_.get(); }
306
307 private:
308 std::string super_device_;
309 uint32_t slot_number_;
310 std::unique_ptr<MetadataBuilder> builder_;
311};
312
313PartitionBuilder::PartitionBuilder(FastbootDevice* device) {
314 auto super_device = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
315 if (!super_device) {
316 return;
317 }
318 super_device_ = *super_device;
319
320 std::string slot = device->GetCurrentSlot();
321 slot_number_ = SlotNumberForSlotSuffix(slot);
322 builder_ = MetadataBuilder::New(super_device_, slot_number_);
323}
324
325bool PartitionBuilder::Write() {
326 std::unique_ptr<LpMetadata> metadata = builder_->Export();
327 if (!metadata) {
328 return false;
329 }
330 return UpdatePartitionTable(super_device_, *metadata.get(), slot_number_);
331}
332
333bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
334 if (args.size() < 3) {
335 return device->WriteFail("Invalid partition name and size");
336 }
337
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700338 if (GetDeviceLockStatus()) {
339 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
340 }
341
David Anderson0d4277d2018-07-31 13:27:37 -0700342 uint64_t partition_size;
343 std::string partition_name = args[1];
344 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
345 return device->WriteFail("Invalid partition size");
346 }
347
348 PartitionBuilder builder(device);
349 if (!builder.Valid()) {
350 return device->WriteFail("Could not open super partition");
351 }
352 // TODO(112433293) Disallow if the name is in the physical table as well.
353 if (builder->FindPartition(partition_name)) {
354 return device->WriteFail("Partition already exists");
355 }
356
357 // Make a random UUID, since they're not currently used.
358 uuid_t uuid;
359 char uuid_str[37];
360 uuid_generate_random(uuid);
361 uuid_unparse(uuid, uuid_str);
362
363 Partition* partition = builder->AddPartition(partition_name, uuid_str, 0);
364 if (!partition) {
365 return device->WriteFail("Failed to add partition");
366 }
367 if (!builder->ResizePartition(partition, partition_size)) {
368 builder->RemovePartition(partition_name);
369 return device->WriteFail("Not enough space for partition");
370 }
371 if (!builder.Write()) {
372 return device->WriteFail("Failed to write partition table");
373 }
374 return device->WriteOkay("Partition created");
375}
376
377bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
378 if (args.size() < 2) {
379 return device->WriteFail("Invalid partition name and size");
380 }
381
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700382 if (GetDeviceLockStatus()) {
383 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
384 }
385
David Anderson0d4277d2018-07-31 13:27:37 -0700386 PartitionBuilder builder(device);
387 if (!builder.Valid()) {
388 return device->WriteFail("Could not open super partition");
389 }
390 builder->RemovePartition(args[1]);
391 if (!builder.Write()) {
392 return device->WriteFail("Failed to write partition table");
393 }
394 return device->WriteOkay("Partition deleted");
395}
396
397bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
398 if (args.size() < 3) {
399 return device->WriteFail("Invalid partition name and size");
400 }
401
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700402 if (GetDeviceLockStatus()) {
403 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
404 }
405
David Anderson0d4277d2018-07-31 13:27:37 -0700406 uint64_t partition_size;
407 std::string partition_name = args[1];
408 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
409 return device->WriteFail("Invalid partition size");
410 }
411
412 PartitionBuilder builder(device);
413 if (!builder.Valid()) {
414 return device->WriteFail("Could not open super partition");
415 }
416
417 Partition* partition = builder->FindPartition(partition_name);
418 if (!partition) {
419 return device->WriteFail("Partition does not exist");
420 }
421 if (!builder->ResizePartition(partition, partition_size)) {
422 return device->WriteFail("Not enough space to resize partition");
423 }
424 if (!builder.Write()) {
425 return device->WriteFail("Failed to write partition table");
426 }
427 return device->WriteOkay("Partition resized");
428}
David Anderson38b3c7a2018-08-15 16:27:42 -0700429
430bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args) {
431 if (args.size() < 2) {
432 return device->WriteFail("Invalid arguments");
433 }
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700434
435 if (GetDeviceLockStatus()) {
436 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
437 }
438
David Anderson38b3c7a2018-08-15 16:27:42 -0700439 bool wipe = (args.size() >= 3 && args[2] == "wipe");
440 return UpdateSuper(device, args[1], wipe);
441}