Merge "Add Start/Stop/Reset to CapturedStdFd."
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index f764a0e..f6ce8e2 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -24,7 +24,7 @@
#include <android-base/macros.h>
-int syntax_error(const char*, ...);
+int syntax_error(const char*, ...) __attribute__((__format__(__printf__, 1, 2)));
void close_stdin();
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index b55ae95..451422f 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -130,7 +130,7 @@
" pull [-a] REMOTE... LOCAL\n"
" copy files/dirs from device\n"
" -a: preserve file timestamp and mode\n"
- " sync [all|data|odm|oem|product|system|vendor]\n"
+ " sync [all|data|odm|oem|product_services|product|system|vendor]\n"
" sync a local build from $ANDROID_PRODUCT_OUT to the device (default all)\n"
" -l: list but don't copy\n"
"\n"
@@ -1713,7 +1713,8 @@
}
if (src.empty()) src = "all";
- std::vector<std::string> partitions{"data", "odm", "oem", "product", "system", "vendor"};
+ std::vector<std::string> partitions{"data", "odm", "oem", "product", "product_services",
+ "system", "vendor"};
bool found = false;
for (const auto& partition : partitions) {
if (src == "all" || src == partition) {
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 095ad98..a7e454d 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -56,15 +56,6 @@
LOG(INFO) << adb_version();
}
-#if defined(_WIN32)
-static BOOL WINAPI ctrlc_handler(DWORD type) {
- // TODO: Consider trying to kill a starting up adb server (if we're in
- // launch_server) by calling GenerateConsoleCtrlEvent().
- exit(STATUS_CONTROL_C_EXIT);
- return TRUE;
-}
-#endif
-
void adb_server_cleanup() {
// Upon exit, we want to clean up in the following order:
// 1. close_smartsockets, so that we don't get any new clients
@@ -97,12 +88,16 @@
}
}
- SetConsoleCtrlHandler(ctrlc_handler, TRUE);
-#else
+ // TODO: On Ctrl-C, consider trying to kill a starting up adb server (if we're in
+ // launch_server) by calling GenerateConsoleCtrlEvent().
+
+ // On Windows, SIGBREAK is when Ctrl-Break is pressed or the console window is closed. It should
+ // act like Ctrl-C.
+ signal(SIGBREAK, [](int) { raise(SIGINT); });
+#endif
signal(SIGINT, [](int) {
fdevent_run_on_main_thread([]() { exit(0); });
});
-#endif
char* leak = getenv("ADB_LEAK");
if (leak && strcmp(leak, "1") == 0) {
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index ed5f944..76500d4 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -209,7 +209,7 @@
bool system_verified = !(android::base::GetProperty("partition.system.verified", "").empty());
bool vendor_verified = !(android::base::GetProperty("partition.vendor.verified", "").empty());
- std::vector<std::string> partitions = {"/odm", "/oem", "/product", "/vendor"};
+ std::vector<std::string> partitions{"/odm", "/oem", "/product_services", "/product", "/vendor"};
if (android::base::GetBoolProperty("ro.build.system_root_image", false)) {
partitions.push_back("/");
} else {
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index c6936f1..71025ad 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -22,6 +22,7 @@
#include <sys/socket.h>
#endif
+#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
@@ -199,6 +200,17 @@
return Socketpair(AF_UNIX, type, 0, left, right);
}
+// Using fdopen with unique_fd correctly is more annoying than it should be,
+// because fdopen doesn't close the file descriptor received upon failure.
+inline FILE* Fdopen(unique_fd&& ufd, const char* mode) {
+ int fd = ufd.release();
+ FILE* file = fdopen(fd, mode);
+ if (!file) {
+ close(fd);
+ }
+ return file;
+}
+
#endif // !defined(_WIN32)
} // namespace base
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 1e853bf..b1c2958 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -42,34 +42,79 @@
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>&)>;
- 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]);
if (found_variable == kVariableMap.end()) {
- return device->WriteStatus(FastbootResult::FAIL, "Unknown variable");
+ return device->WriteFail("Unknown variable");
}
+ std::string message;
std::vector<std::string> getvar_args(args.begin() + 2, args.end());
- return found_variable->second(device, getvar_args);
+ if (!found_variable->second.get(device, getvar_args, &message)) {
+ return device->WriteFail(message);
+ }
+ return device->WriteOkay(message);
}
bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 6ed6d32..55aca9c 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -137,3 +137,7 @@
bool FastbootDevice::WriteFail(const std::string& message) {
return WriteStatus(FastbootResult::FAIL, message);
}
+
+bool FastbootDevice::WriteInfo(const std::string& message) {
+ return WriteStatus(FastbootResult::INFO, message);
+}
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index addc2ef..171e7ae 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -39,9 +39,10 @@
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(); }
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index ec84576..0157e7f 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -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 @@
*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;
+}
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
index 0931fc3..4f0d079 100644
--- a/fastboot/device/utility.h
+++ b/fastboot/device/utility.h
@@ -56,5 +56,5 @@
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);
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 65cfea3..91e844a 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -35,141 +35,224 @@
constexpr int kMaxDownloadSizeDefault = 0x20000000;
constexpr char kFastbootProtocolVersion[] = "0.4";
-bool GetVersion(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay(kFastbootProtocolVersion);
+bool GetVersion(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = kFastbootProtocolVersion;
+ return true;
}
-bool GetBootloaderVersion(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay(android::base::GetProperty("ro.bootloader", ""));
+bool GetBootloaderVersion(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = android::base::GetProperty("ro.bootloader", "");
+ return true;
}
-bool GetBasebandVersion(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay(android::base::GetProperty("ro.build.expect.baseband", ""));
+bool GetBasebandVersion(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = android::base::GetProperty("ro.build.expect.baseband", "");
+ return true;
}
-bool GetProduct(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay(android::base::GetProperty("ro.product.device", ""));
+bool GetProduct(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = android::base::GetProperty("ro.product.device", "");
+ return true;
}
-bool GetSerial(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay(android::base::GetProperty("ro.serialno", ""));
+bool GetSerial(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = android::base::GetProperty("ro.serialno", "");
+ return true;
}
-bool GetSecure(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay(android::base::GetBoolProperty("ro.secure", "") ? "yes" : "no");
+bool GetSecure(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = android::base::GetBoolProperty("ro.secure", "") ? "yes" : "no";
+ return true;
}
-bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& /* args */,
+ std::string* message) {
std::string suffix = device->GetCurrentSlot();
- std::string slot = suffix.size() == 2 ? suffix.substr(1) : suffix;
- return device->WriteOkay(slot);
+ *message = suffix.size() == 2 ? suffix.substr(1) : suffix;
+ return true;
}
-bool GetSlotCount(FastbootDevice* device, const std::vector<std::string>& /* args */) {
+bool GetSlotCount(FastbootDevice* device, const std::vector<std::string>& /* args */,
+ std::string* message) {
auto boot_control_hal = device->boot_control_hal();
if (!boot_control_hal) {
- return "0";
+ *message = "0";
+ } else {
+ *message = std::to_string(boot_control_hal->getNumberSlots());
}
- return device->WriteOkay(std::to_string(boot_control_hal->getNumberSlots()));
+ return true;
}
-bool GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args) {
+bool GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message) {
if (args.empty()) {
- return device->WriteFail("Missing argument");
+ *message = "Missing argument";
+ return false;
}
Slot slot;
if (!GetSlotNumber(args[0], &slot)) {
- return device->WriteFail("Invalid slot");
+ *message = "Invalid slot";
+ return false;
}
auto boot_control_hal = device->boot_control_hal();
if (!boot_control_hal) {
- return device->WriteFail("Device has no slots");
+ *message = "Device has no slots";
+ return false;
}
if (boot_control_hal->isSlotMarkedSuccessful(slot) != BoolResult::TRUE) {
- return device->WriteOkay("no");
+ *message = "no";
+ } else {
+ *message = "yes";
}
- return device->WriteOkay("yes");
+ return true;
}
-bool GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args) {
+bool GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message) {
if (args.empty()) {
- return device->WriteFail("Missing argument");
+ *message = "Missing argument";
+ return false;
}
Slot slot;
if (!GetSlotNumber(args[0], &slot)) {
- return device->WriteFail("Invalid slot");
+ *message = "Invalid slot";
+ return false;
}
auto boot_control_hal = device->boot_control_hal();
if (!boot_control_hal) {
- return device->WriteFail("Device has no slots");
+ *message = "Device has no slots";
+ return false;
}
if (boot_control_hal->isSlotBootable(slot) != BoolResult::TRUE) {
- return device->WriteOkay("yes");
+ *message = "yes";
+ } else {
+ *message = "no";
}
- return device->WriteOkay("no");
+ return true;
}
-bool GetMaxDownloadSize(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay(std::to_string(kMaxDownloadSizeDefault));
+bool GetMaxDownloadSize(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = std::to_string(kMaxDownloadSizeDefault);
+ return true;
}
-bool GetUnlocked(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay("yes");
+bool GetUnlocked(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *message = "yes";
+ return true;
}
-bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args) {
+bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message) {
if (args.empty()) {
- return device->WriteFail("Missing argument");
+ *message = "Missing argument";
+ return false;
}
std::string slot_suffix = device->GetCurrentSlot();
if (slot_suffix.empty()) {
- return device->WriteOkay("no");
+ *message = "no";
+ return true;
}
std::string partition_name = args[0] + slot_suffix;
if (FindPhysicalPartition(partition_name) ||
LogicalPartitionExists(partition_name, slot_suffix)) {
- return device->WriteOkay("yes");
+ *message = "yes";
+ } else {
+ *message = "no";
}
- return device->WriteOkay("no");
+ return true;
}
-bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args) {
+bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message) {
if (args.size() < 1) {
- return device->WriteFail("Missing argument");
+ *message = "Missing argument";
+ return false;
}
// Zero-length partitions cannot be created through device-mapper, so we
// special case them here.
bool is_zero_length;
if (LogicalPartitionExists(args[0], device->GetCurrentSlot(), &is_zero_length) &&
is_zero_length) {
- return device->WriteOkay("0");
+ *message = "0";
+ return true;
}
// Otherwise, open the partition as normal.
PartitionHandle handle;
if (!OpenPartition(device, args[0], &handle)) {
- return device->WriteFail("Could not open partition");
+ *message = "Could not open partition";
+ return false;
}
uint64_t size = get_block_device_size(handle.fd());
- return device->WriteOkay(android::base::StringPrintf("%" PRIX64, size));
+ *message = android::base::StringPrintf("0x%" PRIX64, size);
+ return true;
}
-bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args) {
+bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message) {
if (args.size() < 1) {
- return device->WriteFail("Missing argument");
+ *message = "Missing argument";
+ return false;
}
// Note: if a partition name is in both the GPT and the super partition, we
// return "true", to be consistent with prefering to flash logical partitions
// over physical ones.
std::string partition_name = args[0];
if (LogicalPartitionExists(partition_name, device->GetCurrentSlot())) {
- return device->WriteOkay("yes");
+ *message = "yes";
+ return true;
}
if (FindPhysicalPartition(partition_name)) {
- return device->WriteOkay("no");
+ *message = "no";
+ return true;
}
- return device->WriteFail("Partition not found");
+ *message = "Partition not found";
+ return false;
}
-bool GetIsUserspace(FastbootDevice* device, const std::vector<std::string>& /* args */) {
- return device->WriteOkay("yes");
+bool GetIsUserspace(FastbootDevice* /* device */, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ *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;
}
diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h
index 554a080..c3a64cf 100644
--- a/fastboot/device/variables.h
+++ b/fastboot/device/variables.h
@@ -21,19 +21,34 @@
class FastbootDevice;
-bool GetVersion(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetBootloaderVersion(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetBasebandVersion(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetProduct(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetSerial(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetSecure(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetSlotCount(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetMaxDownloadSize(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetUnlocked(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args);
-bool GetIsUserspace(FastbootDevice* device, const std::vector<std::string>& args);
+bool GetVersion(FastbootDevice* device, const std::vector<std::string>& args, std::string* message);
+bool GetBootloaderVersion(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetBasebandVersion(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetProduct(FastbootDevice* device, const std::vector<std::string>& args, std::string* message);
+bool GetSerial(FastbootDevice* device, const std::vector<std::string>& args, std::string* message);
+bool GetSecure(FastbootDevice* device, const std::vector<std::string>& args, std::string* message);
+bool GetCurrentSlot(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetSlotCount(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetSlotSuccessful(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetSlotUnbootable(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetMaxDownloadSize(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetUnlocked(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetHasSlot(FastbootDevice* device, const std::vector<std::string>& args, std::string* message);
+bool GetPartitionSize(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
+bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string>& args,
+ 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);
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 6a52b12..d80e986 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -88,7 +88,9 @@
}
void fb_reinit(Transport* transport) {
- fb->set_transport(transport);
+ if (Transport* old_transport = fb->set_transport(transport)) {
+ delete old_transport;
+ }
}
const std::string fb_get_error() {
@@ -392,6 +394,6 @@
}
fprintf(stderr, "OKAY\n");
- fb->set_transport(nullptr);
+ fb_reinit(nullptr);
return true;
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 2887d3b..1aef567 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1847,6 +1847,10 @@
int status = fb_execute_queue() ? EXIT_FAILURE : EXIT_SUCCESS;
fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
+
+ if (Transport* old_transport = fb.set_transport(nullptr)) {
+ delete old_transport;
+ }
return status;
}
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index ceee066..f9e640a 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -58,7 +58,6 @@
}
FastBootDriver::~FastBootDriver() {
- set_transport(nullptr);
}
RetCode FastBootDriver::Boot(std::string* response, std::vector<std::string>* info) {
@@ -127,7 +126,7 @@
return RawCommand(Commands::FLASH + part);
}
-RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint32_t>>* parts) {
+RetCode FastBootDriver::Partitions(std::vector<std::tuple<std::string, uint64_t>>* parts) {
std::vector<std::string> all;
RetCode ret;
if ((ret = GetVarAll(&all))) {
@@ -141,7 +140,7 @@
if (std::regex_match(s, sm, reg)) {
std::string m1(sm[1]);
std::string m2(sm[2]);
- uint32_t tmp = strtol(m2.c_str(), 0, 16);
+ uint64_t tmp = strtoll(m2.c_str(), 0, 16);
parts->push_back(std::make_tuple(m1, tmp));
}
}
@@ -537,12 +536,9 @@
return 0;
}
-void FastBootDriver::set_transport(Transport* transport) {
- if (transport_) {
- transport_->Close();
- delete transport_;
- }
- transport_ = transport;
+Transport* FastBootDriver::set_transport(Transport* transport) {
+ std::swap(transport_, transport);
+ return transport;
}
} // End namespace fastboot
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 4647945..ca9003a 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -99,7 +99,7 @@
RetCode FlashPartition(const std::string& part, int fd, uint32_t sz);
RetCode FlashPartition(const std::string& part, sparse_file* s);
- RetCode Partitions(std::vector<std::tuple<std::string, uint32_t>>* parts);
+ RetCode Partitions(std::vector<std::tuple<std::string, uint64_t>>* parts);
RetCode Require(const std::string& var, const std::vector<std::string>& allowed, bool* reqmet,
bool invert = false);
@@ -109,8 +109,8 @@
std::string Error();
RetCode WaitForDisconnect();
- // Note: changing the transport will close and delete the existing one.
- void set_transport(Transport* transport);
+ // Note: set_transport will return the previous transport.
+ Transport* set_transport(Transport* transport);
Transport* transport() const { return transport_; }
// This is temporarily public for engine.cpp
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index 0a87598..4da71ca 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -133,7 +133,6 @@
fb.reset();
if (transport) {
- transport->Close();
transport.reset();
}
@@ -188,7 +187,6 @@
ASSERT_EQ(fb->RawCommand("flashing " + cmd, &resp), SUCCESS)
<< "Attempting to change locked state, but 'flashing" + cmd + "' command failed";
fb.reset();
- transport->Close();
transport.reset();
printf("PLEASE RESPOND TO PROMPT FOR '%sing' BOOTLOADER ON DEVICE\n", cmd.c_str());
while (UsbStillAvailible())
@@ -249,7 +247,6 @@
}
if (transport) {
- transport->Close();
transport.reset();
}
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 1d30f8b..dd64082 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -304,13 +304,13 @@
}
TEST_F(Conformance, PartitionInfo) {
- std::vector<std::tuple<std::string, uint32_t>> parts;
+ std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed";
EXPECT_GT(parts.size(), 0)
<< "getvar:all did not report any partition-size: through INFO responses";
std::set<std::string> allowed{"ext4", "f2fs", "raw"};
for (const auto p : parts) {
- EXPECT_GT(std::get<1>(p), 0);
+ EXPECT_GE(std::get<1>(p), 0);
std::string part(std::get<0>(p));
std::set<std::string> allowed{"ext4", "f2fs", "raw"};
std::string resp;
@@ -340,7 +340,7 @@
// Can't run out of alphabet letters...
ASSERT_LE(num_slots, 26) << "What?! You can't have more than 26 slots";
- std::vector<std::tuple<std::string, uint32_t>> parts;
+ std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed";
std::map<std::string, std::set<char>> part_slots;
@@ -587,14 +587,14 @@
std::vector<char> buf{'a', 'o', 's', 'p'};
EXPECT_EQ(fb->Download(buf), SUCCESS) << "Download failed in unlocked mode";
;
- std::vector<std::tuple<std::string, uint32_t>> parts;
+ std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed in unlocked mode";
}
TEST_F(LockPermissions, DownloadFlash) {
std::vector<char> buf{'a', 'o', 's', 'p'};
EXPECT_EQ(fb->Download(buf), SUCCESS) << "Download failed in locked mode";
- std::vector<std::tuple<std::string, uint32_t>> parts;
+ std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed in locked mode";
std::string resp;
for (const auto tup : parts) {
@@ -607,7 +607,7 @@
}
TEST_F(LockPermissions, Erase) {
- std::vector<std::tuple<std::string, uint32_t>> parts;
+ std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed";
std::string resp;
for (const auto tup : parts) {
@@ -619,7 +619,7 @@
}
TEST_F(LockPermissions, SetActive) {
- std::vector<std::tuple<std::string, uint32_t>> parts;
+ std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed";
std::string resp;
@@ -916,7 +916,7 @@
TEST_P(AnyPartition, ReportedGetVarAll) {
// As long as the partition is reported in INFO, it would be tested by generic Conformance
- std::vector<std::tuple<std::string, uint32_t>> parts;
+ std::vector<std::tuple<std::string, uint64_t>> parts;
ASSERT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed";
const std::string name = GetParam().first;
if (GetParam().second.slots) {
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp b/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
index ee510e9..7c595f4 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
+++ b/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
@@ -12,6 +12,10 @@
const int serial_fd)
: transport_(std::move(transport)), serial_fd_(serial_fd) {}
+UsbTransportSniffer::~UsbTransportSniffer() {
+ Close();
+}
+
ssize_t UsbTransportSniffer::Read(void* data, size_t len) {
ProcessSerial();
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h b/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
index 693f042..89cc009 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
+++ b/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
@@ -68,6 +68,7 @@
};
UsbTransportSniffer(std::unique_ptr<UsbTransport> transport, const int serial_fd = 0);
+ ~UsbTransportSniffer() override;
virtual ssize_t Read(void* data, size_t len) override;
virtual ssize_t Write(const void* data, size_t len) override;
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index 9b779dd..6363aa5 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -95,7 +95,7 @@
public:
explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
: handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
- ~LinuxUsbTransport() override = default;
+ ~LinuxUsbTransport() override;
ssize_t Read(void* data, size_t len) override;
ssize_t Write(const void* data, size_t len) override;
@@ -387,6 +387,10 @@
return usb;
}
+LinuxUsbTransport::~LinuxUsbTransport() {
+ Close();
+}
+
ssize_t LinuxUsbTransport::Write(const void* _data, size_t len)
{
unsigned char *data = (unsigned char*) _data;
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index 4d48f6e..ed02c4a 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -70,7 +70,7 @@
// A timeout of 0 is blocking
OsxUsbTransport(std::unique_ptr<usb_handle> handle, uint32_t ms_timeout = 0)
: handle_(std::move(handle)), ms_timeout_(ms_timeout) {}
- ~OsxUsbTransport() override = default;
+ ~OsxUsbTransport() override;
ssize_t Read(void* data, size_t len) override;
ssize_t Write(const void* data, size_t len) override;
@@ -471,6 +471,10 @@
return new OsxUsbTransport(std::move(handle), timeout_ms);
}
+OsxUsbTransport::~OsxUsbTransport() {
+ Close();
+}
+
int OsxUsbTransport::Close() {
/* TODO: Something better here? */
return 0;
diff --git a/fastboot/usb_windows.cpp b/fastboot/usb_windows.cpp
index 8c60a71..b00edb3 100644
--- a/fastboot/usb_windows.cpp
+++ b/fastboot/usb_windows.cpp
@@ -69,7 +69,7 @@
class WindowsUsbTransport : public UsbTransport {
public:
WindowsUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
- ~WindowsUsbTransport() override = default;
+ ~WindowsUsbTransport() override;
ssize_t Read(void* data, size_t len) override;
ssize_t Write(const void* data, size_t len) override;
@@ -250,6 +250,10 @@
}
}
+WindowsUsbTransport::~WindowsUsbTransport() {
+ Close();
+}
+
int WindowsUsbTransport::Close() {
DBG("usb_close\n");
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 117f5d5..190c650 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -314,7 +314,7 @@
return nullptr;
}
- // Read the priamry copy, and if that fails, try the backup.
+ // Read the primary copy, and if that fails, try the backup.
std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
if (metadata) {
return metadata;
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index a10e636..c42ae49 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -89,29 +89,20 @@
"libbase",
"liblog",
"libunwindstack",
- "libdexfile",
],
static_libs: [
"libprocinfo",
],
-
- // libdexfile will eventually properly export headers, for now
- // include these directly.
- include_dirs: [
- "art/runtime",
- ],
},
android: {
static_libs: ["libasync_safe"],
},
vendor: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- exclude_shared_libs: ["libdexfile"],
},
recovery: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- exclude_shared_libs: ["libdexfile"],
},
},
whole_static_libs: ["libdemangle"],
@@ -154,7 +145,6 @@
shared_libs: [
"libbacktrace_test",
"libbacktrace",
- "libdexfile",
"libbase",
"liblog",
"libunwindstack",
@@ -174,12 +164,6 @@
},
},
- // libdexfile will eventually properly export headers, for now
- // include these directly.
- include_dirs: [
- "art/runtime",
- ],
-
test_suites: ["device-tests"],
data: [
"testdata/arm/*",
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 2606aa9..fd3f602 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -158,4 +158,5 @@
"libbase",
"libziparchive",
],
+ recovery_available: true,
}
diff --git a/llkd/Android.bp b/llkd/Android.bp
index a6edd26..62a637d 100644
--- a/llkd/Android.bp
+++ b/llkd/Android.bp
@@ -20,6 +20,12 @@
export_include_dirs: ["include"],
cflags: ["-Werror"],
+
+ product_variables: {
+ debuggable: {
+ cppflags: ["-D__PTRACE_ENABLED__"],
+ },
+ },
}
cc_binary {
@@ -39,4 +45,9 @@
cflags: ["-Werror"],
init_rc: ["llkd.rc"],
+ product_variables: {
+ debuggable: {
+ init_rc: ["llkd-debuggable.rc"],
+ },
+ },
}
diff --git a/llkd/README.md b/llkd/README.md
index 2314583..1f69718 100644
--- a/llkd/README.md
+++ b/llkd/README.md
@@ -23,6 +23,9 @@
Operations
----------
+There are two detection scenarios. Persistent D or Z state, and persistent
+stack signature.
+
If a thread is in D or Z state with no forward progress for longer than
ro.llk.timeout_ms, or ro.llk.[D|Z].timeout_ms, kill the process or parent
process respectively. If another scan shows the same process continues to
@@ -32,6 +35,26 @@
double the expected time to flow through the mainloop. Sampling is every
ro.llk_sample_ms.
+For usedebug releases only, persistent stack signature checking is enabled.
+If a thread in any state but Z, has a persistent listed ro.llk.stack kernel
+symbol always being reported, even if there is forward scheduling progress, for
+longer than ro.llk.timeout_ms, or ro.llk.stack.timeout_ms, then issue a kill
+to the process. If another scan shows the same process continues to exist,
+then have a confirmed live-lock condition and need to panic. There is no
+ABA detection since forward scheduling progress is allowed, thus the condition
+for the symbols are:
+
+- Check is looking for " " + __symbol__+ "0x" in /proc/<pid>/stack.
+- The __symbol__ should be rare and short lived enough that on a typical
+ system the function is seen at most only once in a sample over the timeout
+ period of ro.llk.stack.timeout_ms, samples occur every ro.llk.check_ms. This
+ can be the only way to prevent a false trigger as there is no ABA protection.
+- Persistent continuously when the live lock condition exists.
+- Should be just below the function that is calling the lock that could
+ contend, because if the lock is below or in the symbol function, the
+ symbol will show in all affected processes, not just the one that
+ caused the lockup.
+
Default will not monitor init, or [kthreadd] and all that [kthreadd] spawns.
This reduces the effectiveness of llkd by limiting its coverage. If there is
value in covering [kthreadd] spawned threads, the requirement will be that
@@ -40,7 +63,9 @@
coding hygiene, a common request to add such to publicly reviewed kernel.org
maintained drivers). For instance use wait_event_interruptible() instead of
wait_event(). The blacklists can be adjusted accordingly if these
-conditions are met to cover kernel components.
+conditions are met to cover kernel components. For the stack symbol checking,
+there is an additional process blacklist so that we do not incide sepolicy
+violations on services that block ptrace operations.
An accompanying gTest set have been added, and will setup a persistent D or Z
process, with and without forward progress, but not in a live-lock state
@@ -93,14 +118,31 @@
#### ro.llk.Z.timeout_ms
default ro.llk.timeout_ms, Z maximum timelimit.
+#### ro.llk.stack.timeout_ms
+default ro.llk.timeout_ms,
+checking for persistent stack symbols maximum timelimit.
+Only active on userdebug and eng builds.
+
#### ro.llk.check_ms
default 2 minutes samples of threads for D or Z.
+#### ro.llk.stack
+default *empty* or false, comma separated list of kernel symbols.
+The string "*false*" is the equivalent to an *empty* list.
+Look for kernel stack symbols that if ever persistently present can
+indicate a subsystem is locked up.
+Beware, check does not on purpose do forward scheduling ABA except by polling
+every ro.llk_check_ms over the period ro.llk.stack.timeout_ms, so stack symbol
+should be exceptionally rare and fleeting.
+One must be convinced that it is virtually *impossible* for symbol to show up
+persistently in all samples of the stack.
+Only active on userdebug and eng builds.
+
#### ro.llk.blacklist.process
default 0,1,2 (kernel, init and [kthreadd]) plus process names
init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,
[watchdogd],[watchdogd/0],...,[watchdogd/***get_nprocs**-1*].
-The string false is the equivalent to an empty list.
+The string "*false*" is the equivalent to an *empty* list.
Do not watch these processes. A process can be comm, cmdline or pid reference.
NB: automated default here can be larger than the current maximum property
size of 92.
@@ -108,15 +150,23 @@
#### ro.llk.blacklist.parent
default 0,2 (kernel and [kthreadd]).
-The string false is the equivalent to an empty list.
+The string "*false*" is the equivalent to an *empty* list.
Do not watch processes that have this parent.
A parent process can be comm, cmdline or pid reference.
#### ro.llk.blacklist.uid
default *empty* or false, comma separated list of uid numbers or names.
-The string false is the equivalent to an empty list.
+The string "*false*" is the equivalent to an *empty* list.
Do not watch processes that match this uid.
+#### ro.llk.blacklist.process.stack
+default process names init,lmkd,lmkd.llkd,llkd,keystore,logd.
+The string "*false*" is the equivalent to an *empty* list.
+This subset of processes are not monitored for live lock stack signatures.
+Also prevents the sepolicy violation associated with processes that block
+ptrace, as these can not be checked anyways.
+Only active on userdebug and eng builds.
+
Architectural Concerns
----------------------
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index e3ae4bb..d0188ec 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -43,9 +43,12 @@
#define KHT_TIMEOUT_PROPERTY "ro.khungtask.timeout"
#define LLK_D_TIMEOUT_MS_PROPERTY "ro.llk.D.timeout_ms"
#define LLK_Z_TIMEOUT_MS_PROPERTY "ro.llk.Z.timeout_ms"
+#define LLK_STACK_TIMEOUT_MS_PROPERTY "ro.llk.stack.timeout_ms"
#define LLK_CHECK_MS_PROPERTY "ro.llk.check_ms"
/* LLK_CHECK_MS_DEFAULT = actual timeout_ms / LLK_CHECKS_PER_TIMEOUT_DEFAULT */
#define LLK_CHECKS_PER_TIMEOUT_DEFAULT 5
+#define LLK_CHECK_STACK_PROPERTY "ro.llk.stack"
+#define LLK_CHECK_STACK_DEFAULT ""
#define LLK_BLACKLIST_PROCESS_PROPERTY "ro.llk.blacklist.process"
#define LLK_BLACKLIST_PROCESS_DEFAULT \
"0,1,2,init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
@@ -53,6 +56,8 @@
#define LLK_BLACKLIST_PARENT_DEFAULT "0,2,[kthreadd]"
#define LLK_BLACKLIST_UID_PROPERTY "ro.llk.blacklist.uid"
#define LLK_BLACKLIST_UID_DEFAULT ""
+#define LLK_BLACKLIST_STACK_PROPERTY "ro.llk.blacklist.process.stack"
+#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,/system/bin/keystore"
/* clang-format on */
__END_DECLS
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index bb55d1f..58c2ba8 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -73,7 +73,14 @@
bool llkMlockall = LLK_MLOCKALL_DEFAULT; // run mlocked
bool llkTestWithKill = LLK_KILLTEST_DEFAULT; // issue test kills
milliseconds llkTimeoutMs = LLK_TIMEOUT_MS_DEFAULT; // default timeout
-enum { llkStateD, llkStateZ, llkNumStates }; // state indexes
+enum { // enum of state indexes
+ llkStateD, // Persistent 'D' state
+ llkStateZ, // Persistent 'Z' state
+#ifdef __PTRACE_ENABLED__ // Extra privileged states
+ llkStateStack, // stack signature
+#endif // End of extra privilege
+ llkNumStates, // Maxumum number of states
+}; // state indexes
milliseconds llkStateTimeoutMs[llkNumStates]; // timeout override for each detection state
milliseconds llkCheckMs; // checking interval to inspect any
// persistent live-locked states
@@ -83,6 +90,10 @@
// Provides a wide angle of margin b/c khtTimeout is also its granularity.
seconds khtTimeout = duration_cast<seconds>(llkTimeoutMs * (1 + LLK_CHECKS_PER_TIMEOUT_DEFAULT) /
LLK_CHECKS_PER_TIMEOUT_DEFAULT);
+#ifdef __PTRACE_ENABLED__
+// list of stack symbols to search for persistence.
+std::unordered_set<std::string> llkCheckStackSymbols;
+#endif
// Blacklist variables, initialized with comma separated lists of high false
// positive and/or dangerous references, e.g. without self restart, for pid,
@@ -97,6 +108,11 @@
std::unordered_set<std::string> llkBlacklistParent;
// list of uids, and uid names, to skip, default nothing
std::unordered_set<std::string> llkBlacklistUid;
+#ifdef __PTRACE_ENABLED__
+// list of names to skip stack checking. "init", "lmkd", "llkd", "keystore" or
+// "logd" (if not userdebug).
+std::unordered_set<std::string> llkBlacklistStack;
+#endif
class dir {
public:
@@ -263,6 +279,9 @@
// forward scheduling progress.
milliseconds update; // llkUpdate millisecond signature of last.
milliseconds count; // duration in state.
+#ifdef __PTRACE_ENABLED__ // Privileged state checking
+ milliseconds count_stack; // duration where stack is stagnant.
+#endif // End privilege
pid_t pid; // /proc/<pid> before iterating through
// /proc/<pid>/task/<tid> for threads.
pid_t ppid; // /proc/<tid>/stat field 4 parent pid.
@@ -272,6 +291,9 @@
std::string cmdline; // cached /cmdline content
char state; // /proc/<tid>/stat field 3: Z or D
// (others we do not monitor: S, R, T or ?)
+#ifdef __PTRACE_ENABLED__ // Privileged state checking
+ char stack; // index in llkCheckStackSymbols for matches
+#endif // and with maximum index PROP_VALUE_MAX/2.
char comm[TASK_COMM_LEN + 3]; // space for adding '[' and ']'
bool exeMissingValid; // exeMissing has been cached
bool cmdlineValid; // cmdline has been cached
@@ -286,11 +308,17 @@
nrSwitches(0),
update(llkUpdate),
count(0ms),
+#ifdef __PTRACE_ENABLED__
+ count_stack(0ms),
+#endif
pid(pid),
ppid(ppid),
uid(-1),
time(time),
state(state),
+#ifdef __PTRACE_ENABLED__
+ stack(-1),
+#endif
exeMissingValid(false),
cmdlineValid(false),
updated(true),
@@ -343,6 +371,10 @@
void reset(void) { // reset cache, if we detected pid rollover
uid = -1;
state = '?';
+#ifdef __PTRACE_ENABLED__
+ count_stack = 0ms;
+ stack = -1;
+#endif
cmdline = "";
comm[0] = '\0';
exeMissingValid = false;
@@ -667,6 +699,48 @@
return ret;
}
+#ifdef __PTRACE_ENABLED__
+bool llkCheckStack(proc* procp, const std::string& piddir) {
+ if (llkCheckStackSymbols.empty()) return false;
+ if (procp->state == 'Z') { // No brains for Zombies
+ procp->stack = -1;
+ procp->count_stack = 0ms;
+ return false;
+ }
+
+ // Don't check process that are known to block ptrace, save sepolicy noise.
+ if (llkSkipName(std::to_string(procp->pid), llkBlacklistStack)) return false;
+ if (llkSkipName(procp->getComm(), llkBlacklistStack)) return false;
+ if (llkSkipName(procp->getCmdline(), llkBlacklistStack)) return false;
+
+ auto kernel_stack = ReadFile(piddir + "/stack");
+ if (kernel_stack.empty()) {
+ LOG(INFO) << piddir << "/stack empty comm=" << procp->getComm()
+ << " cmdline=" << procp->getCmdline();
+ return false;
+ }
+ // A scheduling incident that should not reset count_stack
+ if (kernel_stack.find(" cpu_worker_pools+0x") != std::string::npos) return false;
+ char idx = -1;
+ char match = -1;
+ for (const auto& stack : llkCheckStackSymbols) {
+ if (++idx < 0) break;
+ if (kernel_stack.find(" "s + stack + "+0x") != std::string::npos) {
+ match = idx;
+ break;
+ }
+ }
+ if (procp->stack != match) {
+ procp->stack = match;
+ procp->count_stack = 0ms;
+ return false;
+ }
+ if (match == char(-1)) return false;
+ procp->count_stack += llkCycle;
+ return procp->count_stack >= llkStateTimeoutMs[llkStateStack];
+}
+#endif
+
// Primary ABA mitigation watching last time schedule activity happened
void llkCheckSchedUpdate(proc* procp, const std::string& piddir) {
// Audit finds /proc/<tid>/sched is just over 1K, and
@@ -731,7 +805,15 @@
<< LLK_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkTimeoutMs) << "\n"
<< LLK_D_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkStateTimeoutMs[llkStateD]) << "\n"
<< LLK_Z_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkStateTimeoutMs[llkStateZ]) << "\n"
+#ifdef __PTRACE_ENABLED__
+ << LLK_STACK_TIMEOUT_MS_PROPERTY "=" << llkFormat(llkStateTimeoutMs[llkStateStack])
+ << "\n"
+#endif
<< LLK_CHECK_MS_PROPERTY "=" << llkFormat(llkCheckMs) << "\n"
+#ifdef __PTRACE_ENABLED__
+ << LLK_CHECK_STACK_PROPERTY "=" << llkFormat(llkCheckStackSymbols) << "\n"
+ << LLK_BLACKLIST_STACK_PROPERTY "=" << llkFormat(llkBlacklistStack) << "\n"
+#endif
<< LLK_BLACKLIST_PROCESS_PROPERTY "=" << llkFormat(llkBlacklistProcess) << "\n"
<< LLK_BLACKLIST_PARENT_PROPERTY "=" << llkFormat(llkBlacklistParent) << "\n"
<< LLK_BLACKLIST_UID_PROPERTY "=" << llkFormat(llkBlacklistUid);
@@ -892,9 +974,14 @@
if (pid == myPid) {
break;
}
- if (!llkIsMonitorState(state)) {
+#ifdef __PTRACE_ENABLED__
+ // if no stack monitoring, we can quickly exit here
+ if (!llkIsMonitorState(state) && llkCheckStackSymbols.empty()) {
continue;
}
+#else
+ if (!llkIsMonitorState(state)) continue;
+#endif
if ((tid == myTid) || llkSkipPid(tid)) {
continue;
}
@@ -925,12 +1012,26 @@
// ABA mitigation watching last time schedule activity happened
llkCheckSchedUpdate(procp, piddir);
- // Can only fall through to here if registered D or Z state !!!
- if (procp->count < llkStateTimeoutMs[(state == 'Z') ? llkStateZ : llkStateD]) {
- LOG(VERBOSE) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->"
- << pid << "->" << tid << ' ' << procp->getComm();
+#ifdef __PTRACE_ENABLED__
+ auto stuck = llkCheckStack(procp, piddir);
+ if (llkIsMonitorState(state)) {
+ if (procp->count >= llkStateTimeoutMs[(state == 'Z') ? llkStateZ : llkStateD]) {
+ stuck = true;
+ } else if (procp->count != 0ms) {
+ LOG(VERBOSE) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->"
+ << pid << "->" << tid << ' ' << procp->getComm();
+ }
+ }
+ if (!stuck) continue;
+#else
+ if (procp->count >= llkStateTimeoutMs[(state == 'Z') ? llkStateZ : llkStateD]) {
+ if (procp->count != 0ms) {
+ LOG(VERBOSE) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->"
+ << pid << "->" << tid << ' ' << procp->getComm();
+ }
continue;
}
+#endif
// We have to kill it to determine difference between live lock
// and persistent state blocked on a resource. Is there something
@@ -969,12 +1070,13 @@
// not working is we kill a process that likes to
// stay in 'D' state, instead of panicing the
// kernel (worse).
- LOG(WARNING) << "D " << llkFormat(procp->count) << ' ' << pid << "->" << tid
- << ' ' << procp->getComm() << " [kill]";
+ default:
+ LOG(WARNING) << state << ' ' << llkFormat(procp->count) << ' ' << pid
+ << "->" << tid << ' ' << procp->getComm() << " [kill]";
if ((llkKillOneProcess(llkTidLookup(pid), procp) >= 0) ||
- (llkKillOneProcess(pid, 'D', tid) >= 0) ||
+ (llkKillOneProcess(pid, state, tid) >= 0) ||
(llkKillOneProcess(procp, procp) >= 0) ||
- (llkKillOneProcess(tid, 'D', tid) >= 0)) {
+ (llkKillOneProcess(tid, state, tid) >= 0)) {
continue;
}
break;
@@ -983,7 +1085,8 @@
// We are here because we have confirmed kernel live-lock
LOG(ERROR) << state << ' ' << llkFormat(procp->count) << ' ' << ppid << "->" << pid
<< "->" << tid << ' ' << procp->getComm() << " [panic]";
- llkPanicKernel(true, tid, (state == 'Z') ? "zombie" : "driver");
+ llkPanicKernel(true, tid,
+ (state == 'Z') ? "zombie" : (state == 'D') ? "driver" : "sleeping");
}
LOG(VERBOSE) << "+closedir()";
}
@@ -1041,8 +1144,9 @@
}
bool llkInit(const char* threadname) {
+ auto debuggable = android::base::GetBoolProperty("ro.debuggable", false);
llkLowRam = android::base::GetBoolProperty("ro.config.low_ram", false);
- if (!LLK_ENABLE_DEFAULT && android::base::GetBoolProperty("ro.debuggable", false)) {
+ if (!LLK_ENABLE_DEFAULT && debuggable) {
llkEnable = android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng";
khtEnable = android::base::GetProperty(KHT_ENABLE_PROPERTY, "eng") == "eng";
}
@@ -1069,8 +1173,21 @@
llkValidate(); // validate llkTimeoutMs, llkCheckMs and llkCycle
llkStateTimeoutMs[llkStateD] = GetUintProperty(LLK_D_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
llkStateTimeoutMs[llkStateZ] = GetUintProperty(LLK_Z_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+#ifdef __PTRACE_ENABLED__
+ llkStateTimeoutMs[llkStateStack] = GetUintProperty(LLK_STACK_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+#endif
llkCheckMs = GetUintProperty(LLK_CHECK_MS_PROPERTY, llkCheckMs);
llkValidate(); // validate all (effectively minus llkTimeoutMs)
+#ifdef __PTRACE_ENABLED__
+ if (debuggable) {
+ llkCheckStackSymbols = llkSplit(
+ android::base::GetProperty(LLK_CHECK_STACK_PROPERTY, LLK_CHECK_STACK_DEFAULT));
+ }
+ std::string defaultBlacklistStack(LLK_BLACKLIST_STACK_DEFAULT);
+ if (!debuggable) defaultBlacklistStack += ",logd,/system/bin/logd";
+ llkBlacklistStack = llkSplit(
+ android::base::GetProperty(LLK_BLACKLIST_STACK_PROPERTY, defaultBlacklistStack));
+#endif
std::string defaultBlacklistProcess(
std::to_string(kernelPid) + "," + std::to_string(initPid) + "," +
std::to_string(kthreaddPid) + "," + std::to_string(::getpid()) + "," +
diff --git a/llkd/llkd-debuggable.rc b/llkd/llkd-debuggable.rc
new file mode 100644
index 0000000..724cb5e
--- /dev/null
+++ b/llkd/llkd-debuggable.rc
@@ -0,0 +1,19 @@
+on property:ro.debuggable=1
+ setprop llk.enable ${ro.llk.enable:-1}
+ setprop khungtask.enable ${ro.khungtask.enable:-1}
+
+on property:ro.llk.enable=eng
+ setprop llk.enable ${ro.debuggable:-0}
+
+on property:ro.khungtask.enable=eng
+ setprop khungtask.enable ${ro.debuggable:-0}
+
+service llkd-1 /system/bin/llkd
+ class late_start
+ disabled
+ user llkd
+ group llkd readproc
+ capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE
+ file /dev/kmsg w
+ file /proc/sysrq-trigger w
+ writepid /dev/cpuset/system-background/tasks
diff --git a/llkd/llkd.rc b/llkd/llkd.rc
index e538cdb..b1f96a8 100644
--- a/llkd/llkd.rc
+++ b/llkd/llkd.rc
@@ -3,15 +3,8 @@
setprop llk.enable ${ro.llk.enable:-0}
setprop khungtask.enable ${ro.khungtask.enable:-0}
-on property:ro.debuggable=1
- setprop llk.enable ${ro.llk.enable:-1}
- setprop khungtask.enable ${ro.khungtask.enable:-1}
-
-on property:ro.llk.enable=eng
- setprop llk.enable ${ro.debuggable:-0}
-
-on property:ro.khungtask.enable=eng
- setprop khungtask.enable ${ro.debuggable:-0}
+on property:ro.llk.enable=true
+ setprop llk.enable true
on property:llk.enable=1
setprop llk.enable true
@@ -19,6 +12,9 @@
on property:llk.enable=0
setprop llk.enable false
+on property:ro.khungtask.enable=true
+ setprop khungtask.enable true
+
on property:khungtask.enable=1
setprop khungtask.enable true
@@ -36,9 +32,9 @@
write /proc/sys/kernel/hung_task_panic 0
on property:llk.enable=true
- start llkd
+ start llkd-${ro.debuggable:-0}
-service llkd /system/bin/llkd
+service llkd-0 /system/bin/llkd
class late_start
disabled
user llkd
diff --git a/llkd/tests/llkd_test.cpp b/llkd/tests/llkd_test.cpp
index 3a15ff1..f54932b 100644
--- a/llkd/tests/llkd_test.cpp
+++ b/llkd/tests/llkd_test.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -81,9 +83,12 @@
(GetUintProperty(LLK_CHECK_MS_PROPERTY,
LLK_TIMEOUT_MS_DEFAULT / LLK_CHECKS_PER_TIMEOUT_DEFAULT) !=
duration_cast<milliseconds>(10s))) {
- execute("stop llkd");
+ execute("stop llkd-0");
+ execute("stop llkd-1");
rest();
std::string setprop("setprop ");
+ execute((setprop + LLK_CHECK_STACK_PROPERTY + " SyS_openat").c_str());
+ rest();
execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str());
rest();
execute((setprop + LLK_TIMEOUT_MS_PROPERTY + " 120000").c_str());
@@ -92,8 +97,10 @@
rest();
execute((setprop + LLK_CHECK_MS_PROPERTY + " 10000").c_str());
rest();
- execute((setprop + LLK_ENABLE_PROPERTY + " true").c_str());
- rest();
+ if (!default_enable) {
+ execute((setprop + LLK_ENABLE_PROPERTY + " true").c_str());
+ rest();
+ }
execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " true").c_str());
rest();
}
@@ -104,7 +111,7 @@
}
default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
if (default_enable) {
- execute("start llkd");
+ execute("start llkd-1");
rest();
GTEST_LOG_INFO << "llkd enabled\n";
} else {
@@ -123,8 +130,10 @@
llkTimeoutMs = LLK_TIMEOUT_MS_MINIMUM;
}
milliseconds llkCheckMs = llkTimeoutMs / LLK_CHECKS_PER_TIMEOUT_DEFAULT;
- auto timeout = GetUintProperty(
- (state == 'Z') ? LLK_Z_TIMEOUT_MS_PROPERTY : LLK_D_TIMEOUT_MS_PROPERTY, llkTimeoutMs);
+ auto timeout = GetUintProperty((state == 'Z') ? LLK_Z_TIMEOUT_MS_PROPERTY
+ : (state == 'S') ? LLK_STACK_TIMEOUT_MS_PROPERTY
+ : LLK_D_TIMEOUT_MS_PROPERTY,
+ llkTimeoutMs);
if (timeout < LLK_TIMEOUT_MS_MINIMUM) {
timeout = LLK_TIMEOUT_MS_MINIMUM;
}
@@ -285,3 +294,41 @@
waitForPid(child_pid);
}
+
+TEST(llkd, sleep) {
+ if (checkKill("kernel_panic,sysrq,livelock,sleeping")) {
+ return;
+ }
+ if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ GTEST_LOG_WARNING << "Features not available on user builds\n";
+ }
+
+ const auto period = llkdSleepPeriod('S');
+
+ /* Create a Persistent SyS_openat for single-ended pipe */
+ static constexpr char stack_pipe_file[] = "/dev/stack_pipe_file";
+ unlink(stack_pipe_file);
+ auto pipe_ret = mknod(stack_pipe_file, S_IFIFO | 0666, 0);
+ ASSERT_LE(0, pipe_ret);
+
+ auto child_pid = fork();
+ ASSERT_LE(0, child_pid);
+ if (!child_pid) {
+ child_pid = fork();
+ ASSERT_LE(0, child_pid);
+ if (!child_pid) {
+ sleep(period.count());
+ auto fd = open(stack_pipe_file, O_RDONLY | O_CLOEXEC);
+ close(fd);
+ exit(0);
+ } else {
+ auto fd = open(stack_pipe_file, O_WRONLY | O_CLOEXEC);
+ close(fd);
+ exit(42);
+ }
+ }
+
+ waitForPid(child_pid);
+
+ unlink(stack_pipe_file);
+}
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 3d7521c..2d4a26f 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -21,6 +21,7 @@
"tcpdump",
"toolbox",
"toybox",
+ "unzip",
],
}
@@ -31,6 +32,7 @@
"sh.recovery",
"toolbox.recovery",
"toybox.recovery",
+ "unzip.recovery",
],
}
diff --git a/trusty/keymaster/legacy/trusty_keymaster_device.cpp b/trusty/keymaster/legacy/trusty_keymaster_device.cpp
index ea00a92..afdf43b 100644
--- a/trusty/keymaster/legacy/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/legacy/trusty_keymaster_device.cpp
@@ -122,10 +122,10 @@
void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
RequestType* request) {
request->additional_params.Clear();
- if (client_id) {
+ if (client_id && client_id->data_length > 0) {
request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
}
- if (app_data) {
+ if (app_data && app_data->data_length > 0) {
request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
}
}