blob: 4c77c755b2414ebec5a34be4f678bd7c3f59b944 [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 Anderson5cbd2e42018-09-27 10:53:04 -070030#include <fs_mgr.h>
David Anderson3d782d52019-01-29 13:09:49 -080031#include <fs_mgr/roots.h>
David Anderson1d504e32019-01-15 14:38:20 -080032#include <libgsi/libgsi.h>
David Anderson0d4277d2018-07-31 13:27:37 -070033#include <liblp/builder.h>
34#include <liblp/liblp.h>
35#include <uuid/uuid.h>
Hridya Valsarajudea91b42018-07-17 11:14:01 -070036
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070037#include "constants.h"
Hridya Valsarajudea91b42018-07-17 11:14:01 -070038#include "fastboot_device.h"
David Anderson12211d12018-07-24 15:21:20 -070039#include "flashing.h"
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070040#include "utility.h"
41
David Anderson27475322019-06-11 14:00:08 -070042using android::fs_mgr::MetadataBuilder;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070043using ::android::hardware::hidl_string;
44using ::android::hardware::boot::V1_0::BoolResult;
45using ::android::hardware::boot::V1_0::CommandResult;
46using ::android::hardware::boot::V1_0::Slot;
Hridya Valsarajua15fe312018-09-14 13:58:21 -070047using ::android::hardware::fastboot::V1_0::Result;
48using ::android::hardware::fastboot::V1_0::Status;
49
David Anderson0f626632018-08-31 16:44:25 -070050struct VariableHandlers {
51 // Callback to retrieve the value of a single variable.
52 std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)> get;
53 // Callback to retrieve all possible argument combinations, for getvar all.
54 std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args;
55};
56
57static void GetAllVars(FastbootDevice* device, const std::string& name,
58 const VariableHandlers& handlers) {
59 if (!handlers.get_all_args) {
60 std::string message;
61 if (!handlers.get(device, std::vector<std::string>(), &message)) {
62 return;
63 }
64 device->WriteInfo(android::base::StringPrintf("%s:%s", name.c_str(), message.c_str()));
65 return;
66 }
67
68 auto all_args = handlers.get_all_args(device);
69 for (const auto& args : all_args) {
70 std::string message;
71 if (!handlers.get(device, args, &message)) {
72 continue;
73 }
74 std::string arg_string = android::base::Join(args, ":");
75 device->WriteInfo(android::base::StringPrintf("%s:%s:%s", name.c_str(), arg_string.c_str(),
76 message.c_str()));
77 }
78}
79
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070080bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
David Anderson0f626632018-08-31 16:44:25 -070081 const std::unordered_map<std::string, VariableHandlers> kVariableMap = {
82 {FB_VAR_VERSION, {GetVersion, nullptr}},
83 {FB_VAR_VERSION_BOOTLOADER, {GetBootloaderVersion, nullptr}},
84 {FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}},
85 {FB_VAR_PRODUCT, {GetProduct, nullptr}},
86 {FB_VAR_SERIALNO, {GetSerial, nullptr}},
Hridya Valsaraju4af80902018-09-26 13:08:16 -070087 {FB_VAR_VARIANT, {GetVariant, nullptr}},
David Anderson0f626632018-08-31 16:44:25 -070088 {FB_VAR_SECURE, {GetSecure, nullptr}},
89 {FB_VAR_UNLOCKED, {GetUnlocked, nullptr}},
90 {FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}},
91 {FB_VAR_CURRENT_SLOT, {::GetCurrentSlot, nullptr}},
92 {FB_VAR_SLOT_COUNT, {GetSlotCount, nullptr}},
93 {FB_VAR_HAS_SLOT, {GetHasSlot, GetAllPartitionArgsNoSlot}},
94 {FB_VAR_SLOT_SUCCESSFUL, {GetSlotSuccessful, nullptr}},
95 {FB_VAR_SLOT_UNBOOTABLE, {GetSlotUnbootable, nullptr}},
David Anderson27475322019-06-11 14:00:08 -070096 {FB_VAR_PARTITION_SIZE, {GetPartitionSize, GetAllPartitionArgsWithSlot}},
Hridya Valsarajubf9f8d12018-09-05 16:57:24 -070097 {FB_VAR_PARTITION_TYPE, {GetPartitionType, GetAllPartitionArgsWithSlot}},
David Anderson0f626632018-08-31 16:44:25 -070098 {FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}},
David Andersonc091c172018-09-04 18:11:03 -070099 {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}},
Hridya Valsaraju7c9bbe92018-09-27 10:41:01 -0700100 {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}},
Hridya Valsaraju47658ca2018-09-28 11:41:22 -0700101 {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
Hridya Valsarajua534a5a2018-10-03 15:53:22 -0700102 {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}},
David Anderson90fe0a42018-11-05 18:01:32 -0800103 {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}},
104 {FB_VAR_SUPER_PARTITION_NAME, {GetSuperPartitionName, nullptr}}};
David Anderson0f626632018-08-31 16:44:25 -0700105
106 if (args.size() < 2) {
107 return device->WriteFail("Missing argument");
108 }
109
110 // Special case: return all variables that we can.
111 if (args[1] == "all") {
112 for (const auto& [name, handlers] : kVariableMap) {
113 GetAllVars(device, name, handlers);
114 }
115 return device->WriteOkay("");
116 }
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700117
118 // args[0] is command name, args[1] is variable.
119 auto found_variable = kVariableMap.find(args[1]);
120 if (found_variable == kVariableMap.end()) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700121 return device->WriteFail("Unknown variable");
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700122 }
123
David Anderson1fb3fd72018-08-31 14:40:22 -0700124 std::string message;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700125 std::vector<std::string> getvar_args(args.begin() + 2, args.end());
David Anderson0f626632018-08-31 16:44:25 -0700126 if (!found_variable->second.get(device, getvar_args, &message)) {
David Anderson1fb3fd72018-08-31 14:40:22 -0700127 return device->WriteFail(message);
128 }
129 return device->WriteOkay(message);
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700130}
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700131
David Anderson12211d12018-07-24 15:21:20 -0700132bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
133 if (args.size() < 2) {
134 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
135 }
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700136
137 if (GetDeviceLockStatus()) {
138 return device->WriteStatus(FastbootResult::FAIL, "Erase is not allowed on locked devices");
139 }
140
David Anderson12211d12018-07-24 15:21:20 -0700141 PartitionHandle handle;
142 if (!OpenPartition(device, args[1], &handle)) {
143 return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
144 }
145 if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
146 return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
147 }
148 return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
149}
150
Hridya Valsarajua15fe312018-09-14 13:58:21 -0700151bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args) {
152 auto fastboot_hal = device->fastboot_hal();
153 if (!fastboot_hal) {
154 return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL");
155 }
156
157 Result ret;
158 auto ret_val = fastboot_hal->doOemCommand(args[0], [&](Result result) { ret = result; });
159 if (!ret_val.isOk()) {
160 return device->WriteStatus(FastbootResult::FAIL, "Unable to do OEM command");
161 }
162 if (ret.status != Status::SUCCESS) {
163 return device->WriteStatus(FastbootResult::FAIL, ret.message);
164 }
165
166 return device->WriteStatus(FastbootResult::OKAY, ret.message);
167}
168
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700169bool DownloadHandler(FastbootDevice* device, const std::vector<std::string>& args) {
170 if (args.size() < 2) {
171 return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified");
172 }
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700173
174 if (GetDeviceLockStatus()) {
175 return device->WriteStatus(FastbootResult::FAIL,
176 "Download is not allowed on locked devices");
177 }
178
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700179 // arg[0] is the command name, arg[1] contains size of data to be downloaded
180 unsigned int size;
Hridya Valsarajuaae84e82018-10-08 13:10:25 -0700181 if (!android::base::ParseUint("0x" + args[1], &size, kMaxDownloadSizeDefault)) {
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700182 return device->WriteStatus(FastbootResult::FAIL, "Invalid size");
183 }
David Anderson12211d12018-07-24 15:21:20 -0700184 device->download_data().resize(size);
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700185 if (!device->WriteStatus(FastbootResult::DATA, android::base::StringPrintf("%08x", size))) {
186 return false;
187 }
188
David Anderson12211d12018-07-24 15:21:20 -0700189 if (device->HandleData(true, &device->download_data())) {
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700190 return device->WriteStatus(FastbootResult::OKAY, "");
191 }
192
193 PLOG(ERROR) << "Couldn't download data";
194 return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data");
195}
196
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700197bool SetActiveHandler(FastbootDevice* device, const std::vector<std::string>& args) {
198 if (args.size() < 2) {
199 return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument");
200 }
201
Hridya Valsarajud1e62312018-10-08 09:13:17 -0700202 if (GetDeviceLockStatus()) {
203 return device->WriteStatus(FastbootResult::FAIL,
204 "set_active command is not allowed on locked devices");
205 }
206
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700207 // Slot suffix needs to be between 'a' and 'z'.
208 Slot slot;
209 if (!GetSlotNumber(args[1], &slot)) {
210 return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix");
211 }
212
213 // Non-A/B devices will not have a boot control HAL.
214 auto boot_control_hal = device->boot_control_hal();
215 if (!boot_control_hal) {
216 return device->WriteStatus(FastbootResult::FAIL,
217 "Cannot set slot: boot control HAL absent");
218 }
219 if (slot >= boot_control_hal->getNumberSlots()) {
220 return device->WriteStatus(FastbootResult::FAIL, "Slot out of range");
221 }
222 CommandResult ret;
223 auto cb = [&ret](CommandResult result) { ret = result; };
224 auto result = boot_control_hal->setActiveBootSlot(slot, cb);
Hridya Valsaraju20bdf892018-10-10 11:02:19 -0700225 if (result.isOk() && ret.success) {
226 // Save as slot suffix to match the suffix format as returned from
227 // the boot control HAL.
228 auto current_slot = "_" + args[1];
229 device->set_active_slot(current_slot);
230 return device->WriteStatus(FastbootResult::OKAY, "");
231 }
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700232 return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot");
Hridya Valsarajudea91b42018-07-17 11:14:01 -0700233}
234
235bool ShutDownHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
236 auto result = device->WriteStatus(FastbootResult::OKAY, "Shutting down");
237 android::base::SetProperty(ANDROID_RB_PROPERTY, "shutdown,fastboot");
238 device->CloseDevice();
239 TEMP_FAILURE_RETRY(pause());
240 return result;
241}
242
243bool RebootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
244 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting");
245 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,from_fastboot");
246 device->CloseDevice();
247 TEMP_FAILURE_RETRY(pause());
248 return result;
249}
250
251bool RebootBootloaderHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
252 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting bootloader");
253 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,bootloader");
254 device->CloseDevice();
255 TEMP_FAILURE_RETRY(pause());
256 return result;
257}
258
259bool RebootFastbootHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
260 auto result = device->WriteStatus(FastbootResult::OKAY, "Rebooting fastboot");
261 android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,fastboot");
262 device->CloseDevice();
263 TEMP_FAILURE_RETRY(pause());
264 return result;
265}
266
267static bool EnterRecovery() {
268 const char msg_switch_to_recovery = 'r';
269
270 android::base::unique_fd sock(socket(AF_UNIX, SOCK_STREAM, 0));
271 if (sock < 0) {
272 PLOG(ERROR) << "Couldn't create sock";
273 return false;
274 }
275
276 struct sockaddr_un addr = {.sun_family = AF_UNIX};
277 strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
278 if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
279 PLOG(ERROR) << "Couldn't connect to recovery";
280 return false;
281 }
282 // Switch to recovery will not update the boot reason since it does not
283 // require a reboot.
284 auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
285 if (ret != sizeof(msg_switch_to_recovery)) {
286 PLOG(ERROR) << "Couldn't write message to switch to recovery";
287 return false;
288 }
289
290 return true;
291}
292
293bool RebootRecoveryHandler(FastbootDevice* device, const std::vector<std::string>& /* args */) {
294 auto status = true;
295 if (EnterRecovery()) {
296 status = device->WriteStatus(FastbootResult::OKAY, "Rebooting to recovery");
297 } else {
298 status = device->WriteStatus(FastbootResult::FAIL, "Unable to reboot to recovery");
299 }
300 device->CloseDevice();
301 TEMP_FAILURE_RETRY(pause());
302 return status;
303}
David Anderson0d4277d2018-07-31 13:27:37 -0700304
305// Helper class for opening a handle to a MetadataBuilder and writing the new
306// partition table to the same place it was read.
307class PartitionBuilder {
308 public:
David Andersond25f1c32018-11-09 20:41:33 -0800309 explicit PartitionBuilder(FastbootDevice* device, const std::string& partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700310
311 bool Write();
312 bool Valid() const { return !!builder_; }
313 MetadataBuilder* operator->() const { return builder_.get(); }
314
315 private:
David Anderson4d307b02018-12-17 17:07:34 -0800316 FastbootDevice* device_;
David Anderson0d4277d2018-07-31 13:27:37 -0700317 std::string super_device_;
David Andersond25f1c32018-11-09 20:41:33 -0800318 uint32_t slot_number_;
David Anderson0d4277d2018-07-31 13:27:37 -0700319 std::unique_ptr<MetadataBuilder> builder_;
320};
321
David Anderson4d307b02018-12-17 17:07:34 -0800322PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name)
323 : device_(device) {
David Andersond25f1c32018-11-09 20:41:33 -0800324 std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
David Anderson27475322019-06-11 14:00:08 -0700325 slot_number_ = android::fs_mgr::SlotNumberForSlotSuffix(slot_suffix);
David Andersond25f1c32018-11-09 20:41:33 -0800326 auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number_));
David Anderson0d4277d2018-07-31 13:27:37 -0700327 if (!super_device) {
328 return;
329 }
330 super_device_ = *super_device;
David Andersond25f1c32018-11-09 20:41:33 -0800331 builder_ = MetadataBuilder::New(super_device_, slot_number_);
David Anderson0d4277d2018-07-31 13:27:37 -0700332}
333
334bool PartitionBuilder::Write() {
David Anderson27475322019-06-11 14:00:08 -0700335 auto metadata = builder_->Export();
David Anderson0d4277d2018-07-31 13:27:37 -0700336 if (!metadata) {
337 return false;
338 }
David Anderson4d307b02018-12-17 17:07:34 -0800339 return UpdateAllPartitionMetadata(device_, super_device_, *metadata.get());
David Anderson0d4277d2018-07-31 13:27:37 -0700340}
341
342bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
343 if (args.size() < 3) {
344 return device->WriteFail("Invalid partition name and size");
345 }
346
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700347 if (GetDeviceLockStatus()) {
348 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
349 }
350
David Anderson0d4277d2018-07-31 13:27:37 -0700351 uint64_t partition_size;
352 std::string partition_name = args[1];
353 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
354 return device->WriteFail("Invalid partition size");
355 }
356
David Andersond25f1c32018-11-09 20:41:33 -0800357 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700358 if (!builder.Valid()) {
359 return device->WriteFail("Could not open super partition");
360 }
361 // TODO(112433293) Disallow if the name is in the physical table as well.
362 if (builder->FindPartition(partition_name)) {
363 return device->WriteFail("Partition already exists");
364 }
365
David Anderson27475322019-06-11 14:00:08 -0700366 auto partition = builder->AddPartition(partition_name, 0);
David Anderson0d4277d2018-07-31 13:27:37 -0700367 if (!partition) {
368 return device->WriteFail("Failed to add partition");
369 }
370 if (!builder->ResizePartition(partition, partition_size)) {
371 builder->RemovePartition(partition_name);
372 return device->WriteFail("Not enough space for partition");
373 }
374 if (!builder.Write()) {
375 return device->WriteFail("Failed to write partition table");
376 }
377 return device->WriteOkay("Partition created");
378}
379
380bool DeletePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
381 if (args.size() < 2) {
382 return device->WriteFail("Invalid partition name and size");
383 }
384
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700385 if (GetDeviceLockStatus()) {
386 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
387 }
388
David Andersond25f1c32018-11-09 20:41:33 -0800389 std::string partition_name = args[1];
390
391 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700392 if (!builder.Valid()) {
393 return device->WriteFail("Could not open super partition");
394 }
David Andersond25f1c32018-11-09 20:41:33 -0800395 builder->RemovePartition(partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700396 if (!builder.Write()) {
397 return device->WriteFail("Failed to write partition table");
398 }
399 return device->WriteOkay("Partition deleted");
400}
401
402bool ResizePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
403 if (args.size() < 3) {
404 return device->WriteFail("Invalid partition name and size");
405 }
406
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700407 if (GetDeviceLockStatus()) {
408 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
409 }
410
David Anderson0d4277d2018-07-31 13:27:37 -0700411 uint64_t partition_size;
412 std::string partition_name = args[1];
413 if (!android::base::ParseUint(args[2].c_str(), &partition_size)) {
414 return device->WriteFail("Invalid partition size");
415 }
416
David Andersond25f1c32018-11-09 20:41:33 -0800417 PartitionBuilder builder(device, partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700418 if (!builder.Valid()) {
419 return device->WriteFail("Could not open super partition");
420 }
421
David Anderson27475322019-06-11 14:00:08 -0700422 auto partition = builder->FindPartition(partition_name);
David Anderson0d4277d2018-07-31 13:27:37 -0700423 if (!partition) {
424 return device->WriteFail("Partition does not exist");
425 }
David Andersonad970fc2019-08-27 14:01:16 -0700426
427 // Remove the updated flag to cancel any snapshots.
428 uint32_t attrs = partition->attributes();
429 partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
430
David Anderson0d4277d2018-07-31 13:27:37 -0700431 if (!builder->ResizePartition(partition, partition_size)) {
432 return device->WriteFail("Not enough space to resize partition");
433 }
434 if (!builder.Write()) {
435 return device->WriteFail("Failed to write partition table");
436 }
437 return device->WriteOkay("Partition resized");
438}
David Anderson38b3c7a2018-08-15 16:27:42 -0700439
David Andersonad970fc2019-08-27 14:01:16 -0700440void CancelPartitionSnapshot(FastbootDevice* device, const std::string& partition_name) {
441 PartitionBuilder builder(device, partition_name);
442 if (!builder.Valid()) return;
443
444 auto partition = builder->FindPartition(partition_name);
445 if (!partition) return;
446
447 // Remove the updated flag to cancel any snapshots.
448 uint32_t attrs = partition->attributes();
449 partition->set_attributes(attrs & ~LP_PARTITION_ATTR_UPDATED);
450
451 builder.Write();
452}
453
454bool FlashHandler(FastbootDevice* device, const std::vector<std::string>& args) {
455 if (args.size() < 2) {
456 return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
457 }
458
459 if (GetDeviceLockStatus()) {
460 return device->WriteStatus(FastbootResult::FAIL,
461 "Flashing is not allowed on locked devices");
462 }
463
464 const auto& partition_name = args[1];
465 if (LogicalPartitionExists(device, partition_name)) {
466 CancelPartitionSnapshot(device, partition_name);
467 }
468
469 int ret = Flash(device, partition_name);
470 if (ret < 0) {
471 return device->WriteStatus(FastbootResult::FAIL, strerror(-ret));
472 }
473 return device->WriteStatus(FastbootResult::OKAY, "Flashing succeeded");
474}
475
David Anderson38b3c7a2018-08-15 16:27:42 -0700476bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args) {
477 if (args.size() < 2) {
478 return device->WriteFail("Invalid arguments");
479 }
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700480
481 if (GetDeviceLockStatus()) {
482 return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
483 }
484
David Anderson38b3c7a2018-08-15 16:27:42 -0700485 bool wipe = (args.size() >= 3 && args[2] == "wipe");
486 return UpdateSuper(device, args[1], wipe);
487}
David Anderson1d504e32019-01-15 14:38:20 -0800488
David Anderson3d782d52019-01-29 13:09:49 -0800489class AutoMountMetadata {
490 public:
491 AutoMountMetadata() {
David Anderson27475322019-06-11 14:00:08 -0700492 android::fs_mgr::Fstab proc_mounts;
David Anderson3d782d52019-01-29 13:09:49 -0800493 if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
494 LOG(ERROR) << "Could not read /proc/mounts";
495 return;
496 }
497
498 auto iter = std::find_if(proc_mounts.begin(), proc_mounts.end(),
499 [](const auto& entry) { return entry.mount_point == "/metadata"; });
500 if (iter != proc_mounts.end()) {
501 mounted_ = true;
502 return;
503 }
504
505 if (!ReadDefaultFstab(&fstab_)) {
506 LOG(ERROR) << "Could not read default fstab";
507 return;
508 }
509 mounted_ = EnsurePathMounted(&fstab_, "/metadata");
510 should_unmount_ = true;
David Anderson1d504e32019-01-15 14:38:20 -0800511 }
David Anderson3d782d52019-01-29 13:09:49 -0800512 ~AutoMountMetadata() {
513 if (mounted_ && should_unmount_) {
514 EnsurePathUnmounted(&fstab_, "/metadata");
515 }
516 }
517 explicit operator bool() const { return mounted_; }
518
519 private:
David Anderson27475322019-06-11 14:00:08 -0700520 android::fs_mgr::Fstab fstab_;
David Anderson3d782d52019-01-29 13:09:49 -0800521 bool mounted_ = false;
522 bool should_unmount_ = false;
523};
524
525bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
David Anderson1d504e32019-01-15 14:38:20 -0800526 if (args.size() != 2) {
527 return device->WriteFail("Invalid arguments");
528 }
David Anderson3d782d52019-01-29 13:09:49 -0800529
530 AutoMountMetadata mount_metadata;
531 if (!mount_metadata) {
532 return device->WriteFail("Could not find GSI install");
533 }
534
535 if (!android::gsi::IsGsiInstalled()) {
536 return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed");
537 }
538
David Anderson1d504e32019-01-15 14:38:20 -0800539 if (args[1] == "wipe") {
540 if (!android::gsi::UninstallGsi()) {
541 return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
542 }
543 } else if (args[1] == "disable") {
544 if (!android::gsi::DisableGsi()) {
545 return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
546 }
547 }
548 return device->WriteStatus(FastbootResult::OKAY, "Success");
549}