diff --git a/fastboot/Android.bp b/fastboot/Android.bp index 51cc62ade..aa88a8a44 100644 --- a/fastboot/Android.bp +++ b/fastboot/Android.bp @@ -96,6 +96,8 @@ cc_binary { "device/fastboot_device.cpp", "device/main.cpp", "device/usb_client.cpp", + "device/utility.cpp", + "device/variables.cpp", ], shared_libs: [ @@ -103,6 +105,7 @@ cc_binary { "libext4_utils", "libsparse", "liblog", + "android.hardware.boot@1.0", "libbootloader_message", "libhidltransport", "libhidlbase", diff --git a/fastboot/constants.h b/fastboot/constants.h index 7caca3dba..fa17070b1 100644 --- a/fastboot/constants.h +++ b/fastboot/constants.h @@ -51,3 +51,5 @@ #define FB_VAR_HAS_SLOT "has-slot" #define FB_VAR_SLOT_COUNT "slot-count" #define FB_VAR_PARTITION_SIZE "partition-size" +#define FB_VAR_SLOT_SUCCESSFUL "slot-successful" +#define FB_VAR_SLOT_UNBOOTABLE "slot-unbootable" diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index a3cbf9692..ac381fb1c 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -27,7 +27,43 @@ #include #include +#include "constants.h" #include "fastboot_device.h" +#include "utility.h" + +using ::android::hardware::hidl_string; +using ::android::hardware::boot::V1_0::BoolResult; +using ::android::hardware::boot::V1_0::CommandResult; +using ::android::hardware::boot::V1_0::Slot; + +bool GetVarHandler(FastbootDevice* device, const std::vector& args) { + using VariableHandler = + std::function&)>; + const std::unordered_map kVariableMap = { + {FB_VAR_VERSION, GetVersion}, + {FB_VAR_VERSION_BOOTLOADER, GetBootloaderVersion}, + {FB_VAR_VERSION_BASEBAND, GetBasebandVersion}, + {FB_VAR_PRODUCT, GetProduct}, + {FB_VAR_SERIALNO, GetSerial}, + {FB_VAR_SECURE, GetSecure}, + {FB_VAR_UNLOCKED, GetUnlocked}, + {FB_VAR_MAX_DOWNLOAD_SIZE, GetMaxDownloadSize}, + {FB_VAR_CURRENT_SLOT, ::GetCurrentSlot}, + {FB_VAR_SLOT_COUNT, GetSlotCount}, + {FB_VAR_HAS_SLOT, GetHasSlot}, + {FB_VAR_SLOT_SUCCESSFUL, GetSlotSuccessful}, + {FB_VAR_SLOT_UNBOOTABLE, GetSlotUnbootable}}; + + // args[0] is command name, args[1] is variable. + auto found_variable = kVariableMap.find(args[1]); + if (found_variable == kVariableMap.end()) { + return device->WriteStatus(FastbootResult::FAIL, "Unknown variable"); + } + + std::vector getvar_args(args.begin() + 2, args.end()); + auto result = found_variable->second(device, getvar_args); + return device->WriteStatus(FastbootResult::OKAY, result); +} bool DownloadHandler(FastbootDevice* device, const std::vector& args) { if (args.size() < 2) { @@ -51,8 +87,31 @@ bool DownloadHandler(FastbootDevice* device, const std::vector& arg return device->WriteStatus(FastbootResult::FAIL, "Couldn't download data"); } -bool SetActiveHandler(FastbootDevice* device, const std::vector& /* args */) { - return device->WriteStatus(FastbootResult::OKAY, ""); +bool SetActiveHandler(FastbootDevice* device, const std::vector& args) { + if (args.size() < 2) { + return device->WriteStatus(FastbootResult::FAIL, "Missing slot argument"); + } + + // Slot suffix needs to be between 'a' and 'z'. + Slot slot; + if (!GetSlotNumber(args[1], &slot)) { + return device->WriteStatus(FastbootResult::FAIL, "Bad slot suffix"); + } + + // Non-A/B devices will not have a boot control HAL. + auto boot_control_hal = device->boot_control_hal(); + if (!boot_control_hal) { + return device->WriteStatus(FastbootResult::FAIL, + "Cannot set slot: boot control HAL absent"); + } + if (slot >= boot_control_hal->getNumberSlots()) { + return device->WriteStatus(FastbootResult::FAIL, "Slot out of range"); + } + CommandResult ret; + auto cb = [&ret](CommandResult result) { ret = result; }; + auto result = boot_control_hal->setActiveBootSlot(slot, cb); + if (result.isOk() && ret.success) return device->WriteStatus(FastbootResult::OKAY, ""); + return device->WriteStatus(FastbootResult::FAIL, "Unable to set slot"); } bool ShutDownHandler(FastbootDevice* device, const std::vector& /* args */) { diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h index cd984c854..8785b917a 100644 --- a/fastboot/device/commands.h +++ b/fastboot/device/commands.h @@ -38,3 +38,4 @@ bool RebootHandler(FastbootDevice* device, const std::vector& args) bool RebootBootloaderHandler(FastbootDevice* device, const std::vector& args); bool RebootFastbootHandler(FastbootDevice* device, const std::vector& args); bool RebootRecoveryHandler(FastbootDevice* device, const std::vector& args); +bool GetVarHandler(FastbootDevice* device, const std::vector& args); diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp index 4c3d23f69..f61e5c20e 100644 --- a/fastboot/device/fastboot_device.cpp +++ b/fastboot/device/fastboot_device.cpp @@ -18,23 +18,31 @@ #include #include +#include #include #include "constants.h" #include "usb_client.h" +using ::android::hardware::hidl_string; +using ::android::hardware::boot::V1_0::IBootControl; +using ::android::hardware::boot::V1_0::Slot; +namespace sph = std::placeholders; + FastbootDevice::FastbootDevice() : kCommandMap({ {FB_CMD_SET_ACTIVE, SetActiveHandler}, {FB_CMD_DOWNLOAD, DownloadHandler}, + {FB_CMD_GETVAR, GetVarHandler}, {FB_CMD_SHUTDOWN, ShutDownHandler}, {FB_CMD_REBOOT, RebootHandler}, {FB_CMD_REBOOT_BOOTLOADER, RebootBootloaderHandler}, {FB_CMD_REBOOT_FASTBOOT, RebootFastbootHandler}, {FB_CMD_REBOOT_RECOVERY, RebootRecoveryHandler}, }), - transport_(std::make_unique()) {} + transport_(std::make_unique()), + boot_control_hal_(IBootControl::getService()) {} FastbootDevice::~FastbootDevice() { CloseDevice(); @@ -44,9 +52,21 @@ void FastbootDevice::CloseDevice() { transport_->Close(); } +std::string FastbootDevice::GetCurrentSlot() { + // Non-A/B devices must not have boot control HALs. + if (!boot_control_hal_) { + return ""; + } + std::string suffix; + auto cb = [&suffix](hidl_string s) { suffix = s; }; + boot_control_hal_->getSuffix(boot_control_hal_->getCurrentSlot(), cb); + return suffix; +} + bool FastbootDevice::WriteStatus(FastbootResult result, const std::string& message) { constexpr size_t kResponseReasonSize = 4; constexpr size_t kNumResponseTypes = 4; // "FAIL", "OKAY", "INFO", "DATA" + char buf[FB_RESPONSE_SZ]; constexpr size_t kMaxMessageSize = sizeof(buf) - kResponseReasonSize; size_t msg_len = std::min(kMaxMessageSize, message.size()); diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h index fec42a747..109249994 100644 --- a/fastboot/device/fastboot_device.h +++ b/fastboot/device/fastboot_device.h @@ -22,10 +22,11 @@ #include #include +#include + #include "commands.h" #include "transport.h" - -class FastbootDevice; +#include "variables.h" class FastbootDevice { public: @@ -36,17 +37,21 @@ class FastbootDevice { void ExecuteCommands(); bool WriteStatus(FastbootResult result, const std::string& message); bool HandleData(bool read, std::vector* data); + std::string GetCurrentSlot(); std::vector& get_download_data() { return download_data_; } void set_upload_data(const std::vector& data) { upload_data_ = data; } void set_upload_data(std::vector&& data) { upload_data_ = std::move(data); } Transport* get_transport() { return transport_.get(); } + android::sp boot_control_hal() { + return boot_control_hal_; + } private: const std::unordered_map kCommandMap; std::unique_ptr transport_; - + android::sp boot_control_hal_; std::vector download_data_; std::vector upload_data_; }; diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp new file mode 100644 index 000000000..c8d2b3eb1 --- /dev/null +++ b/fastboot/device/utility.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utility.h" + +using android::hardware::boot::V1_0::Slot; + +bool GetSlotNumber(const std::string& slot, Slot* number) { + if (slot.size() != 1) { + return false; + } + if (slot[0] < 'a' || slot[0] > 'z') { + return false; + } + *number = slot[0] - 'a'; + return true; +} diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h new file mode 100644 index 000000000..867d693ba --- /dev/null +++ b/fastboot/device/utility.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +#include + +bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number); diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp new file mode 100644 index 000000000..153ab9274 --- /dev/null +++ b/fastboot/device/variables.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "variables.h" + +#include +#include +#include +#include +#include +#include + +#include "fastboot_device.h" +#include "utility.h" + +using ::android::hardware::boot::V1_0::BoolResult; +using ::android::hardware::boot::V1_0::Slot; + +constexpr int kMaxDownloadSizeDefault = 0x20000000; +constexpr char kFastbootProtocolVersion[] = "0.4"; + +std::string GetVersion(FastbootDevice* /* device */, const std::vector& /* args */) { + return kFastbootProtocolVersion; +} + +std::string GetBootloaderVersion(FastbootDevice* /* device */, + const std::vector& /* args */) { + return android::base::GetProperty("ro.bootloader", ""); +} + +std::string GetBasebandVersion(FastbootDevice* /* device */, + const std::vector& /* args */) { + return android::base::GetProperty("ro.build.expect.baseband", ""); +} + +std::string GetProduct(FastbootDevice* /* device */, const std::vector& /* args */) { + return android::base::GetProperty("ro.product.device", ""); +} + +std::string GetSerial(FastbootDevice* /* device */, const std::vector& /* args */) { + return android::base::GetProperty("ro.serialno", ""); +} + +std::string GetSecure(FastbootDevice* /* device */, const std::vector& /* args */) { + return android::base::GetBoolProperty("ro.secure", "") ? "yes" : "no"; +} + +std::string GetCurrentSlot(FastbootDevice* device, const std::vector& /* args */) { + std::string suffix = device->GetCurrentSlot(); + return suffix.size() == 2 ? suffix.substr(1) : suffix; +} + +std::string GetSlotCount(FastbootDevice* device, const std::vector& /* args */) { + auto boot_control_hal = device->boot_control_hal(); + if (!boot_control_hal) { + return "0"; + } + return std::to_string(boot_control_hal->getNumberSlots()); +} + +std::string GetSlotSuccessful(FastbootDevice* device, const std::vector& args) { + if (args.empty()) { + return "no"; + } + Slot slot; + if (!GetSlotNumber(args[0], &slot)) { + return "no"; + } + auto boot_control_hal = device->boot_control_hal(); + if (!boot_control_hal) { + return "no"; + } + return boot_control_hal->isSlotMarkedSuccessful(slot) == BoolResult::TRUE ? "yes" : "no"; +} + +std::string GetSlotUnbootable(FastbootDevice* device, const std::vector& args) { + if (args.empty()) { + return "no"; + } + Slot slot; + if (!GetSlotNumber(args[0], &slot)) { + return "no"; + } + auto boot_control_hal = device->boot_control_hal(); + if (!boot_control_hal) { + return "no"; + } + return boot_control_hal->isSlotBootable(slot) == BoolResult::TRUE ? "no" : "yes"; +} + +std::string GetMaxDownloadSize(FastbootDevice* /* device */, + const std::vector& /* args */) { + return std::to_string(kMaxDownloadSizeDefault); +} + +std::string GetUnlocked(FastbootDevice* /* device */, const std::vector& /* args */) { + return "yes"; +} + +std::string GetHasSlot(FastbootDevice* device, const std::vector& args) { + if (args.empty()) { + return "no"; + } + std::string slot_suffix = device->GetCurrentSlot(); + if (slot_suffix.empty()) { + return "no"; + } + return args[0] == "userdata" ? "no" : "yes"; +} diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h new file mode 100644 index 000000000..09ef8ecec --- /dev/null +++ b/fastboot/device/variables.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include + +class FastbootDevice; + +std::string GetVersion(FastbootDevice* device, const std::vector& args); +std::string GetBootloaderVersion(FastbootDevice* device, const std::vector& args); +std::string GetBasebandVersion(FastbootDevice* device, const std::vector& args); +std::string GetProduct(FastbootDevice* device, const std::vector& args); +std::string GetSerial(FastbootDevice* device, const std::vector& args); +std::string GetSecure(FastbootDevice* device, const std::vector& args); +std::string GetCurrentSlot(FastbootDevice* device, const std::vector& args); +std::string GetSlotCount(FastbootDevice* device, const std::vector& args); +std::string GetSlotSuccessful(FastbootDevice* device, const std::vector& args); +std::string GetSlotUnbootable(FastbootDevice* device, const std::vector& args); +std::string GetMaxDownloadSize(FastbootDevice* device, const std::vector& args); +std::string GetUnlocked(FastbootDevice* device, const std::vector& args); +std::string GetHasSlot(FastbootDevice* device, const std::vector& args);