fastbootd: Implement getvar all.
This implements getvar all by invoking each callback and writing an INFO status for each result. For commands that take arguments, the variable handler can specify a function that returns all possible arguments. Currently this only applies to partition variables. Bug: 78793464 Test: fastboot getvar all works Change-Id: I1cf84e06bf67614b6f56171c0ee6ca5d7ac383c9
This commit is contained in:
parent
1fb3fd7242
commit
0f6266305e
7 changed files with 140 additions and 22 deletions
|
@ -42,26 +42,66 @@ using ::android::hardware::boot::V1_0::CommandResult;
|
|||
using ::android::hardware::boot::V1_0::Slot;
|
||||
using namespace android::fs_mgr;
|
||||
|
||||
struct VariableHandlers {
|
||||
// Callback to retrieve the value of a single variable.
|
||||
std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)> get;
|
||||
// Callback to retrieve all possible argument combinations, for getvar all.
|
||||
std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args;
|
||||
};
|
||||
|
||||
static void GetAllVars(FastbootDevice* device, const std::string& name,
|
||||
const VariableHandlers& handlers) {
|
||||
if (!handlers.get_all_args) {
|
||||
std::string message;
|
||||
if (!handlers.get(device, std::vector<std::string>(), &message)) {
|
||||
return;
|
||||
}
|
||||
device->WriteInfo(android::base::StringPrintf("%s:%s", name.c_str(), message.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
auto all_args = handlers.get_all_args(device);
|
||||
for (const auto& args : all_args) {
|
||||
std::string message;
|
||||
if (!handlers.get(device, args, &message)) {
|
||||
continue;
|
||||
}
|
||||
std::string arg_string = android::base::Join(args, ":");
|
||||
device->WriteInfo(android::base::StringPrintf("%s:%s:%s", name.c_str(), arg_string.c_str(),
|
||||
message.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) {
|
||||
using VariableHandler =
|
||||
std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)>;
|
||||
const std::unordered_map<std::string, VariableHandler> 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},
|
||||
{FB_VAR_PARTITION_SIZE, GetPartitionSize},
|
||||
{FB_VAR_IS_LOGICAL, GetPartitionIsLogical},
|
||||
{FB_VAR_IS_USERSPACE, GetIsUserspace}};
|
||||
const std::unordered_map<std::string, VariableHandlers> kVariableMap = {
|
||||
{FB_VAR_VERSION, {GetVersion, nullptr}},
|
||||
{FB_VAR_VERSION_BOOTLOADER, {GetBootloaderVersion, nullptr}},
|
||||
{FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}},
|
||||
{FB_VAR_PRODUCT, {GetProduct, nullptr}},
|
||||
{FB_VAR_SERIALNO, {GetSerial, nullptr}},
|
||||
{FB_VAR_SECURE, {GetSecure, nullptr}},
|
||||
{FB_VAR_UNLOCKED, {GetUnlocked, nullptr}},
|
||||
{FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}},
|
||||
{FB_VAR_CURRENT_SLOT, {::GetCurrentSlot, nullptr}},
|
||||
{FB_VAR_SLOT_COUNT, {GetSlotCount, nullptr}},
|
||||
{FB_VAR_HAS_SLOT, {GetHasSlot, GetAllPartitionArgsNoSlot}},
|
||||
{FB_VAR_SLOT_SUCCESSFUL, {GetSlotSuccessful, nullptr}},
|
||||
{FB_VAR_SLOT_UNBOOTABLE, {GetSlotUnbootable, nullptr}},
|
||||
{FB_VAR_PARTITION_SIZE, {GetPartitionSize, GetAllPartitionArgsWithSlot}},
|
||||
{FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}},
|
||||
{FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}}};
|
||||
|
||||
if (args.size() < 2) {
|
||||
return device->WriteFail("Missing argument");
|
||||
}
|
||||
|
||||
// Special case: return all variables that we can.
|
||||
if (args[1] == "all") {
|
||||
for (const auto& [name, handlers] : kVariableMap) {
|
||||
GetAllVars(device, name, handlers);
|
||||
}
|
||||
return device->WriteOkay("");
|
||||
}
|
||||
|
||||
// args[0] is command name, args[1] is variable.
|
||||
auto found_variable = kVariableMap.find(args[1]);
|
||||
|
@ -71,7 +111,7 @@ bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args)
|
|||
|
||||
std::string message;
|
||||
std::vector<std::string> getvar_args(args.begin() + 2, args.end());
|
||||
if (!found_variable->second(device, getvar_args, &message)) {
|
||||
if (!found_variable->second.get(device, getvar_args, &message)) {
|
||||
return device->WriteFail(message);
|
||||
}
|
||||
return device->WriteOkay(message);
|
||||
|
|
|
@ -137,3 +137,7 @@ bool FastbootDevice::WriteOkay(const std::string& message) {
|
|||
bool FastbootDevice::WriteFail(const std::string& message) {
|
||||
return WriteStatus(FastbootResult::FAIL, message);
|
||||
}
|
||||
|
||||
bool FastbootDevice::WriteInfo(const std::string& message) {
|
||||
return WriteStatus(FastbootResult::INFO, message);
|
||||
}
|
||||
|
|
|
@ -39,9 +39,10 @@ class FastbootDevice {
|
|||
bool HandleData(bool read, std::vector<char>* data);
|
||||
std::string GetCurrentSlot();
|
||||
|
||||
// Shortcuts for writing OKAY and FAIL status results.
|
||||
// Shortcuts for writing status results.
|
||||
bool WriteOkay(const std::string& message);
|
||||
bool WriteFail(const std::string& message);
|
||||
bool WriteInfo(const std::string& message);
|
||||
|
||||
std::vector<char>& download_data() { return download_data_; }
|
||||
Transport* get_transport() { return transport_.get(); }
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
|
||||
#include "utility.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <fs_mgr_dm_linear.h>
|
||||
#include <liblp/liblp.h>
|
||||
|
@ -123,3 +128,33 @@ bool GetSlotNumber(const std::string& slot, Slot* number) {
|
|||
*number = slot[0] - 'a';
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> ListPartitions(FastbootDevice* device) {
|
||||
std::vector<std::string> partitions;
|
||||
|
||||
// First get physical partitions.
|
||||
struct dirent* de;
|
||||
std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir);
|
||||
while ((de = readdir(by_name.get())) != nullptr) {
|
||||
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
|
||||
continue;
|
||||
}
|
||||
struct stat s;
|
||||
std::string path = "/dev/block/by-name/" + std::string(de->d_name);
|
||||
if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) {
|
||||
partitions.emplace_back(de->d_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Next get logical partitions.
|
||||
if (auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME)) {
|
||||
uint32_t slot_number = SlotNumberForSlotSuffix(device->GetCurrentSlot());
|
||||
if (auto metadata = ReadMetadata(path->c_str(), slot_number)) {
|
||||
for (const auto& partition : metadata->partitions) {
|
||||
std::string partition_name = GetPartitionName(partition);
|
||||
partitions.emplace_back(partition_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return partitions;
|
||||
}
|
||||
|
|
|
@ -56,5 +56,5 @@ std::optional<std::string> FindPhysicalPartition(const std::string& name);
|
|||
bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
|
||||
bool* is_zero_length = nullptr);
|
||||
bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle);
|
||||
|
||||
bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number);
|
||||
std::vector<std::string> ListPartitions(FastbootDevice* device);
|
||||
|
|
|
@ -222,3 +222,37 @@ bool GetIsUserspace(FastbootDevice* /* device */, const std::vector<std::string>
|
|||
*message = "yes";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device) {
|
||||
std::vector<std::vector<std::string>> args;
|
||||
auto partitions = ListPartitions(device);
|
||||
for (const auto& partition : partitions) {
|
||||
args.emplace_back(std::initializer_list<std::string>{partition});
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> GetAllPartitionArgsNoSlot(FastbootDevice* device) {
|
||||
auto partitions = ListPartitions(device);
|
||||
|
||||
std::string slot_suffix = device->GetCurrentSlot();
|
||||
if (!slot_suffix.empty()) {
|
||||
auto names = std::move(partitions);
|
||||
for (const auto& name : names) {
|
||||
std::string slotless_name = name;
|
||||
if (android::base::EndsWith(name, "_a") || android::base::EndsWith(name, "_b")) {
|
||||
slotless_name = name.substr(0, name.rfind("_"));
|
||||
}
|
||||
if (std::find(partitions.begin(), partitions.end(), slotless_name) ==
|
||||
partitions.end()) {
|
||||
partitions.emplace_back(slotless_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> args;
|
||||
for (const auto& partition : partitions) {
|
||||
args.emplace_back(std::initializer_list<std::string>{partition});
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
|
|
@ -48,3 +48,7 @@ bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string
|
|||
std::string* message);
|
||||
bool GetIsUserspace(FastbootDevice* device, const std::vector<std::string>& args,
|
||||
std::string* message);
|
||||
|
||||
// Helpers for getvar all.
|
||||
std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device);
|
||||
std::vector<std::vector<std::string>> GetAllPartitionArgsNoSlot(FastbootDevice* device);
|
||||
|
|
Loading…
Reference in a new issue