blob: dfd5690628aac61253c52148a8107b7d77b2abc7 [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>
David Andersonab8f4662019-10-21 16:45:59 -070028#include <android/hardware/boot/1.1/IBootControl.h>
Hridya Valsarajudea91b42018-07-17 11:14:01 -070029#include <cutils/android_reboot.h>
David Anderson12211d12018-07-24 15:21:20 -070030#include <ext4_utils/wipe.h>
David Anderson5cbd2e42018-09-27 10:53:04 -070031#include <fs_mgr.h>
David Anderson3d782d52019-01-29 13:09:49 -080032#include <fs_mgr/roots.h>
David Anderson1d504e32019-01-15 14:38:20 -080033#include <libgsi/libgsi.h>
David Anderson0d4277d2018-07-31 13:27:37 -070034#include <liblp/builder.h>
35#include <liblp/liblp.h>
36#include <uuid/uuid.h>
Hridya Valsarajudea91b42018-07-17 11:14:01 -070037
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070038#include "constants.h"
Hridya Valsarajudea91b42018-07-17 11:14:01 -070039#include "fastboot_device.h"
David Anderson12211d12018-07-24 15:21:20 -070040#include "flashing.h"
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070041#include "utility.h"
42
David Anderson27475322019-06-11 14:00:08 -070043using android::fs_mgr::MetadataBuilder;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070044using ::android::hardware::hidl_string;
45using ::android::hardware::boot::V1_0::BoolResult;
46using ::android::hardware::boot::V1_0::CommandResult;
47using ::android::hardware::boot::V1_0::Slot;
David Andersonab8f4662019-10-21 16:45:59 -070048using ::android::hardware::boot::V1_1::MergeStatus;
Hridya Valsarajua15fe312018-09-14 13:58:21 -070049using ::android::hardware::fastboot::V1_0::Result;
50using ::android::hardware::fastboot::V1_0::Status;
David Andersonab8f4662019-10-21 16:45:59 -070051using IBootControl1_1 = ::android::hardware::boot::V1_1::IBootControl;
Hridya Valsarajua15fe312018-09-14 13:58:21 -070052
David Anderson0f626632018-08-31 16:44:25 -070053struct VariableHandlers {
54 // Callback to retrieve the value of a single variable.
55 std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)> get;
56 // Callback to retrieve all possible argument combinations, for getvar all.
57 std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args;
58};
59
60static void GetAllVars(FastbootDevice* device, const std::string& name,
61 const VariableHandlers& handlers) {
62 if (!handlers.get_all_args) {
63 std::string message;
64 if (!handlers.get(device, std::vector<std::string>(), &message)) {
65 return;
66 }
67 device->WriteInfo(android::base::StringPrintf("%s:%s", name.c_str(), message.c_str()));
68 return;
69 }
70
71 auto all_args = handlers.get_all_args(device);
72 for (const auto& args : all_args) {
73 std::string message;
74 if (!handlers.get(device, args, &message)) {
75 continue;
76 }
77 std::string arg_string = android::base::Join(args, ":");
78 device->WriteInfo(android::base::StringPrintf("%s:%s:%s", name.c_str(), arg_string.c_str(),
79 message.c_str()));
80 }
81}
82
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070083bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
David Anderson0f626632018-08-31 16:44:25 -070084 const std::unordered_map<std::string, VariableHandlers> kVariableMap = {
85 {FB_VAR_VERSION, {GetVersion, nullptr}},
86 {FB_VAR_VERSION_BOOTLOADER, {GetBootloaderVersion, nullptr}},
87 {FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}},
88 {FB_VAR_PRODUCT, {GetProduct, nullptr}},
89 {FB_VAR_SERIALNO, {GetSerial, nullptr}},
Hridya Valsaraju4af80902018-09-26 13:08:16 -070090 {FB_VAR_VARIANT, {GetVariant, nullptr}},
David Anderson0f626632018-08-31 16:44:25 -070091 {FB_VAR_SECURE, {GetSecure, nullptr}},
92 {FB_VAR_UNLOCKED, {GetUnlocked, nullptr}},
93 {FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}},
94 {FB_VAR_CURRENT_SLOT, {::GetCurrentSlot, nullptr}},
95 {FB_VAR_SLOT_COUNT, {GetSlotCount, nullptr}},
96 {FB_VAR_HAS_SLOT, {GetHasSlot, GetAllPartitionArgsNoSlot}},
97 {FB_VAR_SLOT_SUCCESSFUL, {GetSlotSuccessful, nullptr}},
98 {FB_VAR_SLOT_UNBOOTABLE, {GetSlotUnbootable, nullptr}},
David Anderson27475322019-06-11 14:00:08 -070099 {FB_VAR_PARTITION_SIZE, {GetPartitionSize, GetAllPartitionArgsWithSlot}},
Hridya Valsarajubf9f8d12018-09-05 16:57:24 -0700100 {FB_VAR_PARTITION_TYPE, {GetPartitionType, GetAllPartitionArgsWithSlot}},
David Anderson0f626632018-08-31 16:44:25 -0700101 {FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}},
David Andersonc091c172018-09-04 18:11:03 -0700102 {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}},
Hridya Valsaraju7c9bbe92018-09-27 10:41:01 -0700103 {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}},
Hridya Valsaraju47658ca2018-09-28 11:41:22 -0700104 {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
Hridya Valsarajua534a5a2018-10-03 15:53:22 -0700105 {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}},
David Anderson90fe0a42018-11-05 18:01:32 -0800106 {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}},
David Andersonab8f4662019-10-21 16:45:59 -0700107 {FB_VAR_SUPER_PARTITION_NAME, {GetSuperPartitionName, nullptr}},
108 {FB_VAR_SNAPSHOT_UPDATE_STATUS, {GetSnapshotUpdateStatus, nullptr}}};
David Anderson0f626632018-08-31 16:44:25 -0700109
110 if (args.size() < 2) {
111 return device->WriteFail("Missing argument");
112 }
113
114 // Special case: return all variables that we can.
115 if (args[1] == "all") {
116 for (const auto& [name, handlers] : kVariableMap) {
117 GetAllVars(device, name, handlers);
118 }
119 return device->WriteOkay("");
120 }
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700121
122 // args[0] is command name, args[1] is variable.
123 auto found_variable = kVariableMap.find(args[1]);
124 if (found_variable == kVariableMap.end()) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700125 return device->WriteFail("Unknown variable");
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700126 }
127
David Anderson1fb3fd72018-08-31 14:40:22 -0700128 std::string message;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700129 std::vector<std::string> getvar_args(args.begin() + 2, args.end());
David Anderson0f626632018-08-31 16:44:25 -0700130 if (!found_variable->second.get(device, getvar_args, &message)) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700131 return device->WriteFail(message);
132 }
133 return device->WriteOkay(message);
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700134}
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700135
David Anderson12211d12018-07-24 15:21:20 -0700136bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
137 if (args.size() < 2) {
138 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
139 }
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700140
141 if (GetDeviceLockStatus()) {
142 return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
143 }
144
David Anderson12211d12018-07-24 15:21:20 -0700145 PartitionHandle handle;
146 if (!OpenPartition(device, args[1], &handle)) {
147 return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
148 }
149 if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
150 return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
151 }
152 return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
153}
154
Hridya Valsarajua15fe312018-09-14 13:58:21 -0700155bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args) {
156 auto fastboot_hal = device->fastboot_hal();
157 if (!fastboot_hal) {
158 return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL");
159 }
160
161 Result ret;
162 auto ret_val = fastboot_hal->doOemCommand(args[0], [&](Result result) { ret = result; });
163 if (!ret_val.isOk()) {
164 return device->WriteStatus(FastbootResult::FAIL, "Unable to do OEM command");
165 }
166 if (ret.status != Status::SUCCESS) {
167 return device->WriteStatus(FastbootResult::FAIL, ret.message);
168 }
169
170 return device->WriteStatus(FastbootResult::OKAY, ret.message);
171}
172
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700173bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
174 if (args.size() < 2) {
175 return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
176 }
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700177
178 if (GetDeviceLockStatus()) {
179 return device->WriteStatus(FastbootResult::FAIL,
180 "Download is not allowed on locked devices");
181 }
182
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700183 // arg[0] is the command name, arg[1] contains size of data to be downloaded
184 unsigned int size;
Hridya Valsarajuaae84e82018-10-08 13:10:25 -0700185 if (!android::base::ParseUint("0x" + args[1], &size, kMaxDownloadSizeDefault)) {
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700186 return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
187 }
David Anderson12211d12018-07-24 15:21:20 -0700188 device->download_data().resize(size);
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700189 if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
190 return false;
191 }
192
David Anderson12211d12018-07-24 15:21:20 -0700193 if (device->HandleData(true, &device->download_data())) {
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700194 return device->WriteStatus(FastbootResult::OKAY, "");
195 }
196
197 PLOG(ERROR) << "Couldn't download data";
198 return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
199}
200
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700201bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args) {
202 if (args.size() < 2) {
203 return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
204 }
205
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700206 if (GetDeviceLockStatus()) {
207 return device->WriteStatus(FastbootResult::FAIL,
208 "set_active command is not allowed on locked devices");
209 }
210
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700211 // Slot suffix needs to be between 'a' and 'z'.
212 Slot slot;
213 if (!GetSlotNumber(args[1], &slot)) {
214 return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
215 }
216
217 // Non-A/B devices will not have a boot control HAL.
218 auto boot_control_hal = device->boot_control_hal();
219 if (!boot_control_hal) {
220 return device->WriteStatus(FastbootResult::FAIL,
221 "Cannot set slot: boot control HAL absent");
222 }
223 if (slot >= boot_control_hal->getNumberSlots()) {
224 return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
225 }
226 CommandResult ret;
227 auto cb = [&ret](CommandResult result) { ret = result; };
228 auto result = boot_control_hal->setActiveBootSlot(slot, cb);
Hridya Valsaraju20bdf892018-10-10 11:02:19 -0700229 if (result.isOk() && ret.success) {
230 // Save as slot suffix to match the suffix format as returned from
231 // the boot control HAL.
232 auto current_slot = "_" + args[1];
233 device->set_active_slot(current_slot);
234 return device->WriteStatus(FastbootResult::OKAY, "");
235 }
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700236 return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700237}
238
239bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
240 auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
241 android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
242 device->CloseDevice();
243 TEMP_FAILURE_RETRY(pause());
244 return result;
245}
246
247bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
248 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
249 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
250 device->CloseDevice();
251 TEMP_FAILURE_RETRY(pause());
252 return result;
253}
254
255bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
256 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
257 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
258 device->CloseDevice();
259 TEMP_FAILURE_RETRY(pause());
260 return result;
261}
262
263bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
264 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
265 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
266 device->CloseDevice();
267 TEMP_FAILURE_RETRY(pause());
268 return result;
269}
270
271static bool EnterRecovery() {
272 const char msg_switch_to_recovery = 'r';
273
274 android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
275 if (sock < 0) {
276 PLOG(ERROR) << "Couldn't create sock";
277 return false;
278 }
279
280 struct sockaddr_un addr = {.sun_family = AF_UNIX};
281 strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
282 if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
283 PLOG(ERROR) << "Couldn't connect to recovery";
284 return false;
285 }
286 // Switch to recovery will not update the boot reason since it does not
287 // require a reboot.
288 auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
289 if (ret != sizeof(msg_switch_to_recovery)) {
290 PLOG(ERROR) << "Couldn't write message to switch to recovery";
291 return false;
292 }
293
294 return true;
295}
296
297bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
298 auto status = true;
299 if (EnterRecovery()) {
300 status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
301 } else {
302 status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
303 }
304 device->CloseDevice();
305 TEMP_FAILURE_RETRY(pause());
306 return status;
307}
David Anderson0d4277d2018-07-31 13:27:37 -0700308
309// Helper class for opening a handle to a MetadataBuilder and writing the new
310// partition table to the same place it was read.
311class PartitionBuilder {
312 public:
David Andersond25f1c32018-11-09 20:41:33 -0800313 explicit PartitionBuilder(FastbootDevice* device, const std::string& partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700314
315 bool Write();
316 bool Valid() const { return !!builder_; }
317 MetadataBuilder* operator->() const { return builder_.get(); }
318
319 private:
David Anderson4d307b02018-12-17 17:07:34 -0800320 FastbootDevice* device_;
David Anderson0d4277d2018-07-31 13:27:37 -0700321 std::string super_device_;
David Andersond25f1c32018-11-09 20:41:33 -0800322 uint32_t slot_number_;
David Anderson0d4277d2018-07-31 13:27:37 -0700323 std::unique_ptr<MetadataBuilder> builder_;
324};
325
David Anderson4d307b02018-12-17 17:07:34 -0800326PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name)
327 : device_(device) {
David Andersond25f1c32018-11-09 20:41:33 -0800328 std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
David Anderson27475322019-06-11 14:00:08 -0700329 slot_number_ = android::fs_mgr::SlotNumberForSlotSuffix(slot_suffix);
David Andersond25f1c32018-11-09 20:41:33 -0800330 auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number_));
David Anderson0d4277d2018-07-31 13:27:37 -0700331 if (!super_device) {
332 return;
333 }
334 super_device_ = *super_device;
David Andersond25f1c32018-11-09 20:41:33 -0800335 builder_ = MetadataBuilder::New(super_device_, slot_number_);
David Anderson0d4277d2018-07-31 13:27:37 -0700336}
337
338bool PartitionBuilder::Write() {
David Anderson27475322019-06-11 14:00:08 -0700339 auto metadata = builder_->Export();
David Anderson0d4277d2018-07-31 13:27:37 -0700340 if (!metadata) {
341 return false;
342 }
David Anderson4d307b02018-12-17 17:07:34 -0800343 return UpdateAllPartitionMetadata(device_, super_device_, *metadata.get());
David Anderson0d4277d2018-07-31 13:27:37 -0700344}
345
346bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
347 if (args.size() < 3) {
348 return device->WriteFail("Invalid partition name and size");
349 }
350
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700351 if (GetDeviceLockStatus()) {
352 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
353 }
354
David Anderson0d4277d2018-07-31 13:27:37 -0700355 uint64_t partition_size;
356 std::string partition_name = args[1];
357 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
358 return device->WriteFail("Invalid partition size");
359 }
360
David Andersond25f1c32018-11-09 20:41:33 -0800361 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700362 if (!builder.Valid()) {
363 return device->WriteFail("Could not open super partition");
364 }
365 // TODO(112433293) Disallow if the name is in the physical table as well.
366 if (builder->FindPartition(partition_name)) {
367 return device->WriteFail("Partition already exists");
368 }
369
David Anderson27475322019-06-11 14:00:08 -0700370 auto partition = builder->AddPartition(partition_name, 0);
David Anderson0d4277d2018-07-31 13:27:37 -0700371 if (!partition) {
372 return device->WriteFail("Failed to add partition");
373 }
374 if (!builder->ResizePartition(partition, partition_size)) {
375 builder->RemovePartition(partition_name);
376 return device->WriteFail("Not enough space for partition");
377 }
378 if (!builder.Write()) {
379 return device->WriteFail("Failed to write partition table");
380 }
381 return device->WriteOkay("Partition created");
382}
383
384bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
385 if (args.size() < 2) {
386 return device->WriteFail("Invalid partition name and size");
387 }
388
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700389 if (GetDeviceLockStatus()) {
390 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
391 }
392
David Andersond25f1c32018-11-09 20:41:33 -0800393 std::string partition_name = args[1];
394
395 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700396 if (!builder.Valid()) {
397 return device->WriteFail("Could not open super partition");
398 }
David Andersond25f1c32018-11-09 20:41:33 -0800399 builder->RemovePartition(partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700400 if (!builder.Write()) {
401 return device->WriteFail("Failed to write partition table");
402 }
403 return device->WriteOkay("Partition deleted");
404}
405
406bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
407 if (args.size() < 3) {
408 return device->WriteFail("Invalid partition name and size");
409 }
410
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700411 if (GetDeviceLockStatus()) {
412 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
413 }
414
David Anderson0d4277d2018-07-31 13:27:37 -0700415 uint64_t partition_size;
416 std::string partition_name = args[1];
417 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
418 return device->WriteFail("Invalid partition size");
419 }
420
David Andersond25f1c32018-11-09 20:41:33 -0800421 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700422 if (!builder.Valid()) {
423 return device->WriteFail("Could not open super partition");
424 }
425
David Anderson27475322019-06-11 14:00:08 -0700426 auto partition = builder->FindPartition(partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700427 if (!partition) {
428 return device->WriteFail("Partition does not exist");
429 }
David Andersonad970fc2019-08-27 14:01:16 -0700430
431 // Remove the updated flag to cancel any snapshots.
432 uint32_t attrs = partition->attributes();
433 partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
434
David Anderson0d4277d2018-07-31 13:27:37 -0700435 if (!builder->ResizePartition(partition, partition_size)) {
436 return device->WriteFail("Not enough space to resize partition");
437 }
438 if (!builder.Write()) {
439 return device->WriteFail("Failed to write partition table");
440 }
441 return device->WriteOkay("Partition resized");
442}
David Anderson38b3c7a2018-08-15 16:27:42 -0700443
David Andersonad970fc2019-08-27 14:01:16 -0700444void CancelPartitionSnapshot(FastbootDevice* device, const std::string& partition_name) {
445 PartitionBuilder builder(device, partition_name);
446 if (!builder.Valid()) return;
447
448 auto partition = builder->FindPartition(partition_name);
449 if (!partition) return;
450
451 // Remove the updated flag to cancel any snapshots.
452 uint32_t attrs = partition->attributes();
453 partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
454
455 builder.Write();
456}
457
458bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args) {
459 if (args.size() < 2) {
460 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
461 }
462
463 if (GetDeviceLockStatus()) {
464 return device->WriteStatus(FastbootResult::FAIL,
465 "Flashing is not allowed on locked devices");
466 }
467
468 const auto& partition_name = args[1];
469 if (LogicalPartitionExists(device, partition_name)) {
470 CancelPartitionSnapshot(device, partition_name);
471 }
472
473 int ret = Flash(device, partition_name);
474 if (ret < 0) {
475 return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
476 }
477 return device->WriteStatus(FastbootResult::OKAY, "Flashing succeeded");
478}
479
David Anderson38b3c7a2018-08-15 16:27:42 -0700480bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args) {
481 if (args.size() < 2) {
482 return device->WriteFail("Invalid arguments");
483 }
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700484
485 if (GetDeviceLockStatus()) {
486 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
487 }
488
David Anderson38b3c7a2018-08-15 16:27:42 -0700489 bool wipe = (args.size() >= 3 && args[2] == "wipe");
490 return UpdateSuper(device, args[1], wipe);
491}
David Anderson1d504e32019-01-15 14:38:20 -0800492
David Anderson3d782d52019-01-29 13:09:49 -0800493class AutoMountMetadata {
494 public:
495 AutoMountMetadata() {
David Anderson27475322019-06-11 14:00:08 -0700496 android::fs_mgr::Fstab proc_mounts;
David Anderson3d782d52019-01-29 13:09:49 -0800497 if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
498 LOG(ERROR) << "Could not read /proc/mounts";
499 return;
500 }
501
502 auto iter = std::find_if(proc_mounts.begin(), proc_mounts.end(),
503 [](const auto& entry) { return entry.mount_point == "/metadata"; });
504 if (iter != proc_mounts.end()) {
505 mounted_ = true;
506 return;
507 }
508
509 if (!ReadDefaultFstab(&fstab_)) {
510 LOG(ERROR) << "Could not read default fstab";
511 return;
512 }
513 mounted_ = EnsurePathMounted(&fstab_, "/metadata");
514 should_unmount_ = true;
David Anderson1d504e32019-01-15 14:38:20 -0800515 }
David Anderson3d782d52019-01-29 13:09:49 -0800516 ~AutoMountMetadata() {
517 if (mounted_ && should_unmount_) {
518 EnsurePathUnmounted(&fstab_, "/metadata");
519 }
520 }
521 explicit operator bool() const { return mounted_; }
522
523 private:
David Anderson27475322019-06-11 14:00:08 -0700524 android::fs_mgr::Fstab fstab_;
David Anderson3d782d52019-01-29 13:09:49 -0800525 bool mounted_ = false;
526 bool should_unmount_ = false;
527};
528
529bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
David Anderson1d504e32019-01-15 14:38:20 -0800530 if (args.size() != 2) {
531 return device->WriteFail("Invalid arguments");
532 }
David Anderson3d782d52019-01-29 13:09:49 -0800533
534 AutoMountMetadata mount_metadata;
535 if (!mount_metadata) {
536 return device->WriteFail("Could not find GSI install");
537 }
538
539 if (!android::gsi::IsGsiInstalled()) {
540 return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed");
541 }
542
David Anderson1d504e32019-01-15 14:38:20 -0800543 if (args[1] == "wipe") {
544 if (!android::gsi::UninstallGsi()) {
545 return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
546 }
547 } else if (args[1] == "disable") {
548 if (!android::gsi::DisableGsi()) {
549 return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
550 }
551 }
552 return device->WriteStatus(FastbootResult::OKAY, "Success");
553}
David Andersonab8f4662019-10-21 16:45:59 -0700554
555bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string>& args) {
556 // Note that we use the HAL rather than mounting /metadata, since we want
557 // our results to match the bootloader.
558 auto hal = device->boot_control_hal();
559 if (!hal) return device->WriteFail("Not supported");
560
561 android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
562 if (!hal11) return device->WriteFail("Not supported");
563
564 // If no arguments, return the same thing as a getvar. Note that we get the
565 // HAL first so we can return "not supported" before we return the less
566 // specific error message below.
567 if (args.size() < 2 || args[1].empty()) {
568 std::string message;
569 if (!GetSnapshotUpdateStatus(device, {}, &message)) {
570 return device->WriteFail("Could not determine update status");
571 }
572 device->WriteInfo(message);
573 return device->WriteOkay("");
574 }
575
576 if (args.size() != 2 || args[1] != "cancel") {
577 return device->WriteFail("Invalid arguments");
578 }
579
580 MergeStatus status = hal11->getSnapshotMergeStatus();
581 switch (status) {
582 case MergeStatus::SNAPSHOTTED:
583 case MergeStatus::MERGING:
584 hal11->setSnapshotMergeStatus(MergeStatus::CANCELLED);
585 break;
586 default:
587 break;
588 }
589 return device->WriteStatus(FastbootResult::OKAY, "Success");
590}