blob: a2c95d6364211f92072da847fc8ba3157dc4f824 [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}},
Bowgo Tsai33da5c92019-11-13 17:13:49 +0800108 {FB_VAR_SNAPSHOT_UPDATE_STATUS, {GetSnapshotUpdateStatus, nullptr}},
109 {FB_VAR_CPU_ABI, {GetCpuAbi, nullptr}}};
David Anderson0f626632018-08-31 16:44:25 -0700110
111 if (args.size() < 2) {
112 return device->WriteFail("Missing argument");
113 }
114
115 // Special case: return all variables that we can.
116 if (args[1] == "all") {
117 for (const auto& [name, handlers] : kVariableMap) {
118 GetAllVars(device, name, handlers);
119 }
120 return device->WriteOkay("");
121 }
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700122
123 // args[0] is command name, args[1] is variable.
124 auto found_variable = kVariableMap.find(args[1]);
125 if (found_variable == kVariableMap.end()) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700126 return device->WriteFail("Unknown variable");
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700127 }
128
David Anderson1fb3fd72018-08-31 14:40:22 -0700129 std::string message;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700130 std::vector<std::string> getvar_args(args.begin() + 2, args.end());
David Anderson0f626632018-08-31 16:44:25 -0700131 if (!found_variable->second.get(device, getvar_args, &message)) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700132 return device->WriteFail(message);
133 }
134 return device->WriteOkay(message);
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700135}
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700136
David Anderson12211d12018-07-24 15:21:20 -0700137bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
138 if (args.size() < 2) {
139 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
140 }
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700141
142 if (GetDeviceLockStatus()) {
143 return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
144 }
145
David Anderson12211d12018-07-24 15:21:20 -0700146 PartitionHandle handle;
147 if (!OpenPartition(device, args[1], &handle)) {
148 return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
149 }
150 if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
151 return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
152 }
153 return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
154}
155
Hridya Valsarajua15fe312018-09-14 13:58:21 -0700156bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args) {
157 auto fastboot_hal = device->fastboot_hal();
158 if (!fastboot_hal) {
159 return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL");
160 }
161
162 Result ret;
163 auto ret_val = fastboot_hal->doOemCommand(args[0], [&](Result result) { ret = result; });
164 if (!ret_val.isOk()) {
165 return device->WriteStatus(FastbootResult::FAIL, "Unable to do OEM command");
166 }
167 if (ret.status != Status::SUCCESS) {
168 return device->WriteStatus(FastbootResult::FAIL, ret.message);
169 }
170
171 return device->WriteStatus(FastbootResult::OKAY, ret.message);
172}
173
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700174bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
175 if (args.size() < 2) {
176 return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
177 }
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700178
179 if (GetDeviceLockStatus()) {
180 return device->WriteStatus(FastbootResult::FAIL,
181 "Download is not allowed on locked devices");
182 }
183
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700184 // arg[0] is the command name, arg[1] contains size of data to be downloaded
185 unsigned int size;
Hridya Valsarajuaae84e82018-10-08 13:10:25 -0700186 if (!android::base::ParseUint("0x" + args[1], &size, kMaxDownloadSizeDefault)) {
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700187 return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
188 }
David Anderson12211d12018-07-24 15:21:20 -0700189 device->download_data().resize(size);
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700190 if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
191 return false;
192 }
193
David Anderson12211d12018-07-24 15:21:20 -0700194 if (device->HandleData(true, &device->download_data())) {
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700195 return device->WriteStatus(FastbootResult::OKAY, "");
196 }
197
198 PLOG(ERROR) << "Couldn't download data";
199 return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
200}
201
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700202bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args) {
203 if (args.size() < 2) {
204 return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
205 }
206
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700207 if (GetDeviceLockStatus()) {
208 return device->WriteStatus(FastbootResult::FAIL,
209 "set_active command is not allowed on locked devices");
210 }
211
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700212 // Slot suffix needs to be between 'a' and 'z'.
213 Slot slot;
214 if (!GetSlotNumber(args[1], &slot)) {
215 return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
216 }
217
218 // Non-A/B devices will not have a boot control HAL.
219 auto boot_control_hal = device->boot_control_hal();
220 if (!boot_control_hal) {
221 return device->WriteStatus(FastbootResult::FAIL,
222 "Cannot set slot: boot control HAL absent");
223 }
224 if (slot >= boot_control_hal->getNumberSlots()) {
225 return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
226 }
227 CommandResult ret;
228 auto cb = [&ret](CommandResult result) { ret = result; };
229 auto result = boot_control_hal->setActiveBootSlot(slot, cb);
Hridya Valsaraju20bdf892018-10-10 11:02:19 -0700230 if (result.isOk() && ret.success) {
231 // Save as slot suffix to match the suffix format as returned from
232 // the boot control HAL.
233 auto current_slot = "_" + args[1];
234 device->set_active_slot(current_slot);
235 return device->WriteStatus(FastbootResult::OKAY, "");
236 }
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700237 return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700238}
239
240bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
241 auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
242 android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
243 device->CloseDevice();
244 TEMP_FAILURE_RETRY(pause());
245 return result;
246}
247
248bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
249 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
250 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
251 device->CloseDevice();
252 TEMP_FAILURE_RETRY(pause());
253 return result;
254}
255
256bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
257 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
258 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
259 device->CloseDevice();
260 TEMP_FAILURE_RETRY(pause());
261 return result;
262}
263
264bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
265 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
266 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
267 device->CloseDevice();
268 TEMP_FAILURE_RETRY(pause());
269 return result;
270}
271
272static bool EnterRecovery() {
273 const char msg_switch_to_recovery = 'r';
274
275 android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
276 if (sock < 0) {
277 PLOG(ERROR) << "Couldn't create sock";
278 return false;
279 }
280
281 struct sockaddr_un addr = {.sun_family = AF_UNIX};
282 strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
283 if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
284 PLOG(ERROR) << "Couldn't connect to recovery";
285 return false;
286 }
287 // Switch to recovery will not update the boot reason since it does not
288 // require a reboot.
289 auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
290 if (ret != sizeof(msg_switch_to_recovery)) {
291 PLOG(ERROR) << "Couldn't write message to switch to recovery";
292 return false;
293 }
294
295 return true;
296}
297
298bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
299 auto status = true;
300 if (EnterRecovery()) {
301 status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
302 } else {
303 status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
304 }
305 device->CloseDevice();
306 TEMP_FAILURE_RETRY(pause());
307 return status;
308}
David Anderson0d4277d2018-07-31 13:27:37 -0700309
310// Helper class for opening a handle to a MetadataBuilder and writing the new
311// partition table to the same place it was read.
312class PartitionBuilder {
313 public:
David Andersond25f1c32018-11-09 20:41:33 -0800314 explicit PartitionBuilder(FastbootDevice* device, const std::string& partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700315
316 bool Write();
317 bool Valid() const { return !!builder_; }
318 MetadataBuilder* operator->() const { return builder_.get(); }
319
320 private:
David Anderson4d307b02018-12-17 17:07:34 -0800321 FastbootDevice* device_;
David Anderson0d4277d2018-07-31 13:27:37 -0700322 std::string super_device_;
David Andersond25f1c32018-11-09 20:41:33 -0800323 uint32_t slot_number_;
David Anderson0d4277d2018-07-31 13:27:37 -0700324 std::unique_ptr<MetadataBuilder> builder_;
325};
326
David Anderson4d307b02018-12-17 17:07:34 -0800327PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name)
328 : device_(device) {
David Andersond25f1c32018-11-09 20:41:33 -0800329 std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
David Anderson27475322019-06-11 14:00:08 -0700330 slot_number_ = android::fs_mgr::SlotNumberForSlotSuffix(slot_suffix);
David Andersond25f1c32018-11-09 20:41:33 -0800331 auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number_));
David Anderson0d4277d2018-07-31 13:27:37 -0700332 if (!super_device) {
333 return;
334 }
335 super_device_ = *super_device;
David Andersond25f1c32018-11-09 20:41:33 -0800336 builder_ = MetadataBuilder::New(super_device_, slot_number_);
David Anderson0d4277d2018-07-31 13:27:37 -0700337}
338
339bool PartitionBuilder::Write() {
David Anderson27475322019-06-11 14:00:08 -0700340 auto metadata = builder_->Export();
David Anderson0d4277d2018-07-31 13:27:37 -0700341 if (!metadata) {
342 return false;
343 }
David Anderson4d307b02018-12-17 17:07:34 -0800344 return UpdateAllPartitionMetadata(device_, super_device_, *metadata.get());
David Anderson0d4277d2018-07-31 13:27:37 -0700345}
346
347bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
348 if (args.size() < 3) {
349 return device->WriteFail("Invalid partition name and size");
350 }
351
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700352 if (GetDeviceLockStatus()) {
353 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
354 }
355
David Anderson0d4277d2018-07-31 13:27:37 -0700356 uint64_t partition_size;
357 std::string partition_name = args[1];
358 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
359 return device->WriteFail("Invalid partition size");
360 }
361
David Andersond25f1c32018-11-09 20:41:33 -0800362 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700363 if (!builder.Valid()) {
364 return device->WriteFail("Could not open super partition");
365 }
366 // TODO(112433293) Disallow if the name is in the physical table as well.
367 if (builder->FindPartition(partition_name)) {
368 return device->WriteFail("Partition already exists");
369 }
370
David Anderson27475322019-06-11 14:00:08 -0700371 auto partition = builder->AddPartition(partition_name, 0);
David Anderson0d4277d2018-07-31 13:27:37 -0700372 if (!partition) {
373 return device->WriteFail("Failed to add partition");
374 }
375 if (!builder->ResizePartition(partition, partition_size)) {
376 builder->RemovePartition(partition_name);
377 return device->WriteFail("Not enough space for partition");
378 }
379 if (!builder.Write()) {
380 return device->WriteFail("Failed to write partition table");
381 }
382 return device->WriteOkay("Partition created");
383}
384
385bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
386 if (args.size() < 2) {
387 return device->WriteFail("Invalid partition name and size");
388 }
389
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700390 if (GetDeviceLockStatus()) {
391 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
392 }
393
David Andersond25f1c32018-11-09 20:41:33 -0800394 std::string partition_name = args[1];
395
396 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700397 if (!builder.Valid()) {
398 return device->WriteFail("Could not open super partition");
399 }
David Andersond25f1c32018-11-09 20:41:33 -0800400 builder->RemovePartition(partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700401 if (!builder.Write()) {
402 return device->WriteFail("Failed to write partition table");
403 }
404 return device->WriteOkay("Partition deleted");
405}
406
407bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
408 if (args.size() < 3) {
409 return device->WriteFail("Invalid partition name and size");
410 }
411
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700412 if (GetDeviceLockStatus()) {
413 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
414 }
415
David Anderson0d4277d2018-07-31 13:27:37 -0700416 uint64_t partition_size;
417 std::string partition_name = args[1];
418 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
419 return device->WriteFail("Invalid partition size");
420 }
421
David Andersond25f1c32018-11-09 20:41:33 -0800422 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700423 if (!builder.Valid()) {
424 return device->WriteFail("Could not open super partition");
425 }
426
David Anderson27475322019-06-11 14:00:08 -0700427 auto partition = builder->FindPartition(partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700428 if (!partition) {
429 return device->WriteFail("Partition does not exist");
430 }
David Andersonad970fc2019-08-27 14:01:16 -0700431
432 // Remove the updated flag to cancel any snapshots.
433 uint32_t attrs = partition->attributes();
434 partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
435
David Anderson0d4277d2018-07-31 13:27:37 -0700436 if (!builder->ResizePartition(partition, partition_size)) {
437 return device->WriteFail("Not enough space to resize partition");
438 }
439 if (!builder.Write()) {
440 return device->WriteFail("Failed to write partition table");
441 }
442 return device->WriteOkay("Partition resized");
443}
David Anderson38b3c7a2018-08-15 16:27:42 -0700444
David Andersonad970fc2019-08-27 14:01:16 -0700445void CancelPartitionSnapshot(FastbootDevice* device, const std::string& partition_name) {
446 PartitionBuilder builder(device, partition_name);
447 if (!builder.Valid()) return;
448
449 auto partition = builder->FindPartition(partition_name);
450 if (!partition) return;
451
452 // Remove the updated flag to cancel any snapshots.
453 uint32_t attrs = partition->attributes();
454 partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
455
456 builder.Write();
457}
458
459bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args) {
460 if (args.size() < 2) {
461 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
462 }
463
464 if (GetDeviceLockStatus()) {
465 return device->WriteStatus(FastbootResult::FAIL,
466 "Flashing is not allowed on locked devices");
467 }
468
469 const auto& partition_name = args[1];
470 if (LogicalPartitionExists(device, partition_name)) {
471 CancelPartitionSnapshot(device, partition_name);
472 }
473
474 int ret = Flash(device, partition_name);
475 if (ret < 0) {
476 return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
477 }
478 return device->WriteStatus(FastbootResult::OKAY, "Flashing succeeded");
479}
480
David Anderson38b3c7a2018-08-15 16:27:42 -0700481bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args) {
482 if (args.size() < 2) {
483 return device->WriteFail("Invalid arguments");
484 }
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700485
486 if (GetDeviceLockStatus()) {
487 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
488 }
489
David Anderson38b3c7a2018-08-15 16:27:42 -0700490 bool wipe = (args.size() >= 3 && args[2] == "wipe");
491 return UpdateSuper(device, args[1], wipe);
492}
David Anderson1d504e32019-01-15 14:38:20 -0800493
David Anderson3d782d52019-01-29 13:09:49 -0800494class AutoMountMetadata {
495 public:
496 AutoMountMetadata() {
David Anderson27475322019-06-11 14:00:08 -0700497 android::fs_mgr::Fstab proc_mounts;
David Anderson3d782d52019-01-29 13:09:49 -0800498 if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
499 LOG(ERROR) << "Could not read /proc/mounts";
500 return;
501 }
502
503 auto iter = std::find_if(proc_mounts.begin(), proc_mounts.end(),
504 [](const auto& entry) { return entry.mount_point == "/metadata"; });
505 if (iter != proc_mounts.end()) {
506 mounted_ = true;
507 return;
508 }
509
510 if (!ReadDefaultFstab(&fstab_)) {
511 LOG(ERROR) << "Could not read default fstab";
512 return;
513 }
514 mounted_ = EnsurePathMounted(&fstab_, "/metadata");
515 should_unmount_ = true;
David Anderson1d504e32019-01-15 14:38:20 -0800516 }
David Anderson3d782d52019-01-29 13:09:49 -0800517 ~AutoMountMetadata() {
518 if (mounted_ && should_unmount_) {
519 EnsurePathUnmounted(&fstab_, "/metadata");
520 }
521 }
522 explicit operator bool() const { return mounted_; }
523
524 private:
David Anderson27475322019-06-11 14:00:08 -0700525 android::fs_mgr::Fstab fstab_;
David Anderson3d782d52019-01-29 13:09:49 -0800526 bool mounted_ = false;
527 bool should_unmount_ = false;
528};
529
530bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
David Anderson1d504e32019-01-15 14:38:20 -0800531 if (args.size() != 2) {
532 return device->WriteFail("Invalid arguments");
533 }
David Anderson3d782d52019-01-29 13:09:49 -0800534
535 AutoMountMetadata mount_metadata;
536 if (!mount_metadata) {
537 return device->WriteFail("Could not find GSI install");
538 }
539
540 if (!android::gsi::IsGsiInstalled()) {
541 return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed");
542 }
543
David Anderson1d504e32019-01-15 14:38:20 -0800544 if (args[1] == "wipe") {
545 if (!android::gsi::UninstallGsi()) {
546 return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
547 }
548 } else if (args[1] == "disable") {
549 if (!android::gsi::DisableGsi()) {
550 return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
551 }
552 }
553 return device->WriteStatus(FastbootResult::OKAY, "Success");
554}
David Andersonab8f4662019-10-21 16:45:59 -0700555
556bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string>& args) {
557 // Note that we use the HAL rather than mounting /metadata, since we want
558 // our results to match the bootloader.
559 auto hal = device->boot_control_hal();
560 if (!hal) return device->WriteFail("Not supported");
561
562 android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
563 if (!hal11) return device->WriteFail("Not supported");
564
565 // If no arguments, return the same thing as a getvar. Note that we get the
566 // HAL first so we can return "not supported" before we return the less
567 // specific error message below.
568 if (args.size() < 2 || args[1].empty()) {
569 std::string message;
570 if (!GetSnapshotUpdateStatus(device, {}, &message)) {
571 return device->WriteFail("Could not determine update status");
572 }
573 device->WriteInfo(message);
574 return device->WriteOkay("");
575 }
576
577 if (args.size() != 2 || args[1] != "cancel") {
578 return device->WriteFail("Invalid arguments");
579 }
580
581 MergeStatus status = hal11->getSnapshotMergeStatus();
582 switch (status) {
583 case MergeStatus::SNAPSHOTTED:
584 case MergeStatus::MERGING:
585 hal11->setSnapshotMergeStatus(MergeStatus::CANCELLED);
586 break;
587 default:
588 break;
589 }
590 return device->WriteStatus(FastbootResult::OKAY, "Success");
591}