Merge "init: clean up the 1st/2nd stage init split"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c47230f..f9c3b4a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,30 @@
"presubmit": [
{
"name": "adbd_test"
+ },
+ {
+ "name": "debuggerd_test"
+ },
+ {
+ "name": "init_tests"
+ },
+ {
+ "name": "libbase_test"
+ },
+ {
+ "name": "libprocinfo_test"
+ },
+ {
+ "name": "memunreachable_test"
+ },
+ {
+ "name": "memunreachable_binder_test"
+ },
+ {
+ "name": "propertyinfoserializer_tests"
+ },
+ {
+ "name": "ziparchive-tests"
}
]
}
diff --git a/adb/Android.bp b/adb/Android.bp
index 00e98fe..e994075 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -285,6 +285,15 @@
"deploypatchgenerator",
],
+ // Archive adb, adb.exe.
+ dist: {
+ targets: [
+ "dist_files",
+ "sdk",
+ "win_sdk",
+ ],
+ },
+
target: {
darwin: {
cflags: [
diff --git a/adb/Android.mk b/adb/Android.mk
deleted file mode 100644
index 8b2d558..0000000
--- a/adb/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# Archive adb, adb.exe.
-$(call dist-for-goals,dist_files sdk win_sdk,$(HOST_OUT_EXECUTABLES)/adb)
-
-ifdef HOST_CROSS_OS
-$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
-endif
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 715e04f..2fc8478 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -36,6 +36,7 @@
void adb_auth_init();
int adb_auth_keygen(const char* filename);
+int adb_auth_pubkey(const char* filename);
std::string adb_auth_get_userkey();
std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 611b239..91b73a9 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -28,7 +28,6 @@
#include <string>
#include <android-base/file.h>
-#include <android-base/test_utils.h>
// All of these tests fail on Windows because they use the C Runtime open(),
// but the adb_io APIs expect file descriptors from adb_open(). This could
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index a8ec5fb..a024a89 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -41,6 +41,11 @@
const char* tag, const char* file, unsigned int line,
const char* message) {
android::base::StderrLogger(id, severity, tag, file, line, message);
+#if defined(_WIN32)
+ // stderr can be buffered on Windows (and setvbuf doesn't seem to work), so explicitly flush.
+ fflush(stderr);
+#endif
+
#if !ADB_HOST
// Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
// doesn't result in exponential logging.
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 341323f..870f6f0 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -30,8 +30,8 @@
#include "sysdeps.h"
+#include <android-base/file.h>
#include <android-base/macros.h>
-#include <android-base/test_utils.h>
#ifdef _WIN32
static std::string subdir(const char* parent, const char* child) {
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 0008f72..7f37c45 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -30,7 +30,6 @@
#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
-#include "android-base/test_utils.h"
#include "client/file_sync_client.h"
#include "commandline.h"
#include "fastdeploy.h"
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 71c19b8..bcb829b 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -43,6 +43,7 @@
#include "adb.h"
#include "adb_auth.h"
+#include "adb_io.h"
#include "adb_utils.h"
#include "sysdeps.h"
#include "transport.h"
@@ -52,30 +53,7 @@
*new std::map<std::string, std::shared_ptr<RSA>>;
static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
-static std::string get_user_info() {
- LOG(INFO) << "get_user_info...";
-
- std::string hostname;
- if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
- char buf[64];
- if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
- if (hostname.empty()) hostname = "unknown";
-
- std::string username;
- if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
- if (username.empty() && getlogin()) username = getlogin();
-#endif
- if (username.empty()) hostname = "unknown";
-
- return " " + username + "@" + hostname;
-}
-
-static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
- LOG(INFO) << "write_public_keyfile...";
-
+static bool calculate_public_key(std::string* out, RSA* private_key) {
uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
LOG(ERROR) << "Failed to convert to public key";
@@ -88,20 +66,10 @@
return false;
}
- std::string content;
- content.resize(expected_length);
- size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(&content[0]), binary_key_data,
+ out->resize(expected_length);
+ size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
sizeof(binary_key_data));
- content.resize(actual_length);
-
- content += get_user_info();
-
- std::string path(private_key_path + ".pub");
- if (!android::base::WriteStringToFile(content, path)) {
- PLOG(ERROR) << "Failed to write public key to '" << path << "'";
- return false;
- }
-
+ out->resize(actual_length);
return true;
}
@@ -140,11 +108,6 @@
goto out;
}
- if (!write_public_keyfile(rsa, file)) {
- D("Failed to write public key");
- goto out;
- }
-
ret = 1;
out:
@@ -170,36 +133,41 @@
return result;
}
-static bool read_key_file(const std::string& file) {
- LOG(INFO) << "read_key_file '" << file << "'...";
-
+static std::shared_ptr<RSA> read_key_file(const std::string& file) {
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose);
if (!fp) {
PLOG(ERROR) << "Failed to open '" << file << "'";
- return false;
+ return nullptr;
}
RSA* key = RSA_new();
if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
LOG(ERROR) << "Failed to read key";
RSA_free(key);
+ return nullptr;
+ }
+
+ return std::shared_ptr<RSA>(key, RSA_free);
+}
+
+static bool load_key(const std::string& file) {
+ std::shared_ptr<RSA> key = read_key_file(file);
+ if (!key) {
return false;
}
std::lock_guard<std::mutex> lock(g_keys_mutex);
- std::string fingerprint = hash_key(key);
+ std::string fingerprint = hash_key(key.get());
if (g_keys.find(fingerprint) != g_keys.end()) {
LOG(INFO) << "ignoring already-loaded key: " << file;
- RSA_free(key);
} else {
- g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free);
+ g_keys[fingerprint] = std::move(key);
}
-
return true;
}
-static bool read_keys(const std::string& path, bool allow_dir = true) {
- LOG(INFO) << "read_keys '" << path << "'...";
+static bool load_keys(const std::string& path, bool allow_dir = true) {
+ LOG(INFO) << "load_keys '" << path << "'...";
struct stat st;
if (stat(path.c_str(), &st) != 0) {
@@ -208,7 +176,7 @@
}
if (S_ISREG(st.st_mode)) {
- return read_key_file(path);
+ return load_key(path);
} else if (S_ISDIR(st.st_mode)) {
if (!allow_dir) {
// inotify isn't recursive. It would break expectations to load keys in nested
@@ -237,7 +205,7 @@
continue;
}
- result |= read_key_file((path + OS_PATH_SEPARATOR + name));
+ result |= load_key((path + OS_PATH_SEPARATOR + name));
}
return result;
}
@@ -250,7 +218,7 @@
return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
}
-static bool get_user_key() {
+static bool generate_userkey() {
std::string path = get_user_key_path();
if (path.empty()) {
PLOG(ERROR) << "Error getting user key filename";
@@ -266,7 +234,7 @@
}
}
- return read_key_file(path);
+ return load_key(path);
}
static std::set<std::string> get_vendor_keys() {
@@ -320,26 +288,42 @@
return result;
}
+static bool pubkey_from_privkey(std::string* out, const std::string& path) {
+ std::shared_ptr<RSA> privkey = read_key_file(path);
+ if (!privkey) {
+ return false;
+ }
+ return calculate_public_key(out, privkey.get());
+}
+
std::string adb_auth_get_userkey() {
std::string path = get_user_key_path();
if (path.empty()) {
PLOG(ERROR) << "Error getting user key filename";
return "";
}
- path += ".pub";
- std::string content;
- if (!android::base::ReadFileToString(path, &content)) {
- PLOG(ERROR) << "Can't load '" << path << "'";
+ std::string result;
+ if (!pubkey_from_privkey(&result, path)) {
return "";
}
- return content;
+ return result;
}
int adb_auth_keygen(const char* filename) {
return (generate_key(filename) == 0);
}
+int adb_auth_pubkey(const char* filename) {
+ std::string pubkey;
+ if (!pubkey_from_privkey(&pubkey, filename)) {
+ return 1;
+ }
+ pubkey.push_back('\n');
+
+ return WriteFdExactly(STDOUT_FILENO, pubkey.data(), pubkey.size()) ? 0 : 1;
+}
+
#if defined(__linux__)
static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) {
LOG(INFO) << "adb_auth_inotify_update called";
@@ -380,7 +364,7 @@
LOG(INFO) << "ignoring new directory at '" << path << "'";
} else {
LOG(INFO) << "observed new file at '" << path << "'";
- read_keys(path, false);
+ load_keys(path, false);
}
} else {
LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex
@@ -420,8 +404,8 @@
void adb_auth_init() {
LOG(INFO) << "adb_auth_init...";
- if (!get_user_key()) {
- LOG(ERROR) << "Failed to get user key";
+ if (!generate_userkey()) {
+ LOG(ERROR) << "Failed to generate user key";
return;
}
@@ -432,7 +416,7 @@
#endif
for (const std::string& path : key_paths) {
- read_keys(path.c_str());
+ load_keys(path.c_str());
}
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index b5bed28..c11052d 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -185,7 +185,6 @@
" enable-verity re-enable dm-verity checking on userdebug builds\n"
" keygen FILE\n"
" generate adb public/private key; private key stored in FILE,\n"
- " public key stored in FILE.pub (existing files overwritten)\n"
"\n"
"scripting:\n"
" wait-for[-TRANSPORT]-STATE\n"
@@ -1756,14 +1755,14 @@
// Always print key generation information for keygen command.
adb_trace_enable(AUTH);
return adb_auth_keygen(argv[1]);
- }
- else if (!strcmp(argv[0], "jdwp")) {
+ } else if (!strcmp(argv[0], "pubkey")) {
+ if (argc != 2) error_exit("pubkey requires an argument");
+ return adb_auth_pubkey(argv[1]);
+ } else if (!strcmp(argv[0], "jdwp")) {
return adb_connect_command("jdwp");
- }
- else if (!strcmp(argv[0], "track-jdwp")) {
+ } else if (!strcmp(argv[0], "track-jdwp")) {
return adb_connect_command("track-jdwp");
- }
- else if (!strcmp(argv[0], "track-devices")) {
+ } else if (!strcmp(argv[0], "track-devices")) {
return adb_connect_command("host:track-devices");
} else if (!strcmp(argv[0], "raw")) {
if (argc != 2) {
@@ -1772,13 +1771,11 @@
return adb_connect_command(argv[1]);
}
-
/* "adb /?" is a common idiom under Windows */
else if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
help();
return 0;
- }
- else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
+ } else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
fprintf(stdout, "%s", adb_version().c_str());
return 0;
} else if (!strcmp(argv[0], "features")) {
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 10b6090..f2ca63b 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -332,13 +332,6 @@
return;
}
- rc = libusb_set_interface_alt_setting(handle.get(), interface_num, 0);
- if (rc != 0) {
- LOG(WARNING) << "failed to set interface alt setting for device '" << device_serial
- << "'" << libusb_error_name(rc);
- return;
- }
-
for (uint8_t endpoint : {bulk_in, bulk_out}) {
rc = libusb_clear_halt(handle.get(), endpoint);
if (rc != 0) {
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index 720ec6a..b300fac 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -104,7 +104,7 @@
std::string reboot_string = android::base::StringPrintf("reboot,%s", reboot_arg.c_str());
if (reboot_arg == "fastboot" &&
- android::base::GetBoolProperty("ro.boot.logical_partitions", false) &&
+ android::base::GetBoolProperty("ro.boot.dynamic_partitions", false) &&
access("/dev/socket/recovery", F_OK) == 0) {
LOG(INFO) << "Recovery specific reboot fastboot";
/*
diff --git a/adb/fastdeploy/OWNERS b/adb/fastdeploy/OWNERS
new file mode 100644
index 0000000..d145834
--- /dev/null
+++ b/adb/fastdeploy/OWNERS
@@ -0,0 +1 @@
+idries@google.com
diff --git a/adb/sysdeps/stat_test.cpp b/adb/sysdeps/stat_test.cpp
index 2c2e0ee..67155d9 100644
--- a/adb/sysdeps/stat_test.cpp
+++ b/adb/sysdeps/stat_test.cpp
@@ -16,7 +16,7 @@
#include <string>
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
#include <gtest/gtest.h>
#include "adb_utils.h"
diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp
index 529b212..183cd5b 100644
--- a/adb/sysdeps_win32_test.cpp
+++ b/adb/sysdeps_win32_test.cpp
@@ -18,7 +18,7 @@
#include "sysdeps.h"
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
TEST(sysdeps_win32, adb_getenv) {
// Insert all test env vars before first call to adb_getenv() which will
diff --git a/adb/transport_fd.cpp b/adb/transport_fd.cpp
index ec61279..a93e68a 100644
--- a/adb/transport_fd.cpp
+++ b/adb/transport_fd.cpp
@@ -85,18 +85,9 @@
if (pfds[0].revents) {
if ((pfds[0].revents & POLLOUT)) {
std::lock_guard<std::mutex> lock(this->write_mutex_);
- WriteResult result = DispatchWrites();
- switch (result) {
- case WriteResult::Error:
- *error = "write failed";
- return;
-
- case WriteResult::Completed:
- writable_ = true;
- break;
-
- case WriteResult::TryAgain:
- break;
+ if (DispatchWrites() == WriteResult::Error) {
+ *error = "write failed";
+ return;
}
}
@@ -179,13 +170,14 @@
WriteResult DispatchWrites() REQUIRES(write_mutex_) {
CHECK(!write_buffer_.empty());
- if (!writable_) {
- return WriteResult::TryAgain;
- }
-
auto iovs = write_buffer_.iovecs();
ssize_t rc = adb_writev(fd_.get(), iovs.data(), iovs.size());
if (rc == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ writable_ = false;
+ return WriteResult::TryAgain;
+ }
+
return WriteResult::Error;
} else if (rc == 0) {
errno = 0;
@@ -194,6 +186,7 @@
// TODO: Implement a more efficient drop_front?
write_buffer_.take_front(rc);
+ writable_ = write_buffer_.empty();
if (write_buffer_.empty()) {
return WriteResult::Completed;
}
@@ -211,7 +204,12 @@
if (!packet->payload.empty()) {
write_buffer_.append(std::make_unique<IOVector::block_type>(std::move(packet->payload)));
}
- return DispatchWrites() != WriteResult::Error;
+
+ WriteResult result = DispatchWrites();
+ if (result == WriteResult::TryAgain) {
+ WakeThread();
+ }
+ return result != WriteResult::Error;
}
std::thread thread_;
diff --git a/adb/types.h b/adb/types.h
index 0c71c3a..0090c98 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -108,7 +108,10 @@
CHECK_EQ(0ULL, capacity_);
CHECK_EQ(0ULL, size_);
if (size != 0) {
- data_ = std::make_unique<char[]>(size);
+ // This isn't std::make_unique because that's equivalent to `new char[size]()`, which
+ // value-initializes the array instead of leaving it uninitialized. As an optimization,
+ // call new without parentheses to avoid this costly initialization.
+ data_.reset(new char[size]);
capacity_ = size;
size_ = size;
}
diff --git a/base/file.cpp b/base/file.cpp
index 3834ed4..d5bb7fe 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -18,7 +18,10 @@
#include <errno.h>
#include <fcntl.h>
+#include <ftw.h>
#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -28,19 +31,144 @@
#include <string>
#include <vector>
-#include "android-base/logging.h"
-#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
-#include "android-base/unique_fd.h"
-#include "android-base/utf8.h"
-
#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif
#if defined(_WIN32)
+#include <direct.h>
#include <windows.h>
#define O_NOFOLLOW 0
+#define OS_PATH_SEPARATOR '\\'
+#else
+#define OS_PATH_SEPARATOR '/'
#endif
+#include "android-base/logging.h" // and must be after windows.h for ERROR
+#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
+#include "android-base/unique_fd.h"
+#include "android-base/utf8.h"
+
+#ifdef _WIN32
+int mkstemp(char* template_name) {
+ if (_mktemp(template_name) == nullptr) {
+ return -1;
+ }
+ // Use open() to match the close() that TemporaryFile's destructor does.
+ // Use O_BINARY to match base file APIs.
+ return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
+}
+
+char* mkdtemp(char* template_name) {
+ if (_mktemp(template_name) == nullptr) {
+ return nullptr;
+ }
+ if (_mkdir(template_name) == -1) {
+ return nullptr;
+ }
+ return template_name;
+}
+#endif
+
+namespace {
+
+std::string GetSystemTempDir() {
+#if defined(__ANDROID__)
+ const auto* tmpdir = getenv("TMPDIR");
+ if (tmpdir == nullptr) tmpdir = "/data/local/tmp";
+ if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
+ return tmpdir;
+ }
+ // Tests running in app context can't access /data/local/tmp,
+ // so try current directory if /data/local/tmp is not accessible.
+ return ".";
+#elif defined(_WIN32)
+ char tmp_dir[MAX_PATH];
+ DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir); // checks TMP env
+ CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
+ CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
+
+ // GetTempPath() returns a path with a trailing slash, but init()
+ // does not expect that, so remove it.
+ CHECK_EQ(tmp_dir[result - 1], '\\');
+ tmp_dir[result - 1] = '\0';
+ return tmp_dir;
+#else
+ const auto* tmpdir = getenv("TMPDIR");
+ if (tmpdir == nullptr) tmpdir = "/tmp";
+ return tmpdir;
+#endif
+}
+
+} // namespace
+
+TemporaryFile::TemporaryFile() {
+ init(GetSystemTempDir());
+}
+
+TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
+ init(tmp_dir);
+}
+
+TemporaryFile::~TemporaryFile() {
+ if (fd != -1) {
+ close(fd);
+ }
+ if (remove_file_) {
+ unlink(path);
+ }
+}
+
+int TemporaryFile::release() {
+ int result = fd;
+ fd = -1;
+ return result;
+}
+
+void TemporaryFile::init(const std::string& tmp_dir) {
+ snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
+ fd = mkstemp(path);
+}
+
+TemporaryDir::TemporaryDir() {
+ init(GetSystemTempDir());
+}
+
+TemporaryDir::~TemporaryDir() {
+ if (!remove_dir_and_contents_) return;
+
+ auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
+ switch (file_type) {
+ case FTW_D:
+ case FTW_DP:
+ case FTW_DNR:
+ if (rmdir(child) == -1) {
+ PLOG(ERROR) << "rmdir " << child;
+ }
+ break;
+ case FTW_NS:
+ default:
+ if (rmdir(child) != -1) break;
+ // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
+ FALLTHROUGH_INTENDED;
+ case FTW_F:
+ case FTW_SL:
+ case FTW_SLN:
+ if (unlink(child) == -1) {
+ PLOG(ERROR) << "unlink " << child;
+ }
+ break;
+ }
+ return 0;
+ };
+
+ nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
+}
+
+bool TemporaryDir::init(const std::string& tmp_dir) {
+ snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
+ return (mkdtemp(path) != nullptr);
+}
+
namespace android {
namespace base {
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 6794652..f64e81c 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -24,8 +24,6 @@
#include <string>
-#include "android-base/test_utils.h"
-
#if !defined(_WIN32)
#include <pwd.h>
#endif
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 86d537d..f8748b5 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -18,8 +18,10 @@
#include <sys/stat.h>
#include <sys/types.h>
+
#include <string>
+#include <android-base/macros.h>
#include "android-base/off64_t.h"
#if !defined(_WIN32) && !defined(O_BINARY)
@@ -32,6 +34,46 @@
#define O_CLOEXEC O_NOINHERIT
#endif
+class TemporaryFile {
+ public:
+ TemporaryFile();
+ explicit TemporaryFile(const std::string& tmp_dir);
+ ~TemporaryFile();
+
+ // Release the ownership of fd, caller is reponsible for closing the
+ // fd or stream properly.
+ int release();
+ // Don't remove the temporary file in the destructor.
+ void DoNotRemove() { remove_file_ = false; }
+
+ int fd;
+ char path[1024];
+
+ private:
+ void init(const std::string& tmp_dir);
+
+ bool remove_file_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
+};
+
+class TemporaryDir {
+ public:
+ TemporaryDir();
+ ~TemporaryDir();
+ // Don't remove the temporary dir in the destructor.
+ void DoNotRemove() { remove_dir_and_contents_ = false; }
+
+ char path[1024];
+
+ private:
+ bool init(const std::string& tmp_dir);
+
+ bool remove_dir_and_contents_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
+};
+
namespace android {
namespace base {
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 2abe68e..b20f278 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -19,44 +19,9 @@
#include <regex>
#include <string>
+#include <android-base/file.h>
#include <android-base/macros.h>
-class TemporaryFile {
- public:
- TemporaryFile();
- explicit TemporaryFile(const std::string& tmp_dir);
- ~TemporaryFile();
-
- // Release the ownership of fd, caller is reponsible for closing the
- // fd or stream properly.
- int release();
- // Don't remove the temporary file in the destructor.
- void DoNotRemove() { remove_file_ = false; }
-
- int fd;
- char path[1024];
-
- private:
- void init(const std::string& tmp_dir);
-
- bool remove_file_ = true;
-
- DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
-};
-
-class TemporaryDir {
- public:
- TemporaryDir();
- ~TemporaryDir();
-
- char path[1024];
-
- private:
- bool init(const std::string& tmp_dir);
-
- DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
-};
-
class CapturedStdFd {
public:
CapturedStdFd(int std_fd);
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
index 57fde6f..7e89723 100644
--- a/base/mapped_file_test.cpp
+++ b/base/mapped_file_test.cpp
@@ -25,7 +25,6 @@
#include <string>
#include "android-base/file.h"
-#include "android-base/test_utils.h"
#include "android-base/unique_fd.h"
TEST(mapped_file, smoke) {
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 4d9466b..36b4cdf 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -22,109 +22,11 @@
#include <sys/stat.h>
#include <unistd.h>
-#if defined(_WIN32)
-#include <windows.h>
-#include <direct.h>
-#define OS_PATH_SEPARATOR '\\'
-#else
-#define OS_PATH_SEPARATOR '/'
-#endif
-
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
-#ifdef _WIN32
-int mkstemp(char* template_name) {
- if (_mktemp(template_name) == nullptr) {
- return -1;
- }
- // Use open() to match the close() that TemporaryFile's destructor does.
- // Use O_BINARY to match base file APIs.
- return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY,
- S_IRUSR | S_IWUSR);
-}
-
-char* mkdtemp(char* template_name) {
- if (_mktemp(template_name) == nullptr) {
- return nullptr;
- }
- if (_mkdir(template_name) == -1) {
- return nullptr;
- }
- return template_name;
-}
-#endif
-
-static std::string GetSystemTempDir() {
-#if defined(__ANDROID__)
- const char* tmpdir = "/data/local/tmp";
- if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
- return tmpdir;
- }
- // Tests running in app context can't access /data/local/tmp,
- // so try current directory if /data/local/tmp is not accessible.
- return ".";
-#elif defined(_WIN32)
- char tmp_dir[MAX_PATH];
- DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
- CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
- CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
-
- // GetTempPath() returns a path with a trailing slash, but init()
- // does not expect that, so remove it.
- CHECK_EQ(tmp_dir[result - 1], '\\');
- tmp_dir[result - 1] = '\0';
- return tmp_dir;
-#else
- return "/tmp";
-#endif
-}
-
-TemporaryFile::TemporaryFile() {
- init(GetSystemTempDir());
-}
-
-TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
- init(tmp_dir);
-}
-
-TemporaryFile::~TemporaryFile() {
- if (fd != -1) {
- close(fd);
- }
- if (remove_file_) {
- unlink(path);
- }
-}
-
-int TemporaryFile::release() {
- int result = fd;
- fd = -1;
- return result;
-}
-
-void TemporaryFile::init(const std::string& tmp_dir) {
- snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
- OS_PATH_SEPARATOR);
- fd = mkstemp(path);
-}
-
-TemporaryDir::TemporaryDir() {
- init(GetSystemTempDir());
-}
-
-TemporaryDir::~TemporaryDir() {
- rmdir(path);
-}
-
-bool TemporaryDir::init(const std::string& tmp_dir) {
- snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
- OS_PATH_SEPARATOR);
- return (mkdtemp(path) != nullptr);
-}
-
CapturedStdFd::CapturedStdFd(int std_fd) : std_fd_(std_fd), old_fd_(-1) {
Start();
}
diff --git a/base/utf8_test.cpp b/base/utf8_test.cpp
index fcb25c3..472e82c 100644
--- a/base/utf8_test.cpp
+++ b/base/utf8_test.cpp
@@ -21,8 +21,8 @@
#include <fcntl.h>
#include <stdlib.h>
+#include "android-base/file.h"
#include "android-base/macros.h"
-#include "android-base/test_utils.h"
#include "android-base/unique_fd.h"
namespace android {
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 4b7ab36..5ca9b09 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -29,7 +29,6 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
diff --git a/cpio/Android.bp b/cpio/Android.bp
index 847e0f1..baa0319 100644
--- a/cpio/Android.bp
+++ b/cpio/Android.bp
@@ -5,4 +5,7 @@
srcs: ["mkbootfs.c"],
cflags: ["-Werror"],
shared_libs: ["libcutils"],
+ dist: {
+ targets: ["dist_files"],
+ },
}
diff --git a/cpio/Android.mk b/cpio/Android.mk
deleted file mode 100644
index fc3551b..0000000
--- a/cpio/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2005 The Android Open Source Project
-
-$(call dist-for-goals,dist_files,$(ALL_MODULES.mkbootfs.BUILT))
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 577e336..d79d20b 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -348,8 +348,16 @@
return vm_pid;
}
+static void InstallSigPipeHandler() {
+ struct sigaction action = {};
+ action.sa_handler = SIG_IGN;
+ action.sa_flags = SA_RESTART;
+ sigaction(SIGPIPE, &action, nullptr);
+}
+
int main(int argc, char** argv) {
DefuseSignalHandlers();
+ InstallSigPipeHandler();
atrace_begin(ATRACE_TAG, "before reparent");
pid_t target_process = getppid();
diff --git a/debuggerd/libdebuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
index d7036fd..3e920eb 100644
--- a/debuggerd/libdebuggerd/test/open_files_list_test.cpp
+++ b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
@@ -20,10 +20,9 @@
#include <string>
+#include <android-base/file.h>
#include <gtest/gtest.h>
-#include "android-base/test_utils.h"
-
#include "libdebuggerd/open_files_list.h"
// Check that we can produce a list of open files for the current process, and
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 0b8a936..1179263 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -78,7 +78,7 @@
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
-static void dump_probable_cause(log_t* log, const siginfo_t* si) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
std::string cause;
if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -94,6 +94,14 @@
} else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
cause = "call to kuser_cmpxchg64";
}
+ } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
+ for (auto it = map->begin(); it != map->end(); ++it) {
+ const backtrace_map_t* entry = *it;
+ if (si->si_addr >= reinterpret_cast<void*>(entry->start) &&
+ si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) {
+ cause = "execute-only (no-read) memory access error; likely due to data in .text.";
+ }
+ }
} else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
si->si_syscall);
@@ -125,8 +133,6 @@
_LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
-
- dump_probable_cause(log, thread_info.siginfo);
}
static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
@@ -426,6 +432,7 @@
if (thread_info.siginfo) {
dump_signal_info(log, thread_info, process_memory);
+ dump_probable_cause(log, thread_info.siginfo, map);
}
if (primary_thread) {
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 50d18ed..8006c41 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -43,6 +43,7 @@
"libgtest_main",
"libbase",
"libadb_host",
+ "liblp",
],
header_libs: [
@@ -173,6 +174,11 @@
host_ldlibs: ["-lws2_32"],
},
+ not_windows: {
+ static_libs: [
+ "libext4_utils",
+ ],
+ },
},
stl: "libc++_static",
@@ -193,6 +199,8 @@
"libbase",
"libcutils",
"libgtest_host",
+ "liblp",
+ "libcrypto",
],
}
@@ -252,6 +260,13 @@
"mke2fs",
"make_f2fs",
],
+ dist: {
+ targets: [
+ "dist_files",
+ "sdk",
+ "win_sdk",
+ ],
+ },
target: {
not_windows: {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e4c1317..17ec392 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,13 +18,9 @@
# Package fastboot-related executables.
#
-my_dist_files := $(HOST_OUT_EXECUTABLES)/fastboot
-my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs
+my_dist_files := $(HOST_OUT_EXECUTABLES)/mke2fs
my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
-ifdef HOST_CROSS_OS
-$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
-endif
my_dist_files :=
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 08744ec..71d2a1d 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -322,7 +322,7 @@
// partition table to the same place it was read.
class PartitionBuilder {
public:
- explicit PartitionBuilder(FastbootDevice* device);
+ explicit PartitionBuilder(FastbootDevice* device, const std::string& partition_name);
bool Write();
bool Valid() const { return !!builder_; }
@@ -330,19 +330,19 @@
private:
std::string super_device_;
+ uint32_t slot_number_;
std::unique_ptr<MetadataBuilder> builder_;
};
-PartitionBuilder::PartitionBuilder(FastbootDevice* device) {
- auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name());
+PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name) {
+ std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
+ slot_number_ = SlotNumberForSlotSuffix(slot_suffix);
+ auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number_));
if (!super_device) {
return;
}
super_device_ = *super_device;
-
- std::string slot = device->GetCurrentSlot();
- uint32_t slot_number = SlotNumberForSlotSuffix(slot);
- builder_ = MetadataBuilder::New(super_device_, slot_number);
+ builder_ = MetadataBuilder::New(super_device_, slot_number_);
}
bool PartitionBuilder::Write() {
@@ -350,11 +350,7 @@
if (!metadata) {
return false;
}
- bool ok = true;
- for (uint32_t i = 0; i < metadata->geometry.metadata_slot_count; i++) {
- ok &= UpdatePartitionTable(super_device_, *metadata.get(), i);
- }
- return ok;
+ return UpdateAllPartitionMetadata(super_device_, *metadata.get());
}
bool CreatePartitionHandler(FastbootDevice* device, const std::vector<std::string>& args) {
@@ -372,7 +368,7 @@
return device->WriteFail("Invalid partition size");
}
- PartitionBuilder builder(device);
+ PartitionBuilder builder(device, partition_name);
if (!builder.Valid()) {
return device->WriteFail("Could not open super partition");
}
@@ -404,11 +400,13 @@
return device->WriteStatus(FastbootResult::FAIL, "Command not available on locked devices");
}
- PartitionBuilder builder(device);
+ std::string partition_name = args[1];
+
+ PartitionBuilder builder(device, partition_name);
if (!builder.Valid()) {
return device->WriteFail("Could not open super partition");
}
- builder->RemovePartition(args[1]);
+ builder->RemovePartition(partition_name);
if (!builder.Write()) {
return device->WriteFail("Failed to write partition table");
}
@@ -430,7 +428,7 @@
return device->WriteFail("Invalid partition size");
}
- PartitionBuilder builder(device);
+ PartitionBuilder builder(device, partition_name);
if (!builder.Valid()) {
return device->WriteFail("Could not open super partition");
}
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 7c9e1d0..7b99884 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -183,12 +183,7 @@
}
// Write the new table to every metadata slot.
- bool ok = true;
- for (size_t i = 0; i < new_metadata->geometry.metadata_slot_count; i++) {
- ok &= UpdatePartitionTable(super_name, *new_metadata.get(), i);
- }
-
- if (!ok) {
+ if (!UpdateAllPartitionMetadata(super_name, *new_metadata.get())) {
return device->WriteFail("Unable to write new partition table");
}
return device->WriteOkay("Successfully updated partition table");
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index b844b9f..2ae9ac5 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -23,9 +23,11 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
+#include <liblp/builder.h>
#include <liblp/liblp.h>
#include "fastboot_device.h"
@@ -35,7 +37,9 @@
using android::base::unique_fd;
using android::hardware::boot::V1_0::Slot;
-static bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
+namespace {
+
+bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
std::optional<std::string> path = FindPhysicalPartition(name);
if (!path) {
return false;
@@ -44,28 +48,31 @@
return true;
}
-static bool OpenLogicalPartition(const std::string& name, const std::string& slot,
- PartitionHandle* handle) {
- std::optional<std::string> path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
+bool OpenLogicalPartition(FastbootDevice* device, const std::string& partition_name,
+ PartitionHandle* handle) {
+ std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
+ uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
+ auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number));
if (!path) {
return false;
}
- uint32_t slot_number = SlotNumberForSlotSuffix(slot);
std::string dm_path;
- if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, 5s, &dm_path)) {
- LOG(ERROR) << "Could not map partition: " << name;
+ if (!CreateLogicalPartition(path->c_str(), slot_number, partition_name, true, 5s, &dm_path)) {
+ LOG(ERROR) << "Could not map partition: " << partition_name;
return false;
}
- auto closer = [name]() -> void { DestroyLogicalPartition(name, 5s); };
+ auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name, 5s); };
*handle = PartitionHandle(dm_path, std::move(closer));
return true;
}
+} // namespace
+
bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle) {
// We prioritize logical partitions over physical ones, and do this
// consistently for other partition operations (like getvar:partition-size).
- if (LogicalPartitionExists(name, device->GetCurrentSlot())) {
- if (!OpenLogicalPartition(name, device->GetCurrentSlot(), handle)) {
+ if (LogicalPartitionExists(device, name)) {
+ if (!OpenLogicalPartition(device, name, handle)) {
return false;
}
} else if (!OpenPhysicalPartition(name, handle)) {
@@ -104,14 +111,14 @@
return nullptr;
}
-bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
- bool* is_zero_length) {
- auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
+bool LogicalPartitionExists(FastbootDevice* device, const std::string& name, bool* is_zero_length) {
+ std::string slot_suffix = GetSuperSlotSuffix(device, name);
+ uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
+ auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number));
if (!path) {
return false;
}
- uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number);
if (!metadata) {
return false;
@@ -154,12 +161,29 @@
}
}
- // Next get logical partitions.
- if (auto path = FindPhysicalPartition(fs_mgr_get_super_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);
+ // Find metadata in each super partition (on retrofit devices, there will
+ // be two).
+ std::vector<std::unique_ptr<LpMetadata>> metadata_list;
+
+ uint32_t current_slot = SlotNumberForSlotSuffix(device->GetCurrentSlot());
+ std::string super_name = fs_mgr_get_super_partition_name(current_slot);
+ if (auto metadata = ReadMetadata(super_name, current_slot)) {
+ metadata_list.emplace_back(std::move(metadata));
+ }
+
+ uint32_t other_slot = (current_slot == 0) ? 1 : 0;
+ std::string other_super = fs_mgr_get_super_partition_name(other_slot);
+ if (super_name != other_super) {
+ if (auto metadata = ReadMetadata(other_super, other_slot)) {
+ metadata_list.emplace_back(std::move(metadata));
+ }
+ }
+
+ for (const auto& metadata : metadata_list) {
+ for (const auto& partition : metadata->partitions) {
+ std::string partition_name = GetPartitionName(partition);
+ if (std::find(partitions.begin(), partitions.end(), partition_name) ==
+ partitions.end()) {
partitions.emplace_back(partition_name);
}
}
@@ -175,3 +199,30 @@
}
return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
}
+
+bool UpdateAllPartitionMetadata(const std::string& super_name,
+ const android::fs_mgr::LpMetadata& metadata) {
+ bool ok = true;
+ for (size_t i = 0; i < metadata.geometry.metadata_slot_count; i++) {
+ ok &= UpdatePartitionTable(super_name, metadata, i);
+ }
+ return ok;
+}
+
+std::string GetSuperSlotSuffix(FastbootDevice* device, const std::string& partition_name) {
+ // If the super partition does not have a slot suffix, this is not a
+ // retrofit device, and we should take the current slot.
+ std::string current_slot_suffix = device->GetCurrentSlot();
+ uint32_t current_slot_number = SlotNumberForSlotSuffix(current_slot_suffix);
+ std::string super_partition = fs_mgr_get_super_partition_name(current_slot_number);
+ if (GetPartitionSlotSuffix(super_partition).empty()) {
+ return current_slot_suffix;
+ }
+
+ // Otherwise, infer the slot from the partition name.
+ std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
+ if (!slot_suffix.empty()) {
+ return slot_suffix;
+ }
+ return current_slot_suffix;
+}
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
index bb08f72..4c6aa07 100644
--- a/fastboot/device/utility.h
+++ b/fastboot/device/utility.h
@@ -20,6 +20,7 @@
#include <android-base/unique_fd.h>
#include <android/hardware/boot/1.0/IBootControl.h>
+#include <liblp/liblp.h>
// Logical partitions are only mapped to a block device as needed, and
// immediately unmapped when no longer needed. In order to enforce this we
@@ -52,10 +53,20 @@
class FastbootDevice;
+// On normal devices, the super partition is always named "super". On retrofit
+// devices, the name must be derived from the partition name or current slot.
+// This helper assists in choosing the correct super for a given partition
+// name.
+std::string GetSuperSlotSuffix(FastbootDevice* device, const std::string& partition_name);
+
std::optional<std::string> FindPhysicalPartition(const std::string& name);
-bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
+bool LogicalPartitionExists(FastbootDevice* device, const std::string& name,
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);
bool GetDeviceLockStatus();
+
+// Update all copies of metadata.
+bool UpdateAllPartitionMetadata(const std::string& super_name,
+ const android::fs_mgr::LpMetadata& metadata);
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 601af34..130a3cf 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -271,8 +271,7 @@
return true;
}
std::string partition_name = args[0] + slot_suffix;
- if (FindPhysicalPartition(partition_name) ||
- LogicalPartitionExists(partition_name, slot_suffix)) {
+ if (FindPhysicalPartition(partition_name) || LogicalPartitionExists(device, partition_name)) {
*message = "yes";
} else {
*message = "no";
@@ -289,8 +288,7 @@
// 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) {
+ if (LogicalPartitionExists(device, args[0], &is_zero_length) && is_zero_length) {
*message = "0x0";
return true;
}
@@ -313,8 +311,7 @@
}
std::string partition_name = args[0];
- if (!FindPhysicalPartition(partition_name) &&
- !LogicalPartitionExists(partition_name, device->GetCurrentSlot())) {
+ if (!FindPhysicalPartition(partition_name) && !LogicalPartitionExists(device, partition_name)) {
*message = "Invalid partition";
return false;
}
@@ -363,7 +360,7 @@
// 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())) {
+ if (LogicalPartitionExists(device, partition_name)) {
*message = "yes";
return true;
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 625e047..0978ec1 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -56,9 +56,9 @@
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <build/version.h>
+#include <liblp/liblp.h>
#include <platform_tools_version.h>
#include <sparse/sparse.h>
#include <ziparchive/zip_archive.h>
@@ -162,9 +162,17 @@
// clang-format on
};
-static std::string find_item_given_name(const std::string& img_name) {
+static char* get_android_product_out() {
char* dir = getenv("ANDROID_PRODUCT_OUT");
if (dir == nullptr || dir[0] == '\0') {
+ return nullptr;
+ }
+ return dir;
+}
+
+static std::string find_item_given_name(const std::string& img_name) {
+ char* dir = get_android_product_out();
+ if (!dir) {
die("ANDROID_PRODUCT_OUT not set");
}
return std::string(dir) + "/" + img_name;
@@ -408,6 +416,7 @@
" -s SERIAL Specify a USB device.\n"
" -s tcp|udp:HOST[:PORT] Specify a network device.\n"
" -S SIZE[K|M|G] Break into sparse files no larger than SIZE.\n"
+ " --force Force a flash operation that may be unsafe.\n"
" --slot SLOT Use SLOT; 'all' for both slots, 'other' for\n"
" non-current slot (default: current active slot).\n"
" --set-active[=SLOT] Sets the active slot before rebooting.\n"
@@ -1465,15 +1474,13 @@
fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str());
return;
}
- fprintf(stderr, "Formatting is not supported for file system with type '%s'.\n",
- partition_type.c_str());
- return;
+ die("Formatting is not supported for file system with type '%s'.",
+ partition_type.c_str());
}
int64_t size;
if (!android::base::ParseInt(partition_size, &size)) {
- fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
- return;
+ die("Couldn't parse partition size '%s'.", partition_size.c_str());
}
unsigned eraseBlkSize, logicalBlkSize;
@@ -1483,17 +1490,14 @@
if (fs_generator_generate(gen, output.path, size, initial_dir,
eraseBlkSize, logicalBlkSize)) {
die("Cannot generate image for %s", partition.c_str());
- return;
}
fd.reset(open(output.path, O_RDONLY));
if (fd == -1) {
- fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
- return;
+ die("Cannot open generated image: %s", strerror(errno));
}
if (!load_buf_fd(fd.release(), &buf)) {
- fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
- return;
+ die("Cannot read image: %s", strerror(errno));
}
flash_buf(partition, &buf);
return;
@@ -1504,6 +1508,37 @@
if (errMsg) fprintf(stderr, "%s", errMsg);
}
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+ if (!skip_if_not_supported) {
+ die("Command failed");
+ }
+}
+
+static bool should_flash_in_userspace(const std::string& partition_name) {
+ if (!get_android_product_out()) {
+ return false;
+ }
+ auto path = find_item_given_name("super_empty.img");
+ if (path.empty()) {
+ return false;
+ }
+ auto metadata = android::fs_mgr::ReadFromImageFile(path);
+ if (!metadata) {
+ return false;
+ }
+ for (const auto& partition : metadata->partitions) {
+ auto candidate = android::fs_mgr::GetPartitionName(partition);
+ if (partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED) {
+ // On retrofit devices, we don't know if, or whether, the A or B
+ // slot has been flashed for dynamic partitions. Instead we add
+ // both names to the list as a conservative guess.
+ if (candidate + "_a" == partition_name || candidate + "_b" == partition_name) {
+ return true;
+ }
+ } else if (candidate == partition_name) {
+ return true;
+ }
+ }
+ return false;
}
int FastBootTool::Main(int argc, char* argv[]) {
@@ -1516,6 +1551,7 @@
bool wants_set_active = false;
bool skip_secondary = false;
bool set_fbe_marker = false;
+ bool force_flash = false;
int longindex;
std::string slot_override;
std::string next_active;
@@ -1531,6 +1567,7 @@
{"cmdline", required_argument, 0, 0},
{"disable-verification", no_argument, 0, 0},
{"disable-verity", no_argument, 0, 0},
+ {"force", no_argument, 0, 0},
{"header-version", required_argument, 0, 0},
{"help", no_argument, 0, 'h'},
{"kernel-offset", required_argument, 0, 0},
@@ -1566,6 +1603,8 @@
g_disable_verification = true;
} else if (name == "disable-verity") {
g_disable_verity = true;
+ } else if (name == "force") {
+ force_flash = true;
} else if (name == "header-version") {
g_boot_img_hdr.header_version = strtoul(optarg, nullptr, 0);
} else if (name == "kernel-offset") {
@@ -1780,6 +1819,16 @@
if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
auto flash = [&](const std::string &partition) {
+ if (should_flash_in_userspace(partition) && !is_userspace_fastboot() &&
+ !force_flash) {
+ die("The partition you are trying to flash is dynamic, and "
+ "should be flashed via fastbootd. Please run:\n"
+ "\n"
+ " fastboot reboot fastboot\n"
+ "\n"
+ "And try again. If you are intentionally trying to "
+ "overwrite a fixed partition, use --force.");
+ }
do_flash(partition.c_str(), fname.c_str());
};
do_for_partitions(pname.c_str(), slot_override, flash, true);
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index fc6a16b..8c0aa6b 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -172,13 +172,8 @@
mkf2fs_args.push_back("-S");
std::string size_str = std::to_string(partSize);
mkf2fs_args.push_back(size_str.c_str());
- mkf2fs_args.push_back("-f");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("encrypt");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("quota");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("verity");
+ mkf2fs_args.push_back("-g");
+ mkf2fs_args.push_back("android");
mkf2fs_args.push_back(fileName);
mkf2fs_args.push_back(nullptr);
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index 301534b..277cc3a 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -26,6 +26,9 @@
"libadb_host",
"libtinyxml2",
"libsparse",
+ "liblp",
+ "libcrypto",
+ "libext4_utils",
],
// Static libs (libfastboot2) shared library dependencies are not transitively included
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index ed02c4a..f597f50 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -61,7 +61,7 @@
UInt8 bulkIn;
UInt8 bulkOut;
- IOUSBInterfaceInterface190 **interface;
+ IOUSBInterfaceInterface500** interface;
unsigned int zero_mask;
};
@@ -86,13 +86,13 @@
/** Try out all the interfaces and see if there's a match. Returns 0 on
* success, -1 on failure. */
-static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
+static int try_interfaces(IOUSBDeviceInterface500** dev, usb_handle* handle) {
IOReturn kr;
IOUSBFindInterfaceRequest request;
io_iterator_t iterator;
io_service_t usbInterface;
IOCFPlugInInterface **plugInInterface;
- IOUSBInterfaceInterface190 **interface = NULL;
+ IOUSBInterfaceInterface500** interface = NULL;
HRESULT result;
SInt32 score;
UInt8 interfaceNumEndpoints;
@@ -128,10 +128,10 @@
}
// Now create the interface interface for the interface
- result = (*plugInInterface)->QueryInterface(
- plugInInterface,
- CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
- (LPVOID*) &interface);
+ result = (*plugInInterface)
+ ->QueryInterface(plugInInterface,
+ CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID500),
+ (LPVOID*)&interface);
// No longer need the intermediate plugin
(*plugInInterface)->Release(plugInInterface);
@@ -270,7 +270,7 @@
static int try_device(io_service_t device, usb_handle *handle) {
kern_return_t kr;
IOCFPlugInInterface **plugin = NULL;
- IOUSBDeviceInterface182 **dev = NULL;
+ IOUSBDeviceInterface500** dev = NULL;
SInt32 score;
HRESULT result;
UInt8 serialIndex;
@@ -287,8 +287,8 @@
}
// Now create the device interface.
- result = (*plugin)->QueryInterface(plugin,
- CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev);
+ result = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500),
+ (LPVOID*)&dev);
if ((result != 0) || (dev == NULL)) {
ERR("Couldn't create a device interface (%08x)\n", (int) result);
goto error;
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index c321fe3..6310238 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1031,7 +1031,7 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open(*fstab);
+ avb_handle = FsManagerAvbHandle::Open();
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return FS_MGR_MNTALL_FAIL;
@@ -1275,7 +1275,7 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open(*fstab);
+ avb_handle = FsManagerAvbHandle::Open();
if (!avb_handle) {
LERROR << "Failed to open FsManagerAvbHandle";
return FS_MGR_DOMNT_FAILED;
@@ -1603,9 +1603,6 @@
} else if (slot == -1) {
suffix = fs_mgr_get_slot_suffix();
}
- if (suffix.empty()) {
- LFATAL << "Super partition name can only be overridden on A/B devices.";
- }
return super_partition + suffix;
}
return LP_METADATA_DEFAULT_PARTITION_NAME;
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7c6093e..6f94d45 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -322,17 +322,6 @@
continue;
}
- // Ensures that hashtree descriptor is in /vbmeta or /boot or in
- // the same partition for verity setup.
- std::string vbmeta_partition_name(verify_data.vbmeta_images[i].partition_name);
- if (vbmeta_partition_name != "vbmeta" &&
- vbmeta_partition_name != "boot" && // for legacy device to append top-level vbmeta
- vbmeta_partition_name != partition_name) {
- LWARNING << "Skip vbmeta image at " << verify_data.vbmeta_images[i].partition_name
- << " for partition: " << partition_name.c_str();
- continue;
- }
-
for (size_t j = 0; j < num_descriptors && !found; j++) {
AvbDescriptor desc;
if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) {
@@ -372,21 +361,7 @@
return true;
}
-FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const fstab& fstab) {
- FsManagerAvbOps avb_ops(fstab);
- return DoOpen(&avb_ops);
-}
-
-FsManagerAvbUniquePtr FsManagerAvbHandle::Open(ByNameSymlinkMap&& by_name_symlink_map) {
- if (by_name_symlink_map.empty()) {
- LERROR << "Empty by_name_symlink_map when opening FsManagerAvbHandle";
- return nullptr;
- }
- FsManagerAvbOps avb_ops(std::move(by_name_symlink_map));
- return DoOpen(&avb_ops);
-}
-
-FsManagerAvbUniquePtr FsManagerAvbHandle::DoOpen(FsManagerAvbOps* avb_ops) {
+FsManagerAvbUniquePtr FsManagerAvbHandle::Open() {
bool is_device_unlocked = fs_mgr_is_device_unlocked();
FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
@@ -395,10 +370,11 @@
return nullptr;
}
+ FsManagerAvbOps avb_ops;
AvbSlotVerifyFlags flags = is_device_unlocked ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
: AVB_SLOT_VERIFY_FLAGS_NONE;
AvbSlotVerifyResult verify_result =
- avb_ops->AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->avb_slot_data_);
+ avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->avb_slot_data_);
// Only allow two verify results:
// - AVB_SLOT_VERIFY_RESULT_OK.
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 43879fe..18efa22 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -40,6 +40,8 @@
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
+using namespace std::literals;
+
static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
size_t num_bytes, void* buffer, size_t* out_num_read) {
return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
@@ -98,7 +100,7 @@
return AVB_IO_RESULT_OK;
}
-void FsManagerAvbOps::InitializeAvbOps() {
+FsManagerAvbOps::FsManagerAvbOps() {
// We only need to provide the implementation of read_from_partition()
// operation since that's all what is being used by the avb_slot_verify().
// Other I/O operations are only required in bootloader but not in
@@ -116,31 +118,10 @@
avb_ops_.user_data = this;
}
-FsManagerAvbOps::FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map)
- : by_name_symlink_map_(std::move(by_name_symlink_map)) {
- InitializeAvbOps();
-}
-
-FsManagerAvbOps::FsManagerAvbOps(const fstab& fstab) {
- // Constructs the by-name symlink map for each fstab record.
- // /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a =>
- // by_name_symlink_map_["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
- for (int i = 0; i < fstab.num_entries; i++) {
- std::string partition_name = basename(fstab.recs[i].blk_device);
- by_name_symlink_map_[partition_name] = fstab.recs[i].blk_device;
- }
- InitializeAvbOps();
-}
-
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
size_t num_bytes, void* buffer,
size_t* out_num_read) {
- const auto iter = by_name_symlink_map_.find(partition);
- if (iter == by_name_symlink_map_.end()) {
- LERROR << "by-name symlink not found for partition: '" << partition << "'";
- return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
- }
- std::string path = iter->second;
+ const std::string path = "/dev/block/by-name/"s + partition;
// Ensures the device path (a symlink created by init) is ready to access.
if (!fs_mgr_wait_for_file(path, 1s)) {
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 845cca9..0983663 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -117,12 +117,7 @@
// clang-format off
const char* const args[] = {
"/system/bin/make_f2fs",
- "-d1",
- "-f",
- "-O", "encrypt",
- "-O", "quota",
- "-O", "verity",
- "-w", "4096",
+ "-g", "android",
fs_blkdev,
size_str.c_str(),
nullptr
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index a1de005..bef46e1 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -432,7 +432,7 @@
if (change) *change = true;
if (!DestroyLogicalPartition(partition_name, 0s)) return false;
} else {
- PERROR << "delete partition " << overlay;
+ LERROR << "delete partition " << overlay;
return false;
}
errno = save_errno;
@@ -647,49 +647,65 @@
if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
auto scratch_device = fs_mgr_overlayfs_scratch_device();
- auto partition_exists = fs_mgr_rw_access(scratch_device);
+ auto partition_create = !fs_mgr_rw_access(scratch_device);
+ auto slot_number = fs_mgr_overlayfs_slot_number();
+ auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+ if (!fs_mgr_rw_access(super_device)) return false;
+ if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+ auto builder = MetadataBuilder::New(super_device, slot_number);
+ if (!builder) {
+ LERROR << "open " << super_device << " metadata";
+ return false;
+ }
+ const auto partition_name = android::base::Basename(kScratchMountPoint);
+ auto partition = builder->FindPartition(partition_name);
+ auto partition_exists = partition != nullptr;
+ auto changed = false;
if (!partition_exists) {
- auto slot_number = fs_mgr_overlayfs_slot_number();
- auto super_device = fs_mgr_overlayfs_super_device(slot_number);
- if (!fs_mgr_rw_access(super_device)) return false;
- if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
- auto builder = MetadataBuilder::New(super_device, slot_number);
- if (!builder) {
- PERROR << "open " << super_device << " metadata";
+ partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+ if (!partition) {
+ LERROR << "create " << partition_name;
return false;
}
- const auto partition_name = android::base::Basename(kScratchMountPoint);
- partition_exists = builder->FindPartition(partition_name) != nullptr;
- if (!partition_exists) {
- auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
- if (!partition) {
- PERROR << "create " << partition_name;
- return false;
+ changed = true;
+ }
+ // Take half of free space, minimum 512MB or free space - 256KB margin.
+ static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024);
+ static constexpr auto kMarginSize = uint64_t(256 * 1024);
+ if (partition->size() < kMinimumSize) {
+ auto partition_size =
+ builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
+ if ((partition_size > kMinimumSize) || !partition->size()) {
+ partition_size = std::max(std::min(kMinimumSize, partition_size - kMarginSize),
+ partition_size / 2);
+ if (partition_size > partition->size()) {
+ if (!builder->ResizePartition(partition, partition_size)) {
+ LERROR << "resize " << partition_name;
+ return false;
+ }
+ if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+ changed = true;
+ partition_exists = false;
}
- auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
- // 512MB or half the remaining available space, whichever is greater.
- partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
- if (!builder->ResizePartition(partition, partition_size)) {
- PERROR << "resize " << partition_name;
- return false;
- }
-
- auto metadata = builder->Export();
- if (!metadata) {
- LERROR << "generate new metadata " << partition_name;
- return false;
- }
- if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
- LERROR << "update " << partition_name;
- return false;
- }
-
- if (change) *change = true;
+ }
+ }
+ // land the update back on to the partition
+ if (changed) {
+ auto metadata = builder->Export();
+ if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+ LERROR << "add partition " << partition_name;
+ return false;
}
+ if (change) *change = true;
+ }
+
+ if (changed || partition_create) {
if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
&scratch_device))
return false;
+
+ if (change) *change = true;
}
if (partition_exists) {
@@ -709,6 +725,7 @@
} else if (mnt_type == "ext4") {
command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
} else {
+ errno = ESRCH;
LERROR << mnt_type << " has no mkfs cookbook";
return false;
}
@@ -773,6 +790,8 @@
}
std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return {};
+
if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
return {};
}
diff --git a/fs_mgr/fs_mgr_priv_avb_ops.h b/fs_mgr/fs_mgr_priv_avb_ops.h
index d1ef2e9..44eb1da 100644
--- a/fs_mgr/fs_mgr_priv_avb_ops.h
+++ b/fs_mgr/fs_mgr_priv_avb_ops.h
@@ -46,8 +46,7 @@
//
class FsManagerAvbOps {
public:
- FsManagerAvbOps(const fstab& fstab);
- FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map);
+ FsManagerAvbOps();
static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
@@ -60,8 +59,6 @@
AvbSlotVerifyData** out_data);
private:
- void InitializeAvbOps();
-
AvbOps avb_ops_;
std::map<std::string, std::string> by_name_symlink_map_;
};
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index e1815ff..830f0dd 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -35,43 +35,42 @@
namespace {
-const auto kVendorOverlaySourceDir = "/system/vendor_overlay/"s;
+// The order of the list means the priority to show the files in the directory.
+// The last one has the highest priority.
+const std::vector<const std::string> kVendorOverlaySourceDirs = {
+ "/system/vendor_overlay/",
+ "/product/vendor_overlay/",
+};
const auto kVndkVersionPropertyName = "ro.vndk.version"s;
const auto kVendorTopDir = "/vendor/"s;
const auto kLowerdirOption = "lowerdir="s;
-std::string fs_mgr_get_vendor_overlay_top_dir() {
- // VNDK version is provided by the /vendor/default.prop
- // To read the property, it must be called at the second init stage after the default
- // properties are loaded.
- std::string vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
- if (vndk_version.empty()) {
- return "";
- }
- return kVendorOverlaySourceDir + vndk_version;
-}
+std::vector<std::pair<std::string, std::string>> fs_mgr_get_vendor_overlay_dirs(
+ const std::string& vndk_version) {
+ std::vector<std::pair<std::string, std::string>> vendor_overlay_dirs;
+ for (const auto& vendor_overlay_source : kVendorOverlaySourceDirs) {
+ const auto overlay_top = vendor_overlay_source + vndk_version;
+ std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
+ closedir);
+ if (!vendor_overlay_top) continue;
-std::vector<std::string> fs_mgr_get_vendor_overlay_dirs(const std::string& overlay_top) {
- std::vector<std::string> vendor_overlay_dirs;
- std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
- closedir);
- if (!vendor_overlay_top) return vendor_overlay_dirs;
+ // Vendor overlay root for current vendor version found!
+ LINFO << "vendor overlay root: " << overlay_top;
- // Vendor overlay root for current vendor version found!
- LINFO << "vendor overlay root: " << overlay_top;
- struct dirent* dp;
- while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
- if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
- continue;
+ struct dirent* dp;
+ while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
+ if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
+ continue;
+ }
+ vendor_overlay_dirs.emplace_back(overlay_top, dp->d_name);
}
- vendor_overlay_dirs.push_back(dp->d_name);
}
-
return vendor_overlay_dirs;
}
-bool fs_mgr_vendor_overlay_mount(const std::string& overlay_top, const std::string& mount_point) {
- const auto vendor_mount_point = kVendorTopDir + mount_point;
+bool fs_mgr_vendor_overlay_mount(const std::pair<std::string, std::string>& mount_point) {
+ const auto [overlay_top, mount_dir] = mount_point;
+ const auto vendor_mount_point = kVendorTopDir + mount_dir;
LINFO << "vendor overlay mount on " << vendor_mount_point;
const auto target_context = fs_mgr_get_context(vendor_mount_point);
@@ -79,7 +78,7 @@
PERROR << " failed: cannot find the target vendor mount point";
return false;
}
- const auto source_directory = overlay_top + "/" + mount_point;
+ const auto source_directory = overlay_top + "/" + mount_dir;
const auto source_context = fs_mgr_get_context(source_directory);
if (target_context != source_context) {
LERROR << " failed: source and target contexts do not match (source:" << source_context
@@ -112,22 +111,25 @@
// To read the properties, vendor overlay must be mounted at the second stage, right
// after "property_load_boot_defaults()" is called.
bool fs_mgr_vendor_overlay_mount_all() {
- const auto overlay_top = fs_mgr_get_vendor_overlay_top_dir();
- if (overlay_top.empty()) {
+ // To read the property, it must be called at the second init stage after the default
+ // properties are loaded.
+ static const auto vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
+ if (vndk_version.empty()) {
LINFO << "vendor overlay: vndk version not defined";
return false;
}
- const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(overlay_top);
+
+ const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(vndk_version);
if (vendor_overlay_dirs.empty()) return true;
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
LINFO << "vendor overlay: kernel does not support overlayfs";
return false;
}
- // Mount each directory in /system/vendor_overlay/<ver> on /vendor
+ // Mount each directory in /(system|product)/vendor_overlay/<ver> on /vendor
auto ret = true;
for (const auto& vendor_overlay_dir : vendor_overlay_dirs) {
- if (!fs_mgr_vendor_overlay_mount(overlay_top, vendor_overlay_dir)) {
+ if (!fs_mgr_vendor_overlay_mount(vendor_overlay_dir)) {
ret = false;
}
}
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h
index 73a22c8..bb55a14 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -53,13 +53,6 @@
// A typical usage will be:
// - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
//
- // There are two overloaded Open() functions with a single parameter.
- // The argument can be a ByNameSymlinkMap describing the mapping from partition
- // name to by-name symlink, or a fstab file to which the ByNameSymlinkMap is
- // constructed from. e.g.,
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a ->
- // - ByNameSymlinkMap["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
- //
// Possible return values:
// - nullptr: any error when reading and verifying the metadata,
// e.g., I/O error, digest value mismatch, size mismatch, etc.
@@ -82,8 +75,7 @@
// - a valid unique_ptr with status kAvbHandleSuccess: the metadata
// is verified and can be trusted.
//
- static FsManagerAvbUniquePtr Open(const fstab& fstab);
- static FsManagerAvbUniquePtr Open(ByNameSymlinkMap&& by_name_symlink_map);
+ static FsManagerAvbUniquePtr Open();
// Sets up dm-verity on the given fstab entry.
// The 'wait_for_verity_dev' parameter makes this function wait for the
@@ -121,7 +113,6 @@
};
FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
- static FsManagerAvbUniquePtr DoOpen(FsManagerAvbOps* avb_ops);
AvbSlotVerifyData* avb_slot_data_;
AvbHandleStatus status_;
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index 5689bdf..355b7a1 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -39,6 +39,11 @@
"libext4_utils",
"libz",
],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
export_include_dirs: ["include"],
}
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 6b4901b..da86d75 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include "liblp/liblp.h"
@@ -29,6 +30,9 @@
namespace android {
namespace fs_mgr {
+bool MetadataBuilder::sABOverrideSet;
+bool MetadataBuilder::sABOverrideValue;
+
bool LinearExtent::AddTo(LpMetadata* out) const {
if (device_index_ >= out->block_devices.size()) {
LERROR << "Extent references unknown block device.";
@@ -158,42 +162,56 @@
return nullptr;
}
- // Get the list of devices we already have.
- std::set<std::string> block_devices;
- for (const auto& block_device : metadata->block_devices) {
- block_devices.emplace(GetBlockDevicePartitionName(block_device));
+ // On non-retrofit devices there is only one location for metadata: the
+ // super partition. update_engine will remove and resize partitions as
+ // needed. On the other hand, for retrofit devices, we'll need to
+ // translate block device and group names to update their slot suffixes.
+ auto super_device = GetMetadataSuperBlockDevice(*metadata.get());
+ if (GetBlockDevicePartitionName(*super_device) == "super") {
+ return New(*metadata.get(), &opener);
}
- auto new_block_devices = metadata->block_devices;
+ // Clear partitions and extents, since they have no meaning on the target
+ // slot. We also clear groups since they are re-added during OTA.
+ metadata->partitions.clear();
+ metadata->extents.clear();
+ metadata->groups.clear();
- // Add missing block devices.
std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number);
std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number);
- for (const auto& block_device : metadata->block_devices) {
- std::string partition_name = GetBlockDevicePartitionName(block_device);
+
+ // Translate block devices.
+ auto source_block_devices = std::move(metadata->block_devices);
+ for (const auto& source_block_device : source_block_devices) {
+ std::string partition_name = GetBlockDevicePartitionName(source_block_device);
std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
- continue;
+ // This should never happen. It means that the source metadata
+ // refers to a target or unknown block device.
+ LERROR << "Invalid block device for slot " << source_slot_suffix << ": "
+ << partition_name;
+ return nullptr;
}
std::string new_name =
partition_name.substr(0, partition_name.size() - slot_suffix.size()) +
target_slot_suffix;
- if (block_devices.find(new_name) != block_devices.end()) {
- continue;
- }
- auto new_device = block_device;
+ auto new_device = source_block_device;
if (!UpdateBlockDevicePartitionName(&new_device, new_name)) {
LERROR << "Partition name too long: " << new_name;
return nullptr;
}
- new_block_devices.emplace_back(new_device);
+ metadata->block_devices.emplace_back(new_device);
}
- metadata->block_devices = new_block_devices;
return New(*metadata.get(), &opener);
}
+void MetadataBuilder::OverrideABForTesting(bool ab_device) {
+ sABOverrideSet = true;
+ sABOverrideValue = ab_device;
+}
+
MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
memset(&geometry_, 0, sizeof(geometry_));
geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
@@ -418,6 +436,11 @@
LERROR << "Could not find partition group: " << group_name;
return nullptr;
}
+ if (IsABDevice() && !auto_slot_suffixing_ && name != "scratch" &&
+ GetPartitionSlotSuffix(name).empty()) {
+ LERROR << "Unsuffixed partition not allowed on A/B device: " << name;
+ return nullptr;
+ }
partitions_.push_back(std::make_unique<Partition>(name, group_name, attributes));
return partitions_.back().get();
}
@@ -536,8 +559,8 @@
if (group_size >= group->maximum_size() ||
group->maximum_size() - group_size < space_needed) {
LERROR << "Partition " << partition->name() << " is part of group " << group->name()
- << " which does not have enough space free (" << space_needed << "requested, "
- << group_size << " used out of " << group->maximum_size();
+ << " which does not have enough space free (" << space_needed << " requested, "
+ << group_size << " used out of " << group->maximum_size() << ")";
return false;
}
}
@@ -623,6 +646,9 @@
LERROR << "Partition group name is too long: " << group->name();
return nullptr;
}
+ if (auto_slot_suffixing_ && group->name() != "default") {
+ out.flags |= LP_GROUP_SLOT_SUFFIXED;
+ }
strncpy(out.name, group->name().c_str(), sizeof(out.name));
out.maximum_size = group->maximum_size();
@@ -713,6 +739,11 @@
return false;
}
+bool MetadataBuilder::HasBlockDevice(const std::string& partition_name) const {
+ uint32_t index;
+ return FindBlockDeviceByName(partition_name, &index);
+}
+
bool MetadataBuilder::GetBlockDeviceInfo(const std::string& partition_name,
BlockDeviceInfo* info) const {
uint32_t index;
@@ -892,5 +923,12 @@
auto_slot_suffixing_ = true;
}
+bool MetadataBuilder::IsABDevice() const {
+ if (sABOverrideSet) {
+ return sABOverrideValue;
+ }
+ return android::base::GetBoolProperty("ro.build.ab_update", false);
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 35cab38..926fe12 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -25,7 +25,25 @@
using namespace android::fs_mgr;
using ::testing::ElementsAre;
-TEST(liblp, BuildBasic) {
+class Environment : public ::testing::Environment {
+ public:
+ void SetUp() override { MetadataBuilder::OverrideABForTesting(false); }
+};
+
+int main(int argc, char** argv) {
+ std::unique_ptr<Environment> env(new Environment);
+ ::testing::AddGlobalTestEnvironment(env.get());
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+class BuilderTest : public ::testing::Test {
+ public:
+ void SetUp() override { MetadataBuilder::OverrideABForTesting(false); }
+ void TearDown() override { MetadataBuilder::OverrideABForTesting(false); }
+};
+
+TEST_F(BuilderTest, BuildBasic) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
ASSERT_NE(builder, nullptr);
@@ -40,7 +58,7 @@
EXPECT_EQ(builder->FindPartition("system"), nullptr);
}
-TEST(liblp, ResizePartition) {
+TEST_F(BuilderTest, ResizePartition) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
ASSERT_NE(builder, nullptr);
@@ -94,7 +112,7 @@
EXPECT_EQ(system->extents().size(), 0);
}
-TEST(liblp, PartitionAlignment) {
+TEST_F(BuilderTest, PartitionAlignment) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
ASSERT_NE(builder, nullptr);
@@ -110,7 +128,7 @@
EXPECT_EQ(system->extents().size(), 1);
}
-TEST(liblp, DiskAlignment) {
+TEST_F(BuilderTest, DiskAlignment) {
static const uint64_t kDiskSize = 1000000;
static const uint32_t kMetadataSize = 1024;
static const uint32_t kMetadataSlots = 2;
@@ -120,7 +138,7 @@
ASSERT_EQ(builder, nullptr);
}
-TEST(liblp, MetadataAlignment) {
+TEST_F(BuilderTest, MetadataAlignment) {
// Make sure metadata sizes get aligned up.
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1000, 2);
ASSERT_NE(builder, nullptr);
@@ -129,7 +147,7 @@
EXPECT_EQ(exported->geometry.metadata_max_size, 1024);
}
-TEST(liblp, InternalAlignment) {
+TEST_F(BuilderTest, InternalAlignment) {
// Test the metadata fitting within alignment.
BlockDeviceInfo device_info("super", 1024 * 1024, 768 * 1024, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 2);
@@ -177,7 +195,7 @@
EXPECT_EQ(super_device->first_logical_sector, 160);
}
-TEST(liblp, InternalPartitionAlignment) {
+TEST_F(BuilderTest, InternalPartitionAlignment) {
BlockDeviceInfo device_info("super", 512 * 1024 * 1024, 768 * 1024, 753664, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
@@ -211,7 +229,7 @@
EXPECT_EQ(exported->extents.back().target_data, 30656);
}
-TEST(liblp, UseAllDiskSpace) {
+TEST_F(BuilderTest, UseAllDiskSpace) {
static constexpr uint64_t total = 1024 * 1024;
static constexpr uint64_t metadata = 1024;
static constexpr uint64_t slots = 2;
@@ -237,7 +255,7 @@
EXPECT_EQ(builder->AllocatableSpace(), allocatable);
}
-TEST(liblp, BuildComplex) {
+TEST_F(BuilderTest, BuildComplex) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
@@ -271,7 +289,7 @@
EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
}
-TEST(liblp, AddInvalidPartition) {
+TEST_F(BuilderTest, AddInvalidPartition) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
Partition* partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
@@ -286,7 +304,7 @@
EXPECT_EQ(partition, nullptr);
}
-TEST(liblp, BuilderExport) {
+TEST_F(BuilderTest, BuilderExport) {
static const uint64_t kDiskSize = 1024 * 1024;
static const uint32_t kMetadataSize = 1024;
static const uint32_t kMetadataSlots = 2;
@@ -344,7 +362,7 @@
}
}
-TEST(liblp, BuilderImport) {
+TEST_F(BuilderTest, BuilderImport) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
@@ -382,7 +400,7 @@
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
}
-TEST(liblp, ExportNameTooLong) {
+TEST_F(BuilderTest, ExportNameTooLong) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
std::string name = "abcdefghijklmnopqrstuvwxyz0123456789";
@@ -393,7 +411,7 @@
EXPECT_EQ(exported, nullptr);
}
-TEST(liblp, MetadataTooLarge) {
+TEST_F(BuilderTest, MetadataTooLarge) {
static const size_t kDiskSize = 128 * 1024;
static const size_t kMetadataSize = 64 * 1024;
@@ -423,7 +441,7 @@
EXPECT_EQ(builder, nullptr);
}
-TEST(liblp, block_device_info) {
+TEST_F(BuilderTest, block_device_info) {
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
ASSERT_NE(fstab, nullptr);
@@ -444,7 +462,7 @@
ASSERT_LT(device_info.alignment_offset, device_info.alignment);
}
-TEST(liblp, UpdateBlockDeviceInfo) {
+TEST_F(BuilderTest, UpdateBlockDeviceInfo) {
BlockDeviceInfo device_info("super", 1024 * 1024, 4096, 1024, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
@@ -482,13 +500,13 @@
EXPECT_EQ(new_info.logical_block_size, 4096);
}
-TEST(liblp, InvalidBlockSize) {
+TEST_F(BuilderTest, InvalidBlockSize) {
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 513);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
EXPECT_EQ(builder, nullptr);
}
-TEST(liblp, AlignedExtentSize) {
+TEST_F(BuilderTest, AlignedExtentSize) {
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
@@ -499,14 +517,14 @@
EXPECT_EQ(partition->size(), 4096);
}
-TEST(liblp, AlignedFreeSpace) {
+TEST_F(BuilderTest, AlignedFreeSpace) {
// Only one sector free - at least one block is required.
BlockDeviceInfo device_info("super", 10240, 0, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 512, 1);
ASSERT_EQ(builder, nullptr);
}
-TEST(liblp, HasDefaultGroup) {
+TEST_F(BuilderTest, HasDefaultGroup) {
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
@@ -514,7 +532,7 @@
EXPECT_FALSE(builder->AddGroup("default", 0));
}
-TEST(liblp, GroupSizeLimits) {
+TEST_F(BuilderTest, GroupSizeLimits) {
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
@@ -538,7 +556,7 @@
return x << 20;
}
-TEST(liblp, RemoveAndAddFirstPartition) {
+TEST_F(BuilderTest, RemoveAndAddFirstPartition) {
auto builder = MetadataBuilder::New(10_GiB, 65536, 2);
ASSERT_NE(nullptr, builder);
ASSERT_TRUE(builder->AddGroup("foo_a", 5_GiB));
@@ -561,7 +579,7 @@
ASSERT_TRUE(p && builder->ResizePartition(p, 1_GiB));
}
-TEST(liblp, ListGroups) {
+TEST_F(BuilderTest, ListGroups) {
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
@@ -571,7 +589,7 @@
ASSERT_THAT(groups, ElementsAre("default", "example"));
}
-TEST(liblp, RemoveGroupAndPartitions) {
+TEST_F(BuilderTest, RemoveGroupAndPartitions) {
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
@@ -588,7 +606,7 @@
ASSERT_NE(builder->FindPartition("system"), nullptr);
}
-TEST(liblp, MultipleBlockDevices) {
+TEST_F(BuilderTest, MultipleBlockDevices) {
std::vector<BlockDeviceInfo> partitions = {
BlockDeviceInfo("system_a", 256_MiB, 786432, 229376, 4096),
BlockDeviceInfo("vendor_a", 128_MiB, 786432, 753664, 4096),
@@ -633,7 +651,7 @@
EXPECT_EQ(metadata->extents[2].target_source, 2);
}
-TEST(liblp, ImportPartitionsOk) {
+TEST_F(BuilderTest, ImportPartitionsOk) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
ASSERT_NE(builder, nullptr);
@@ -673,7 +691,7 @@
EXPECT_EQ(extent_a.target_source, extent_b.target_source);
}
-TEST(liblp, ImportPartitionsFail) {
+TEST_F(BuilderTest, ImportPartitionsFail) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
ASSERT_NE(builder, nullptr);
@@ -693,3 +711,12 @@
ASSERT_NE(builder, nullptr);
EXPECT_FALSE(builder->ImportPartitions(*exported.get(), {"system"}));
}
+
+TEST_F(BuilderTest, UnsuffixedPartitions) {
+ MetadataBuilder::OverrideABForTesting(true);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
+ ASSERT_NE(builder, nullptr);
+
+ ASSERT_EQ(builder->AddPartition("system", 0), nullptr);
+ ASSERT_NE(builder->AddPartition("system_a", 0), nullptr);
+}
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index a976643..5a498f9 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -27,6 +27,12 @@
namespace android {
namespace fs_mgr {
+using android::base::unique_fd;
+
+#if defined(_WIN32)
+static const int O_NOFOLLOW = 0;
+#endif
+
std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, 0, SEEK_SET) < 0) {
@@ -61,10 +67,10 @@
return ParseMetadata(geometry, metadata_buffer, metadata_buffer_size);
}
-std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
- android::base::unique_fd fd(open(file, O_RDONLY | O_CLOEXEC));
+std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file) {
+ unique_fd fd(open(image_file.c_str(), O_RDONLY | O_CLOEXEC));
if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << image_file;
return nullptr;
}
return ReadFromImageFile(fd);
@@ -84,7 +90,7 @@
}
bool WriteToImageFile(const char* file, const LpMetadata& input) {
- android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
+ unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
return false;
@@ -120,7 +126,7 @@
return;
}
- uint64_t num_blocks = total_size % block_size;
+ uint64_t num_blocks = total_size / block_size;
if (num_blocks >= UINT_MAX) {
// libsparse counts blocks in unsigned 32-bit integers, so we check to
// make sure we're not going to overflow.
@@ -143,7 +149,7 @@
}
bool SparseBuilder::Export(const char* file) {
- android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
+ unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
if (fd < 0) {
PERROR << "open failed: " << file;
return false;
@@ -162,19 +168,15 @@
}
bool SparseBuilder::ExportFiles(const std::string& output_dir) {
- android::base::unique_fd dir(open(output_dir.c_str(), O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW));
- if (dir < 0) {
- PERROR << "open dir failed: " << output_dir;
- return false;
- }
-
for (size_t i = 0; i < device_images_.size(); i++) {
std::string name = GetBlockDevicePartitionName(metadata_.block_devices[i]);
- std::string path = output_dir + "/super_" + name + ".img";
- android::base::unique_fd fd(openat(
- dir, path.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0644));
+ std::string file_name = "super_" + name + ".img";
+ std::string file_path = output_dir + "/" + file_name;
+
+ static const int kOpenFlags = O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW;
+ unique_fd fd(open(file_path.c_str(), kOpenFlags, 0644));
if (fd < 0) {
- PERROR << "open failed: " << path;
+ PERROR << "open failed: " << file_path;
return false;
}
// No gzip compression; sparseify; no checksum.
@@ -299,7 +301,7 @@
uint64_t partition_size = ComputePartitionSize(partition);
if (file_length > partition_size) {
LERROR << "Image for partition '" << GetPartitionName(partition)
- << "' is greater than its size (" << file_length << ", excepted " << partition_size
+ << "' is greater than its size (" << file_length << ", expected " << partition_size
<< ")";
return false;
}
@@ -419,25 +421,19 @@
return fd;
}
- char temp_file[PATH_MAX];
- snprintf(temp_file, sizeof(temp_file), "%s/imageXXXXXX", P_tmpdir);
- android::base::unique_fd temp_fd(mkstemp(temp_file));
- if (temp_fd < 0) {
- PERROR << "mkstemp failed";
- return -1;
- }
- if (unlink(temp_file) < 0) {
- PERROR << "unlink failed";
+ TemporaryFile tf;
+ if (tf.fd < 0) {
+ PERROR << "make temporary file failed";
return -1;
}
// We temporarily unsparse the file, rather than try to merge its chunks.
- int rv = sparse_file_write(source.get(), temp_fd, false, false, false);
+ int rv = sparse_file_write(source.get(), tf.fd, false, false, false);
if (rv) {
LERROR << "sparse_file_write failed with code: " << rv;
return -1;
}
- temp_fds_.push_back(std::move(temp_fd));
+ temp_fds_.push_back(android::base::unique_fd(tf.release()));
return temp_fds_.back().get();
}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 59717d1..4bb38d6 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -22,6 +22,7 @@
#include <map>
#include <memory>
+#include <optional>
#include <set>
#include "liblp.h"
@@ -186,6 +187,9 @@
return New(device_info, metadata_max_size, metadata_slot_count);
}
+ // Used by the test harness to override whether the device is "A/B".
+ static void OverrideABForTesting(bool ab_device);
+
// Define a new partition group. By default there is one group called
// "default", with an unrestricted size. A non-zero size will restrict the
// total space used by all partitions in the group.
@@ -248,6 +252,9 @@
// false is returned.
bool ImportPartitions(const LpMetadata& metadata, const std::set<std::string>& partition_names);
+ // Return true if a block device is found, else false.
+ bool HasBlockDevice(const std::string& partition_name) const;
+
private:
MetadataBuilder();
MetadataBuilder(const MetadataBuilder&) = delete;
@@ -267,6 +274,7 @@
void ImportExtents(Partition* dest, const LpMetadata& metadata,
const LpMetadataPartition& source);
bool ImportPartition(const LpMetadata& metadata, const LpMetadataPartition& source);
+ bool IsABDevice() const;
struct Interval {
uint32_t device_index;
@@ -287,6 +295,9 @@
void ExtentsToFreeList(const std::vector<Interval>& extents,
std::vector<Interval>* free_regions) const;
+ static bool sABOverrideValue;
+ static bool sABOverrideSet;
+
LpMetadataGeometry geometry_;
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 1af1e80..6348f55 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -75,7 +75,7 @@
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
const std::map<std::string, std::string>& images);
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
-std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
+std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file);
std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
// Similar to WriteToSparseFile, this will generate an image that can be
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index c2e25fb..9c5ec5c 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 9
+#define LP_METADATA_MAJOR_VERSION 10
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -267,10 +267,19 @@
/* 0: Name of this group. Any unused characters must be 0. */
char name[36];
- /* 36: Maximum size in bytes. If 0, the group has no maximum size. */
+ /* 36: Flags (see LP_GROUP_*). */
+ uint32_t flags;
+
+ /* 40: Maximum size in bytes. If 0, the group has no maximum size. */
uint64_t maximum_size;
} LpMetadataPartitionGroup;
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. If set, the group needs a slot suffix to be interpreted
+ * correctly. The suffix is automatically applied by ReadMetadata().
+ */
+#define LP_GROUP_SLOT_SUFFIXED (1 << 0)
+
/* This struct defines an entry in the block_devices table. There must be at
* least one device, and the first device must represent the partition holding
* the super metadata.
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 9acf23e..9f3314d 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -622,6 +622,7 @@
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
ASSERT_NE(builder, nullptr);
ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+ ASSERT_TRUE(builder->AddGroup("example", 0));
builder->SetAutoSlotSuffixing();
auto fd = CreateFakeDisk();
@@ -641,6 +642,11 @@
EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_b");
ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_b");
+ ASSERT_EQ(metadata->groups.size(), static_cast<size_t>(2));
+ EXPECT_EQ(GetPartitionGroupName(metadata->groups[0]), "default");
+ EXPECT_EQ(GetPartitionGroupName(metadata->groups[1]), "example_b");
+ EXPECT_EQ(metadata->groups[0].flags, 0);
+ EXPECT_EQ(metadata->groups[1].flags, 0);
metadata = ReadMetadata(opener, "super_a", 0);
ASSERT_NE(metadata, nullptr);
@@ -648,12 +654,18 @@
EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_a");
ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
+ ASSERT_EQ(metadata->groups.size(), static_cast<size_t>(2));
+ EXPECT_EQ(GetPartitionGroupName(metadata->groups[0]), "default");
+ EXPECT_EQ(GetPartitionGroupName(metadata->groups[1]), "example_a");
+ EXPECT_EQ(metadata->groups[0].flags, 0);
+ EXPECT_EQ(metadata->groups[1].flags, 0);
}
TEST(liblp, UpdateRetrofit) {
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
ASSERT_NE(builder, nullptr);
ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+ ASSERT_TRUE(builder->AddGroup("example", 0));
builder->SetAutoSlotSuffixing();
auto fd = CreateFakeDisk();
@@ -671,9 +683,11 @@
ASSERT_NE(builder, nullptr);
auto updated = builder->Export();
ASSERT_NE(updated, nullptr);
- ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(2));
- EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_a");
- EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[1]), "super_b");
+ ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
+ EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_b");
+ ASSERT_TRUE(updated->groups.empty());
+ ASSERT_TRUE(updated->partitions.empty());
+ ASSERT_TRUE(updated->extents.empty());
}
TEST(liblp, UpdateNonRetrofit) {
diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp
index 77b0e62..898f241 100644
--- a/fs_mgr/liblp/partition_opener.cpp
+++ b/fs_mgr/liblp/partition_opener.cpp
@@ -19,8 +19,9 @@
#if defined(__linux__)
#include <linux/fs.h>
#endif
+#if !defined(_WIN32)
#include <sys/ioctl.h>
-#include <sys/stat.h>
+#endif
#include <sys/types.h>
#include <unistd.h>
@@ -53,18 +54,18 @@
return false;
}
if (ioctl(fd, BLKIOMIN, &device_info->alignment) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+ PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed on " << block_device;
return false;
}
int alignment_offset;
if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
+ PERROR << __PRETTY_FUNCTION__ << "BLKALIGNOFF failed on " << block_device;
return false;
}
int logical_block_size;
if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed";
+ PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed on " << block_device;
return false;
}
@@ -84,7 +85,7 @@
unique_fd PartitionOpener::Open(const std::string& partition_name, int flags) const {
std::string path = GetPartitionAbsolutePath(partition_name);
- return unique_fd{open(path.c_str(), flags)};
+ return unique_fd{open(path.c_str(), flags | O_CLOEXEC)};
}
bool PartitionOpener::GetInfo(const std::string& partition_name, BlockDeviceInfo* info) const {
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index b36ba0e..24c6b2c 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -375,6 +375,17 @@
}
block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED;
}
+ for (auto& group : metadata->groups) {
+ if (!(group.flags & LP_GROUP_SLOT_SUFFIXED)) {
+ continue;
+ }
+ std::string group_name = GetPartitionGroupName(group) + slot_suffix;
+ if (!UpdatePartitionGroupName(&group, group_name)) {
+ LERROR << __PRETTY_FUNCTION__ << " group name too long: " << group_name;
+ return false;
+ }
+ group.flags &= ~LP_GROUP_SLOT_SUFFIXED;
+ }
return true;
}
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 4f20b6b..9ccabe9 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -29,6 +29,7 @@
namespace fs_mgr {
bool GetDescriptorSize(int fd, uint64_t* size) {
+#if !defined(_WIN32)
struct stat s;
if (fstat(fd, &s) < 0) {
PERROR << __PRETTY_FUNCTION__ << "fstat failed";
@@ -39,6 +40,7 @@
*size = get_block_device_size(fd);
return *size != 0;
}
+#endif
int64_t result = SeekFile64(fd, 0, SEEK_END);
if (result == -1) {
@@ -145,5 +147,13 @@
return true;
}
+bool UpdatePartitionGroupName(LpMetadataPartitionGroup* group, const std::string& name) {
+ if (name.size() > sizeof(group->name)) {
+ return false;
+ }
+ strncpy(group->name, name.c_str(), sizeof(group->name));
+ return true;
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 55ecb5a..8b70919 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -86,6 +86,7 @@
// Update names from C++ strings.
bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name);
+bool UpdatePartitionGroupName(LpMetadataPartitionGroup* group, const std::string& name);
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index e72cdfa..d8195ca 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -235,6 +235,10 @@
return android::base::WriteFully(fd, blob.data(), blob.size());
}
+#if defined(_WIN32)
+static const int O_SYNC = 0;
+#endif
+
bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& super_partition,
const LpMetadata& metadata) {
android::base::unique_fd fd = opener.Open(super_partition, O_RDWR | O_SYNC);
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 98c0879..d9e017c 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -52,11 +52,28 @@
adb shell "${@}"
}
+[ "USAGE: adb_date >/dev/stdout
+
+Returns: report device epoch time (suitable for logcat -t)" ]
+adb_date() {
+ adb_sh date +%s.%N </dev/null
+}
+
+[ "USAGE: adb_logcat [arguments] >/dev/stdout
+
+Returns: the logcat output" ]
+adb_logcat() {
+ echo "${RED}[ INFO ]${NORMAL} logcat ${@}" >&2 &&
+ adb logcat "${@}" </dev/null |
+ grep -v 'logd : logdr: UID=' |
+ sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
+}
+
[ "USAGE: get_property <prop>
Returns the property value" ]
get_property() {
- adb_sh getprop ${1} 2>&1 </dev/null
+ adb_sh getprop ${1} </dev/null
}
[ "USAGE: isDebuggable
@@ -90,12 +107,13 @@
Returns: true if the reboot command succeeded" ]
adb_reboot() {
- adb reboot remount-test
+ adb reboot remount-test &&
+ sleep 2
}
[ "USAGE: adb_wait [timeout]
-Returns: waits until the device has returned or the optional timeout" ]
+Returns: waits until the device has returned for adb or optional timeout" ]
adb_wait() {
if [ -n "${1}" ]; then
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
@@ -104,17 +122,61 @@
fi
}
+[ "USAGE: fastboot_wait [timeout]
+
+Returns: waits until the device has returned for fastboot or optional timeout" ]
+fastboot_wait() {
+ # fastboot has no wait-for-device, but it does an automatic
+ # wait and requires (even a nonsensical) command to do so.
+ if [ -n "${1}" ]; then
+ timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
+ else
+ fastboot wait-for-device >/dev/null
+ fi >/dev/null 2>/dev/null ||
+ inFastboot
+}
+
[ "USAGE: adb_root
Returns: true if device in root state" ]
adb_root() {
- adb root >/dev/null </dev/null 2>&1 &&
- sleep 1 &&
- adb_wait &&
- sleep 1
+ adb root >/dev/null </dev/null 2>/dev/null
+ sleep 2
+ adb_wait 2m &&
+ [ `adb_sh echo '${USER}'` = root ]
}
+[ "USAGE: fastboot_getvar var expected
+
+Returns: true if var output matches expected" ]
+fastboot_getvar() {
+ O=`fastboot getvar ${1} 2>&1`
+ err=${?}
+ O="${O#< waiting for * >?}"
+ O="${O%%?Finished. Total time: *}"
+ if [ 0 -ne ${err} ]; then
+ echo ${O} >&2
+ false
+ return
+ fi
+ if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
+ echo "${2} != ${O}" >&2
+ false
+ return
+ fi
+ echo ${O} >&2
+}
+
+[ "USAGE: die [-t <epoch>] [message] >/dev/stderr
+
+If -t <epoch> argument is supplied, dump logcat.
+
+Returns: exit failure, report status" ]
die() {
+ if [ X"-t" = X"${1}" -a -n "${2}" ]; then
+ adb_logcat -b all -v nsec -t ${2} >&2
+ shift 2
+ fi
echo "${RED}[ FAILED ]${NORMAL} ${@}" >&2
exit 1
}
@@ -176,11 +238,15 @@
die "${@}"
}
-[ "USAGE: skip_administrative_mounts
+[ "USAGE: skip_administrative_mounts < /proc/mounts
-Filters out all administrative (eg: sysfs) mounts" ]
+Filters out all administrative (eg: sysfs) mounts uninteresting to the test" ]
skip_administrative_mounts() {
- grep -v -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\|/data/media\) " -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\|data\) "
+ grep -v \
+ -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
+ -e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
+ -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
+ -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\|data\) "
}
if [ X"-s" = X"${1}" -a -n "${2}" ]; then
@@ -204,13 +270,12 @@
adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
die "overlay module can not be used on ANDROID"
-adb_root &&
- adb_wait ||
+adb_root ||
die "initial setup"
reboot=false
OVERLAYFS_BACKING="cache mnt/scratch"
for d in ${OVERLAYFS_BACKING}; do
- if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>&1; then
+ if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
echo "${ORANGE}[ WARNING ]${NORMAL} /${d}/overlay is setup, wiping" >&2
adb_sh rm -rf /${d}/overlay </dev/null ||
die "/${d}/overlay wipe"
@@ -221,8 +286,7 @@
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
adb_reboot &&
adb_wait 2m &&
- adb_root &&
- adb_wait ||
+ adb_root ||
die "reboot after wipe"
fi
D=`adb_sh df -k </dev/null` &&
@@ -232,10 +296,17 @@
echo "${D}" &&
echo "${ORANGE}[ WARNING ]${NORMAL} overlays present before setup" >&2 ||
echo "${GREEN}[ OK ]${NORMAL} no overlay present before setup" >&2
+adb_sh df -k `adb_sh cat /proc/mounts |
+ skip_administrative_mounts |
+ cut -s -d' ' -f1`
-D=`adb disable-verity 2>&1` ||
- die "setup for overlay ${D}"
+T=`adb_date`
+D=`adb disable-verity 2>&1`
+err=${?}
echo "${D}"
+if [ ${err} != 0 -o X"${D}" != X"${D##*setup failed}" ]; then
+ die -t ${T} "setup for overlay"
+fi
if [ X"${D}" != X"${D##*using overlayfs}" ]; then
echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
fi
@@ -250,11 +321,11 @@
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover before remount not complete" >&2
+T=`adb_date`
adb_root &&
- adb_wait &&
adb remount &&
D=`adb_sh df -k </dev/null` ||
- die "can not collect filesystem data"
+ die -t ${T} "can not collect filesystem data"
if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
echo "${ORANGE}[ INFO ]${NORMAL} using scratch dynamic partition for overrides" >&2
H=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
@@ -262,7 +333,7 @@
echo "${ORANGE}[ INFO ]${NORMAL} scratch filesystem ${H}"
fi
for d in ${OVERLAYFS_BACKING}; do
- if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>&1; then
+ if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
echo "${ORANGE}[ INFO ]${NORMAL} /${d}/overlay is setup" >&2
fi
done
@@ -303,18 +374,31 @@
die "re-read vendor hello after reboot w/o root"
check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
adb_root &&
- adb_wait &&
B="`adb_cat /vendor/hello`" ||
die "re-read vendor hello after reboot"
check_eq "${A}" "${B}" vendor after reboot
adb reboot-fastboot &&
- fastboot flash vendor &&
- fastboot reboot ||
+ fastboot_wait 2m &&
+ fastboot flash vendor ||
die "fastbootd flash vendor"
-adb_wait &&
- adb_root &&
- adb_wait &&
+# check scratch via fastboot
+fastboot_getvar partition-type:scratch raw &&
+ fastboot_getvar has-slot:scratch no &&
+ fastboot_getvar is-logical:scratch yes ||
+ die "fastboot can not see scratch parameters"
+echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot erase scratch to fail" >&2
+fastboot erase scratch &&
+ die "fastbootd can erase scratch"
+echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot format scratch to fail" >&2
+fastboot format scratch &&
+ die "fastbootd can format scratch"
+fastboot reboot ||
+ die "can not reboot out of fastbootd"
+echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
+adb_wait 2m ||
+ die "did not reboot after flash"
+adb_root &&
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` &&
@@ -327,17 +411,17 @@
B="`adb_cat /system/hello`" ||
die "re-read system hello after flash vendor"
check_eq "${A}" "${B}" system after flash vendor
-adb_root &&
- adb_wait ||
+adb_root ||
die "adb root"
B="`adb_cat /vendor/hello`" &&
die "re-read vendor hello after flash vendor"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+T=`adb_date`
adb remount &&
( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
adb_sh rm /system/hello </dev/null ||
- die "cleanup hello"
+ die -t ${T} "cleanup hello"
B="`adb_cat /system/hello`" &&
die "re-read system hello after rm"
check_eq "cat: /system/hello: No such file or directory" "${B}" after flash rm
@@ -345,4 +429,27 @@
die "re-read vendor hello after rm"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
+adb reboot-fastboot &&
+ dd if=/dev/zero of=adb-remount-test.img bs=4096 count=16 &&
+ fastboot_wait 2m ||
+ die "reboot into fastbootd"
+fastboot flash scratch adb-remount-test.img
+err=${?}
+rm adb-remount-test.img
+[ 0 -eq ${err} ] ||
+ die "fastbootd flash scratch"
+fastboot reboot ||
+ die "can not reboot out of fastbootd"
+adb_wait 2m &&
+ adb_root ||
+ die "did not reboot after flash"
+T=`adb_date`
+D=`adb disable-verity 2>&1`
+err=${?}
+echo "${D}"
+[ ${err} = 0 ] &&
+ [ X"${D}" = X"${D##*setup failed}" ] &&
+ [ X"${D}" != X"${D##*using overlayfs}" ] ||
+ die -t ${T} "setup for overlayfs"
+
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index f2818f3..446b66e 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -25,7 +25,7 @@
#include <unistd.h>
#include <memory>
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
@@ -318,8 +318,8 @@
// TODO: cache service?
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
- sp<security::IKeystoreService> service =
- interface_cast<security::IKeystoreService>(binder);
+ sp<security::keystore::IKeystoreService> service =
+ interface_cast<security::keystore::IKeystoreService>(binder);
if (service != NULL) {
std::vector<uint8_t> auth_token_vector(*auth_token,
(*auth_token) + *auth_token_length);
diff --git a/init/README.md b/init/README.md
index 4b21e32..5c07ac1 100644
--- a/init/README.md
+++ b/init/README.md
@@ -332,6 +332,13 @@
This is particularly useful for creating a periodic service combined with the restart_period
option described above.
+`updatable`
+> Mark that the service can be overridden (via the 'override' option) later in
+ the boot sequence by APEXes. When a service with updatable option is started
+ before APEXes are all activated, the execution is delayed until the activation
+ is finished. A service that is not marked as updatable cannot be overridden by
+ APEXes.
+
`user <username>`
> Change to 'username' before exec'ing this service.
Currently defaults to root. (??? probably should default to nobody)
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8660d2a..6eb65b2 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1060,7 +1060,8 @@
// where the APEXes are really mounted at. Otherwise, we will parse the
// same file twice.
static constexpr char glob_pattern[] = "/apex/*@*/etc/*.rc";
- if (glob(glob_pattern, GLOB_MARK, nullptr, &glob_result) != 0) {
+ const int ret = glob(glob_pattern, GLOB_MARK, nullptr, &glob_result);
+ if (ret != 0 && ret != GLOB_NOMATCH) {
globfree(&glob_result);
return Error() << "glob pattern '" << glob_pattern << "' failed";
}
@@ -1079,6 +1080,7 @@
}
success &= parser.ParseConfigFile(c);
}
+ ServiceList::GetInstance().MarkServicesUpdate();
if (success) {
return Success();
} else {
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index d658f4d..3e7c1a8 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -16,8 +16,8 @@
#include "devices.h"
+#include <android-base/file.h>
#include <android-base/scopeguard.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include "util.h"
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a8b7862..a3257f5 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -73,7 +73,7 @@
bool GetDmLinearMetadataDevice();
bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
- virtual ListenerAction UeventCallback(const Uevent& uevent);
+ ListenerAction UeventCallback(const Uevent& uevent);
// Pure virtual functions.
virtual bool GetDmVerityDevices() = 0;
@@ -108,14 +108,12 @@
~FirstStageMountVBootV2() override = default;
protected:
- ListenerAction UeventCallback(const Uevent& uevent) override;
bool GetDmVerityDevices() override;
bool SetUpDmVerity(fstab_rec* fstab_rec) override;
bool InitAvbHandle();
std::string device_tree_vbmeta_parts_;
FsManagerAvbUniquePtr avb_handle_;
- ByNameSymlinkMap by_name_symlink_map_;
};
// Static Functions
@@ -451,7 +449,9 @@
// Includes the partition names of fstab records and verity_loc_device (if any).
// Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
for (auto fstab_rec : mount_fstab_recs_) {
- required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ if (!fs_mgr_is_logical(fstab_rec)) {
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ }
}
if (!verity_loc_device.empty()) {
@@ -544,33 +544,6 @@
return true;
}
-ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
- // Check if this uevent corresponds to one of the required partitions and store its symlinks if
- // so, in order to create FsManagerAvbHandle later.
- // Note that the parent callback removes partitions from the list of required partitions
- // as it finds them, so this must happen first.
- if (!uevent.partition_name.empty() &&
- required_devices_partition_names_.find(uevent.partition_name) !=
- required_devices_partition_names_.end()) {
- // GetBlockDeviceSymlinks() will return three symlinks at most, depending on
- // the content of uevent. by-name symlink will be at [0] if uevent->partition_name
- // is not empty. e.g.,
- // - /dev/block/platform/soc.0/f9824900.sdhci/by-name/modem
- // - /dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1
- std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
- if (!links.empty()) {
- auto [it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
- if (!inserted) {
- LOG(ERROR) << "Partition '" << uevent.partition_name
- << "' already existed in the by-name symlink map with a value of '"
- << it->second << "', new value '" << links[0] << "' will be ignored.";
- }
- }
- }
-
- return FirstStageMount::UeventCallback(uevent);
-}
-
bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
if (fs_mgr_is_avb(fstab_rec)) {
if (!InitAvbHandle()) return false;
@@ -594,13 +567,7 @@
bool FirstStageMountVBootV2::InitAvbHandle() {
if (avb_handle_) return true; // Returns true if the handle is already initialized.
- if (by_name_symlink_map_.empty()) {
- LOG(ERROR) << "by_name_symlink_map_ is empty";
- return false;
- }
-
- avb_handle_ = FsManagerAvbHandle::Open(std::move(by_name_symlink_map_));
- by_name_symlink_map_.clear(); // Removes all elements after the above std::move().
+ avb_handle_ = FsManagerAvbHandle::Open();
if (!avb_handle_) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
@@ -651,8 +618,7 @@
return;
}
- FsManagerAvbUniquePtr avb_handle =
- FsManagerAvbHandle::Open(std::move(avb_first_mount.by_name_symlink_map_));
+ FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open();
if (!avb_handle) {
PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
return;
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 0f9635f..c2f0c41 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -17,7 +17,6 @@
#include <functional>
#include <android-base/file.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include "action.h"
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
index 872e9a1..13796a6 100644
--- a/init/persistent_properties_test.cpp
+++ b/init/persistent_properties_test.cpp
@@ -20,7 +20,7 @@
#include <vector>
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
#include <gtest/gtest.h>
#include "util.h"
diff --git a/init/reboot.cpp b/init/reboot.cpp
index a145797..45dc6d3 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -468,7 +468,7 @@
// adb reboot fastboot should boot into bootloader for devices not
// supporting logical partitions.
if (reboot_target == "fastboot" &&
- !android::base::GetBoolProperty("ro.boot.logical_partitions", false)) {
+ !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
reboot_target = "bootloader";
}
// When rebooting to the bootloader notify the bootloader writing
diff --git a/init/service.cpp b/init/service.cpp
index 1bda7ec..5aa3764 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -765,6 +765,11 @@
return Success();
}
+Result<Success> Service::ParseUpdatable(std::vector<std::string>&& args) {
+ updatable_ = true;
+ return Success();
+}
+
class Service::OptionParserMap : public KeywordMap<OptionParser> {
public:
OptionParserMap() {}
@@ -817,6 +822,7 @@
{"socket", {3, 6, &Service::ParseSocket}},
{"timeout_period",
{1, 1, &Service::ParseTimeoutPeriod}},
+ {"updatable", {0, 0, &Service::ParseUpdatable}},
{"user", {1, 1, &Service::ParseUser}},
{"writepid", {1, kMax, &Service::ParseWritepid}},
};
@@ -834,6 +840,13 @@
}
Result<Success> Service::ExecStart() {
+ if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+ // Don't delay the service for ExecStart() as the semantic is that
+ // the caller might depend on the side effect of the execution.
+ return Error() << "Cannot start an updatable service '" << name_
+ << "' before configs from APEXes are all loaded";
+ }
+
flags_ |= SVC_ONESHOT;
if (auto result = Start(); !result) {
@@ -851,6 +864,13 @@
}
Result<Success> Service::Start() {
+ if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+ ServiceList::GetInstance().DelayService(*this);
+ return Error() << "Cannot start an updatable service '" << name_
+ << "' before configs from APEXes are all loaded. "
+ << "Queued for execution.";
+ }
+
bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
@@ -1280,6 +1300,32 @@
}
}
+void ServiceList::MarkServicesUpdate() {
+ services_update_finished_ = true;
+
+ // start the delayed services
+ for (const auto& name : delayed_service_names_) {
+ Service* service = FindService(name);
+ if (service == nullptr) {
+ LOG(ERROR) << "delayed service '" << name << "' could not be found.";
+ continue;
+ }
+ if (auto result = service->Start(); !result) {
+ LOG(ERROR) << result.error_string();
+ }
+ }
+ delayed_service_names_.clear();
+}
+
+void ServiceList::DelayService(const Service& service) {
+ if (services_update_finished_) {
+ LOG(ERROR) << "Cannot delay the start of service '" << service.name()
+ << "' because all services are already updated. Ignoring.";
+ return;
+ }
+ delayed_service_names_.emplace_back(service.name());
+}
+
Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
const std::string& filename, int line) {
if (args.size() < 3) {
@@ -1291,6 +1337,8 @@
return Error() << "invalid service name '" << name << "'";
}
+ filename_ = filename;
+
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
@@ -1326,6 +1374,11 @@
<< "'";
}
+ if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
+ return Error() << "cannot update a non-updatable service '" << service_->name()
+ << "' with a config in APEX";
+ }
+
service_list_->RemoveService(*old_service);
old_service = nullptr;
}
diff --git a/init/service.h b/init/service.h
index 49b09ce..56e75b0 100644
--- a/init/service.h
+++ b/init/service.h
@@ -123,6 +123,7 @@
std::chrono::seconds restart_period() const { return restart_period_; }
std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
const std::vector<std::string>& args() const { return args_; }
+ bool is_updatable() const { return updatable_; }
private:
using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
@@ -170,6 +171,7 @@
Result<Success> ParseFile(std::vector<std::string>&& args);
Result<Success> ParseUser(std::vector<std::string>&& args);
Result<Success> ParseWritepid(std::vector<std::string>&& args);
+ Result<Success> ParseUpdatable(std::vector<std::string>&& args);
template <typename T>
Result<Success> AddDescriptor(std::vector<std::string>&& args);
@@ -235,6 +237,8 @@
std::chrono::seconds restart_period_ = 5s;
std::optional<std::chrono::seconds> timeout_period_;
+ bool updatable_ = false;
+
std::vector<std::string> args_;
std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
@@ -279,8 +283,15 @@
const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
const std::vector<Service*> services_in_shutdown_order() const;
+ void MarkServicesUpdate();
+ bool IsServicesUpdated() const { return services_update_finished_; }
+ void DelayService(const Service& service);
+
private:
std::vector<std::unique_ptr<Service>> services_;
+
+ bool services_update_finished_ = false;
+ std::vector<std::string> delayed_service_names_;
};
class ServiceParser : public SectionParser {
@@ -291,6 +302,7 @@
int line) override;
Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
Result<Success> EndSection() override;
+ void EndFile() override { filename_ = ""; }
private:
bool IsValidName(const std::string& name) const;
@@ -298,6 +310,7 @@
ServiceList* service_list_;
std::vector<Subcontext>* subcontexts_;
std::unique_ptr<Service> service_;
+ std::string filename_;
};
} // namespace init
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index 31208b9..c3af341 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -16,7 +16,7 @@
#include "ueventd_parser.h"
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
diff --git a/init/ueventd_test.cpp b/init/ueventd_test.cpp
index 7290051..bfdc28e 100644
--- a/init/ueventd_test.cpp
+++ b/init/ueventd_test.cpp
@@ -27,7 +27,6 @@
#include <android-base/file.h>
#include <android-base/scopeguard.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include <selinux/android.h>
#include <selinux/label.h>
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 3ae53a4..1b5afba 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -20,8 +20,8 @@
#include <fcntl.h>
#include <sys/stat.h>
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
using namespace std::literals::string_literals;
diff --git a/libcutils/tests/android_get_control_file_test.cpp b/libcutils/tests/android_get_control_file_test.cpp
index 6c6fd2a..8de8530 100644
--- a/libcutils/tests/android_get_control_file_test.cpp
+++ b/libcutils/tests/android_get_control_file_test.cpp
@@ -23,8 +23,8 @@
#include <string>
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
#include <cutils/android_get_control_file.h>
#include <gtest/gtest.h>
diff --git a/libcutils/tests/trace-dev_test.cpp b/libcutils/tests/trace-dev_test.cpp
index f8d4f00..832b36a 100644
--- a/libcutils/tests/trace-dev_test.cpp
+++ b/libcutils/tests/trace-dev_test.cpp
@@ -22,7 +22,6 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include "../trace-dev.cpp"
diff --git a/libmeminfo/libmeminfo_benchmark.cpp b/libmeminfo/libmeminfo_benchmark.cpp
index 3820776b..e2239f0 100644
--- a/libmeminfo/libmeminfo_benchmark.cpp
+++ b/libmeminfo/libmeminfo_benchmark.cpp
@@ -24,7 +24,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/test_utils.h>
#include <benchmark/benchmark.h>
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 22f3585..7a2be41 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -30,7 +30,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
-#include <android-base/test_utils.h>
using namespace std;
using namespace android::meminfo;
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 2403ad0..a046dad 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -76,12 +76,14 @@
Range range = to_do.back();
to_do.pop_back();
+ walking_range_ = range;
ForEachPtrInRange(range, [&](Range& ref_range, AllocationInfo* ref_info) {
if (!ref_info->referenced_from_root) {
ref_info->referenced_from_root = true;
to_do.push_back(ref_range);
}
});
+ walking_range_ = Range{0, 0};
}
}
@@ -113,6 +115,10 @@
RecurseRoot(vals);
+ if (segv_page_count_ > 0) {
+ MEM_ALOGE("%zu pages skipped due to segfaults", segv_page_count_);
+ }
+
return true;
}
@@ -168,7 +174,15 @@
handler.reset();
return;
}
- MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (!segv_logged_) {
+ MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (walking_range_.begin != 0U) {
+ MEM_ALOGW("while walking range %p-%p", reinterpret_cast<void*>(walking_range_.begin),
+ reinterpret_cast<void*>(walking_range_.end));
+ }
+ segv_logged_ = true;
+ }
+ segv_page_count_++;
if (!MapOverPage(si->si_addr)) {
handler.reset();
}
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 92a8325..b37cc62 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -53,7 +53,10 @@
roots_(allocator),
root_vals_(allocator),
segv_handler_(),
- walking_ptr_(0) {
+ walking_ptr_(0),
+ walking_range_{0, 0},
+ segv_logged_(false),
+ segv_page_count_(0) {
valid_allocations_range_.end = 0;
valid_allocations_range_.begin = ~valid_allocations_range_.end;
@@ -100,7 +103,10 @@
allocator::vector<uintptr_t> root_vals_;
ScopedSignalHandler segv_handler_;
- uintptr_t walking_ptr_;
+ volatile uintptr_t walking_ptr_;
+ Range walking_range_;
+ bool segv_logged_;
+ size_t segv_page_count_;
};
template <class F>
diff --git a/libpixelflinger/Android.bp b/libpixelflinger/Android.bp
new file mode 100644
index 0000000..76d9444
--- /dev/null
+++ b/libpixelflinger/Android.bp
@@ -0,0 +1,115 @@
+cc_defaults {
+ name: "pixelflinger_defaults",
+
+ cflags: [
+ "-fstrict-aliasing",
+ "-fomit-frame-pointer",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-function",
+ ],
+ export_include_dirs: ["include"],
+ header_libs: ["libbase_headers"],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+
+ arch: {
+ arm: {
+ neon: {
+ cflags: ["-D__ARM_HAVE_NEON"],
+ },
+ },
+ },
+}
+
+cc_library_static {
+ name: "libpixelflinger-arm",
+ defaults: ["pixelflinger_defaults"],
+
+ srcs: [
+ "fixed.cpp",
+ "picker.cpp",
+ "pixelflinger.cpp",
+ "trap.cpp",
+ "scanline.cpp",
+ ],
+
+ arch: {
+ arm: {
+ instruction_set: "arm",
+ },
+ },
+}
+
+// For the tests to use
+cc_library_headers {
+ name: "libpixelflinger_internal",
+ export_include_dirs: [
+ "include",
+ ".",
+ ],
+}
+
+cc_library {
+ name: "libpixelflinger",
+ defaults: ["pixelflinger_defaults"],
+
+ srcs: [
+ "codeflinger/ARMAssemblerInterface.cpp",
+ "codeflinger/ARMAssemblerProxy.cpp",
+ "codeflinger/CodeCache.cpp",
+ "codeflinger/GGLAssembler.cpp",
+ "codeflinger/load_store.cpp",
+ "codeflinger/blending.cpp",
+ "codeflinger/texturing.cpp",
+ "format.cpp",
+ "clear.cpp",
+ "raster.cpp",
+ "buffer.cpp",
+ ],
+ whole_static_libs: ["libpixelflinger-arm"],
+
+ arch: {
+ arm: {
+ srcs: [
+ "codeflinger/ARMAssembler.cpp",
+ "codeflinger/disassem.c",
+ "col32cb16blend.S",
+ "t32cb16blend.S",
+ ],
+
+ neon: {
+ srcs: ["col32cb16blend_neon.S"],
+ },
+ },
+ arm64: {
+ srcs: [
+ "codeflinger/Arm64Assembler.cpp",
+ "codeflinger/Arm64Disassembler.cpp",
+ "arch-arm64/col32cb16blend.S",
+ "arch-arm64/t32cb16blend.S",
+ ],
+ },
+ mips: {
+ mips32r6: {
+ srcs: [
+ "codeflinger/MIPSAssembler.cpp",
+ "codeflinger/mips_disassem.c",
+ "arch-mips/t32cb16blend.S",
+ ],
+ },
+ },
+ mips64: {
+ srcs: [
+ "codeflinger/MIPSAssembler.cpp",
+ "codeflinger/MIPS64Assembler.cpp",
+ "codeflinger/mips64_disassem.c",
+ "arch-mips64/col32cb16blend.S",
+ "arch-mips64/t32cb16blend.S",
+ ],
+ },
+ },
+}
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
deleted file mode 100644
index 8c80f6a..0000000
--- a/libpixelflinger/Android.mk
+++ /dev/null
@@ -1,81 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-#
-# C/C++ and ARMv5 objects
-#
-
-include $(CLEAR_VARS)
-PIXELFLINGER_SRC_FILES:= \
- codeflinger/ARMAssemblerInterface.cpp \
- codeflinger/ARMAssemblerProxy.cpp \
- codeflinger/CodeCache.cpp \
- codeflinger/GGLAssembler.cpp \
- codeflinger/load_store.cpp \
- codeflinger/blending.cpp \
- codeflinger/texturing.cpp \
- fixed.cpp.arm \
- picker.cpp.arm \
- pixelflinger.cpp.arm \
- trap.cpp.arm \
- scanline.cpp.arm \
- format.cpp \
- clear.cpp \
- raster.cpp \
- buffer.cpp
-
-PIXELFLINGER_CFLAGS := -fstrict-aliasing -fomit-frame-pointer
-PIXELFLINGER_CFLAGS += -Wall -Werror
-PIXELFLINGER_CFLAGS += -Wno-unused-function
-
-PIXELFLINGER_SRC_FILES_arm := \
- codeflinger/ARMAssembler.cpp \
- codeflinger/disassem.c \
- col32cb16blend.S \
- t32cb16blend.S \
-
-ifeq ($(ARCH_ARM_HAVE_NEON),true)
-PIXELFLINGER_SRC_FILES_arm += col32cb16blend_neon.S
-PIXELFLINGER_CFLAGS_arm += -D__ARM_HAVE_NEON
-endif
-
-PIXELFLINGER_SRC_FILES_arm64 := \
- codeflinger/Arm64Assembler.cpp \
- codeflinger/Arm64Disassembler.cpp \
- arch-arm64/col32cb16blend.S \
- arch-arm64/t32cb16blend.S \
-
-ifndef ARCH_MIPS_REV6
-PIXELFLINGER_SRC_FILES_mips := \
- codeflinger/MIPSAssembler.cpp \
- codeflinger/mips_disassem.c \
- arch-mips/t32cb16blend.S \
-
-endif
-
-PIXELFLINGER_SRC_FILES_mips64 := \
- codeflinger/MIPSAssembler.cpp \
- codeflinger/MIPS64Assembler.cpp \
- codeflinger/mips64_disassem.c \
- arch-mips64/col32cb16blend.S \
- arch-mips64/t32cb16blend.S \
-
-#
-# Shared library
-#
-
-LOCAL_MODULE:= libpixelflinger
-LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
-LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
-LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
-LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
-LOCAL_SRC_FILES_mips64 := $(PIXELFLINGER_SRC_FILES_mips64)
-LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
-LOCAL_HEADER_LIBRARIES := libbase_headers
-LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/tests/Android.bp b/libpixelflinger/tests/Android.bp
new file mode 100644
index 0000000..820a84d
--- /dev/null
+++ b/libpixelflinger/tests/Android.bp
@@ -0,0 +1,16 @@
+cc_defaults {
+ name: "pixelflinger-tests",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ header_libs: ["libpixelflinger_internal"],
+ static_libs: [
+ "libcutils",
+ "liblog",
+ "libpixelflinger",
+ "libutils",
+ ],
+}
diff --git a/libpixelflinger/tests/Android.mk b/libpixelflinger/tests/Android.mk
deleted file mode 100644
index 6571161..0000000
--- a/libpixelflinger/tests/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(all-subdir-makefiles)
diff --git a/libpixelflinger/tests/arch-arm64/Android.bp b/libpixelflinger/tests/arch-arm64/Android.bp
new file mode 100644
index 0000000..2f5586a
--- /dev/null
+++ b/libpixelflinger/tests/arch-arm64/Android.bp
@@ -0,0 +1,11 @@
+cc_defaults {
+ name: "pixelflinger-tests-arm64",
+ defaults: ["pixelflinger-tests"],
+
+ enabled: false,
+ arch: {
+ arm64: {
+ enabled: true,
+ },
+ },
+}
diff --git a/libpixelflinger/tests/arch-arm64/Android.mk b/libpixelflinger/tests/arch-arm64/Android.mk
deleted file mode 100644
index ca58b4b..0000000
--- a/libpixelflinger/tests/arch-arm64/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-ifeq ($(TARGET_ARCH),arm64)
-include $(all-subdir-makefiles)
-endif
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.bp b/libpixelflinger/tests/arch-arm64/assembler/Android.bp
new file mode 100644
index 0000000..003f485
--- /dev/null
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.bp
@@ -0,0 +1,9 @@
+cc_test {
+ name: "test-pixelflinger-arm64-assembler-test",
+ defaults: ["pixelflinger-tests-arm64"],
+
+ srcs: [
+ "arm64_assembler_test.cpp",
+ "asm_test_jacket.S",
+ ],
+}
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
deleted file mode 100644
index db5dc4d..0000000
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- arm64_assembler_test.cpp\
- asm_test_jacket.S
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libpixelflinger
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../../..
-
-LOCAL_MODULE:= test-pixelflinger-arm64-assembler-test
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 64
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp
new file mode 100644
index 0000000..e640aeb
--- /dev/null
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "test-pixelflinger-arm64-col32cb16blend",
+ defaults: ["pixelflinger-tests-arm64"],
+
+ srcs: ["col32cb16blend_test.c"],
+}
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
deleted file mode 100644
index 3096232..0000000
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- col32cb16blend_test.c \
- ../../../arch-arm64/col32cb16blend.S
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_C_INCLUDES :=
-
-LOCAL_MODULE:= test-pixelflinger-arm64-col32cb16blend
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 64
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.bp b/libpixelflinger/tests/arch-arm64/disassembler/Android.bp
new file mode 100644
index 0000000..38dc99a
--- /dev/null
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "test-pixelflinger-arm64-disassembler-test",
+ defaults: ["pixelflinger-tests-arm64"],
+
+ srcs: ["arm64_diassembler_test.cpp"],
+}
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
deleted file mode 100644
index 78f12af..0000000
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- arm64_diassembler_test.cpp \
- ../../../codeflinger/Arm64Disassembler.cpp
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_MODULE:= test-pixelflinger-arm64-disassembler-test
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 64
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp
new file mode 100644
index 0000000..9d060d1
--- /dev/null
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "test-pixelflinger-arm64-t32cb16blend",
+ defaults: ["pixelflinger-tests-arm64"],
+
+ srcs: ["t32cb16blend_test.c"],
+}
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
deleted file mode 100644
index 664347f..0000000
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- t32cb16blend_test.c \
- ../../../arch-arm64/t32cb16blend.S
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_C_INCLUDES :=
-
-LOCAL_MODULE:= test-pixelflinger-arm64-t32cb16blend
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 64
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-mips/Android.bp b/libpixelflinger/tests/arch-mips/Android.bp
new file mode 100644
index 0000000..2ca2721
--- /dev/null
+++ b/libpixelflinger/tests/arch-mips/Android.bp
@@ -0,0 +1,11 @@
+cc_defaults {
+ name: "pixelflinger-tests-mips",
+ defaults: ["pixelflinger-tests"],
+
+ enabled: false,
+ arch: {
+ mips: {
+ enabled: true,
+ },
+ },
+}
diff --git a/libpixelflinger/tests/arch-mips/Android.mk b/libpixelflinger/tests/arch-mips/Android.mk
deleted file mode 100644
index fe6979e..0000000
--- a/libpixelflinger/tests/arch-mips/Android.mk
+++ /dev/null
@@ -1,6 +0,0 @@
-ifeq ($(TARGET_ARCH),mips)
-include $(all-subdir-makefiles)
-endif
-ifeq ($(TARGET_ARCH),mipsel)
-include $(all-subdir-makefiles)
-endif
diff --git a/libpixelflinger/tests/arch-mips/col32cb16blend/Android.bp b/libpixelflinger/tests/arch-mips/col32cb16blend/Android.bp
new file mode 100644
index 0000000..45bfe29
--- /dev/null
+++ b/libpixelflinger/tests/arch-mips/col32cb16blend/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "test-pixelflinger-mips-col32cb16blend",
+ defaults: ["pixelflinger-tests-mips"],
+
+ srcs: ["col32cb16blend_test.c"],
+}
diff --git a/libpixelflinger/tests/arch-mips/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-mips/col32cb16blend/Android.mk
deleted file mode 100644
index 40f197f..0000000
--- a/libpixelflinger/tests/arch-mips/col32cb16blend/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- col32cb16blend_test.c \
- ../../../arch-mips/col32cb16blend.S
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_C_INCLUDES :=
-
-LOCAL_MODULE:= test-pixelflinger-mips-col32cb16blend
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 32
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-mips/t32cb16blend/Android.bp b/libpixelflinger/tests/arch-mips/t32cb16blend/Android.bp
new file mode 100644
index 0000000..069e97c
--- /dev/null
+++ b/libpixelflinger/tests/arch-mips/t32cb16blend/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "test-pixelflinger-mips-t32cb16blend",
+ defaults: ["pixelflinger-tests-mips"],
+
+ srcs: ["t32cb16blend_test.c"],
+}
diff --git a/libpixelflinger/tests/arch-mips/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-mips/t32cb16blend/Android.mk
deleted file mode 100644
index d0c0ae4..0000000
--- a/libpixelflinger/tests/arch-mips/t32cb16blend/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- t32cb16blend_test.c \
- ../../../arch-mips/t32cb16blend.S
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_C_INCLUDES :=
-
-LOCAL_MODULE:= test-pixelflinger-mips-t32cb16blend
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 32
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-mips64/Android.bp b/libpixelflinger/tests/arch-mips64/Android.bp
new file mode 100644
index 0000000..ba55d62
--- /dev/null
+++ b/libpixelflinger/tests/arch-mips64/Android.bp
@@ -0,0 +1,11 @@
+cc_defaults {
+ name: "pixelflinger-tests-mips64",
+ defaults: ["pixelflinger-tests"],
+
+ enabled: false,
+ arch: {
+ mips64: {
+ enabled: true,
+ },
+ },
+}
diff --git a/libpixelflinger/tests/arch-mips64/Android.mk b/libpixelflinger/tests/arch-mips64/Android.mk
deleted file mode 100644
index 3b1c64e..0000000
--- a/libpixelflinger/tests/arch-mips64/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-ifeq ($(TARGET_ARCH),mips64)
-include $(all-subdir-makefiles)
-endif
diff --git a/libpixelflinger/tests/arch-mips64/assembler/Android.bp b/libpixelflinger/tests/arch-mips64/assembler/Android.bp
new file mode 100644
index 0000000..b672053
--- /dev/null
+++ b/libpixelflinger/tests/arch-mips64/assembler/Android.bp
@@ -0,0 +1,9 @@
+cc_test {
+ name: "test-pixelflinger-mips64-assembler-test",
+ defaults: ["pixelflinger-tests-mips64"],
+
+ srcs: [
+ "mips64_assembler_test.cpp",
+ "asm_mips_test_jacket.S",
+ ],
+}
diff --git a/libpixelflinger/tests/arch-mips64/assembler/Android.mk b/libpixelflinger/tests/arch-mips64/assembler/Android.mk
deleted file mode 100644
index 4699961..0000000
--- a/libpixelflinger/tests/arch-mips64/assembler/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- mips64_assembler_test.cpp\
- asm_mips_test_jacket.S
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libpixelflinger
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../../..
-
-LOCAL_MODULE:= test-pixelflinger-mips64-assembler-test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 64
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.bp b/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.bp
new file mode 100644
index 0000000..bfc6ae9
--- /dev/null
+++ b/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "test-pixelflinger-mips64-col32cb16blend",
+ defaults: ["pixelflinger-tests-mips64"],
+
+ srcs: ["col32cb16blend_test.c"],
+}
diff --git a/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.mk
deleted file mode 100644
index 7d4177e..0000000
--- a/libpixelflinger/tests/arch-mips64/col32cb16blend/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- col32cb16blend_test.c \
- ../../../arch-mips64/col32cb16blend.S
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_C_INCLUDES :=
-
-LOCAL_MODULE:= test-pixelflinger-mips64-col32cb16blend
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 64
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-mips64/disassembler/Android.bp b/libpixelflinger/tests/arch-mips64/disassembler/Android.bp
new file mode 100644
index 0000000..96bf9e9
--- /dev/null
+++ b/libpixelflinger/tests/arch-mips64/disassembler/Android.bp
@@ -0,0 +1,6 @@
+cc_test {
+ name: "test-pixelflinger-mips64-disassembler-test",
+ defaults: ["pixelflinger-tests-mips64"],
+
+ srcs: ["mips64_disassembler_test.cpp"],
+}
diff --git a/libpixelflinger/tests/arch-mips64/disassembler/Android.mk b/libpixelflinger/tests/arch-mips64/disassembler/Android.mk
deleted file mode 100644
index 4e72b57..0000000
--- a/libpixelflinger/tests/arch-mips64/disassembler/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- mips64_disassembler_test.cpp \
- ../../../codeflinger/mips64_disassem.c
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_MODULE:= test-pixelflinger-mips64-disassembler-test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MULTILIB := 64
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/Android.bp b/libpixelflinger/tests/codegen/Android.bp
new file mode 100644
index 0000000..7e4bcfb
--- /dev/null
+++ b/libpixelflinger/tests/codegen/Android.bp
@@ -0,0 +1,12 @@
+cc_test {
+ name: "test-opengl-codegen",
+ defaults: ["pixelflinger-tests"],
+
+ srcs: ["codegen.cpp"],
+
+ arch: {
+ arm: {
+ instruction_set: "arm",
+ },
+ },
+}
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
deleted file mode 100644
index 72d71ef..0000000
--- a/libpixelflinger/tests/codegen/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- codegen.cpp.arm
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libpixelflinger
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../..
-
-LOCAL_MODULE:= test-opengl-codegen
-
-LOCAL_CFLAGS:= -Wall -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/gglmul/Android.bp b/libpixelflinger/tests/gglmul/Android.bp
new file mode 100644
index 0000000..288337b
--- /dev/null
+++ b/libpixelflinger/tests/gglmul/Android.bp
@@ -0,0 +1,12 @@
+cc_test {
+ name: "test-pixelflinger-gglmul",
+
+ srcs: ["gglmul_test.cpp"],
+
+ header_libs: ["libpixelflinger_internal"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
deleted file mode 100644
index 67f358f..0000000
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- gglmul_test.cpp
-
-LOCAL_SHARED_LIBRARIES :=
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../../include
-
-LOCAL_MODULE:= test-pixelflinger-gglmul
-
-LOCAL_CFLAGS:= -Wall -Werror
-
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 14f82c7..a5e0dc9 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -184,6 +184,7 @@
"tests/MapInfoGetLoadBiasTest.cpp",
"tests/MapsTest.cpp",
"tests/MemoryBufferTest.cpp",
+ "tests/MemoryCacheTest.cpp",
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
@@ -310,6 +311,28 @@
],
}
+//-------------------------------------------------------------------------
+// Benchmarks
+//-------------------------------------------------------------------------
+cc_benchmark {
+ name: "unwind_benchmarks",
+ host_supported: true,
+ defaults: ["libunwindstack_flags"],
+
+ // Disable optimizations so that all of the calls are not optimized away.
+ cflags: [
+ "-O0",
+ ],
+
+ srcs: [
+ "benchmarks/unwind_benchmarks.cpp",
+ ],
+
+ shared_libs: [
+ "libunwindstack",
+ ],
+}
+
// Generates the elf data for use in the tests for .gnu_debugdata frames.
// Once these files are generated, use the xz command to compress the data.
cc_binary_host {
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index fe32b5e..e3b48ca 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -96,11 +96,6 @@
}
}
- // If the map isn't readable, don't bother trying to read from process memory.
- if (!(flags & PROT_READ)) {
- return nullptr;
- }
-
// Need to verify that this elf is valid. It's possible that
// only part of the elf file to be mapped into memory is in the executable
// map. In this case, there will be another read-only map that includes the
@@ -132,18 +127,19 @@
}
}
- if (ro_map_info != nullptr) {
- // Make sure that relative pc values are corrected properly.
- elf_offset = offset - closest_offset;
-
- MemoryRanges* ranges = new MemoryRanges;
- ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
- ro_map_info->end - ro_map_info->start, 0));
- ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
-
- return ranges;
+ if (ro_map_info == nullptr) {
+ return nullptr;
}
- return nullptr;
+
+ // Make sure that relative pc values are corrected properly.
+ elf_offset = offset - closest_offset;
+
+ MemoryRanges* ranges = new MemoryRanges;
+ ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
+ ro_map_info->end - ro_map_info->start, 0));
+ ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
+
+ return ranges;
}
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index cfa8c6d..a30d65e 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -174,6 +174,13 @@
return std::shared_ptr<Memory>(new MemoryRemote(pid));
}
+std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
+ if (pid == getpid()) {
+ return std::shared_ptr<Memory>(new MemoryCache(new MemoryLocal()));
+ }
+ return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
+}
+
size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
if (addr >= raw_.size()) {
return 0;
@@ -398,4 +405,50 @@
return 0;
}
+size_t MemoryCache::Read(uint64_t addr, void* dst, size_t size) {
+ // Only bother caching and looking at the cache if this is a small read for now.
+ if (size > 64) {
+ return impl_->Read(addr, dst, size);
+ }
+
+ uint64_t addr_page = addr >> kCacheBits;
+ auto entry = cache_.find(addr_page);
+ uint8_t* cache_dst;
+ if (entry != cache_.end()) {
+ cache_dst = entry->second;
+ } else {
+ cache_dst = cache_[addr_page];
+ if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+ // Erase the entry.
+ cache_.erase(addr_page);
+ return impl_->Read(addr, dst, size);
+ }
+ }
+ size_t max_read = ((addr_page + 1) << kCacheBits) - addr;
+ if (size <= max_read) {
+ memcpy(dst, &cache_dst[addr & kCacheMask], size);
+ return size;
+ }
+
+ // The read crossed into another cached entry, since a read can only cross
+ // into one extra cached page, duplicate the code rather than looping.
+ memcpy(dst, &cache_dst[addr & kCacheMask], max_read);
+ dst = &reinterpret_cast<uint8_t*>(dst)[max_read];
+ addr_page++;
+
+ entry = cache_.find(addr_page);
+ if (entry != cache_.end()) {
+ cache_dst = entry->second;
+ } else {
+ cache_dst = cache_[addr_page];
+ if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+ // Erase the entry.
+ cache_.erase(addr_page);
+ return impl_->Read(addr_page << kCacheBits, dst, size - max_read) + max_read;
+ }
+ }
+ memcpy(dst, cache_dst, size - max_read);
+ return size;
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
new file mode 100644
index 0000000..db0fb54
--- /dev/null
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 <stdint.h>
+
+#include <memory>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
+
+size_t Call6(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+ unwindstack::RegsGetLocal(regs.get());
+ unwindstack::Unwinder unwinder(32, maps, regs.get(), process_memory);
+ unwinder.Unwind();
+ return unwinder.NumFrames();
+}
+
+size_t Call5(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call6(process_memory, maps);
+}
+
+size_t Call4(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call5(process_memory, maps);
+}
+
+size_t Call3(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call4(process_memory, maps);
+}
+
+size_t Call2(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call3(process_memory, maps);
+}
+
+size_t Call1(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call2(process_memory, maps);
+}
+
+static void BM_uncached_unwind(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
+ unwindstack::LocalMaps maps;
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ }
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(Call1(process_memory, &maps));
+ }
+}
+BENCHMARK(BM_uncached_unwind);
+
+static void BM_cached_unwind(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ unwindstack::LocalMaps maps;
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ }
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(Call1(process_memory, &maps));
+ }
+}
+BENCHMARK(BM_cached_unwind);
+
+BENCHMARK_MAIN();
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 9c425cb..dba41d1 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -25,6 +25,7 @@
#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
namespace unwindstack {
@@ -35,9 +36,12 @@
virtual ~Memory() = default;
static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
+ static std::shared_ptr<Memory> CreateProcessMemoryCached(pid_t pid);
virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
+ virtual void Clear() {}
+
virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
bool ReadFully(uint64_t addr, void* dst, size_t size);
@@ -51,6 +55,24 @@
}
};
+class MemoryCache : public Memory {
+ public:
+ MemoryCache(Memory* memory) : impl_(memory) {}
+ virtual ~MemoryCache() = default;
+
+ size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ void Clear() override { cache_.clear(); }
+
+ private:
+ constexpr static size_t kCacheBits = 12;
+ constexpr static size_t kCacheMask = (1 << kCacheBits) - 1;
+ constexpr static size_t kCacheSize = 1 << kCacheBits;
+ std::unordered_map<uint64_t, uint8_t[kCacheSize]> cache_;
+
+ std::unique_ptr<Memory> impl_;
+};
+
class MemoryBuffer : public Memory {
public:
MemoryBuffer() = default;
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 40f9f8e..95d2176 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -20,7 +20,7 @@
#include <unordered_map>
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
index d9acdec..07fd6f6 100644
--- a/libunwindstack/tests/ElfCacheTest.cpp
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -18,7 +18,6 @@
#include <unistd.h>
#include <android-base/file.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2a73c7e..0987bc1 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -27,7 +27,6 @@
#include <vector>
#include <android-base/file.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include <unwindstack/Elf.h>
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 4d74696..99f8fa3 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -29,7 +29,6 @@
#include <vector>
#include <android-base/file.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include <unwindstack/Elf.h>
@@ -291,27 +290,6 @@
ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
}
-TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
- MapInfo info(nullptr, 0x9000, 0xa000, 0x1000, 0, "");
-
- // Create valid elf data in process memory only.
- Elf64_Ehdr ehdr;
- TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
- ehdr.e_shoff = 0x2000;
- ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 0;
- memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_FALSE(elf->valid());
-
- info.elf.reset();
- info.flags = PROT_READ;
- elf = info.GetElf(process_memory_, ARCH_ARM64);
- ASSERT_TRUE(elf->valid());
-}
-
TEST_F(MapInfoGetElfTest, check_device_maps) {
MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP,
"/dev/something");
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 6bdd0b2..80e292a 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -19,7 +19,6 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include <unwindstack/Maps.h>
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
new file mode 100644
index 0000000..a3def20
--- /dev/null
+++ b/libunwindstack/tests/MemoryCacheTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 <stdint.h>
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Memory.h>
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class MemoryCacheTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ memory_ = new MemoryFake;
+ memory_cache_.reset(new MemoryCache(memory_));
+
+ memory_->SetMemoryBlock(0x8000, 4096, 0xab);
+ memory_->SetMemoryBlock(0x9000, 4096, 0xde);
+ memory_->SetMemoryBlock(0xa000, 3000, 0x50);
+ }
+
+ MemoryFake* memory_;
+ std::unique_ptr<MemoryCache> memory_cache_;
+
+ constexpr static size_t kMaxCachedSize = 64;
+};
+
+TEST_F(MemoryCacheTest, cached_read) {
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, no_cached_read_after_clear) {
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is not used after a reset.
+ memory_cache_->Clear();
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, cached_read_across_caches) {
+ std::vector<uint8_t> expect(16, 0xab);
+ expect.resize(32, 0xde);
+
+ std::vector<uint8_t> buffer(32);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+
+ // Verify the cached data is used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ memory_->SetMemoryBlock(0x9000, 4096, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+}
+
+TEST_F(MemoryCacheTest, no_cache_read) {
+ for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is not used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail) {
+ std::vector<uint8_t> buffer(kMaxCachedSize);
+ ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+ ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0x50), buffer);
+
+ // Verify the cached data is not used.
+ memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+ ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0xff), buffer);
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail_cross) {
+ std::vector<uint8_t> expect(16, 0xde);
+ expect.resize(32, 0x50);
+
+ std::vector<uint8_t> buffer(32);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+
+ // Verify the cached data is not used for the second half but for the first.
+ memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+ expect.resize(16);
+ expect.resize(32, 0xff);
+ ASSERT_EQ(expect, buffer);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryOfflineTest.cpp b/libunwindstack/tests/MemoryOfflineTest.cpp
index 14d58e6..ab9aa9d 100644
--- a/libunwindstack/tests/MemoryOfflineTest.cpp
+++ b/libunwindstack/tests/MemoryOfflineTest.cpp
@@ -19,7 +19,6 @@
#include <gtest/gtest.h>
#include <android-base/file.h>
-#include <android-base/test_utils.h>
#include <unwindstack/Memory.h>
namespace unwindstack {
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 2095189..9538bba 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -125,6 +125,7 @@
enabled: true,
},
},
+ test_suites: ["device-tests"],
}
// Performance benchmarks.
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 0ea7d5d..cea42d4 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -28,7 +28,6 @@
#include <android-base/file.h>
#include <android-base/mapped_file.h>
-#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_archive.h>
@@ -298,7 +297,7 @@
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
+ ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));
ZipEntry entry;
ZipString empty_name;
@@ -323,7 +322,7 @@
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
sizeof(kAbZip) - 1));
ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
+ ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle, false));
ZipEntry entry;
ZipString ab_name;
@@ -370,7 +369,7 @@
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
ZipArchiveHandle handle;
- ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
+ ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));
}
TEST(ziparchive, ExtractToFile) {
@@ -580,7 +579,7 @@
ASSERT_NE(-1, tmp_file.fd);
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &zip_data[0], zip_data.size()));
ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle));
+ ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "ExtractEntryToMemory", &handle, false));
// This function expects a variant of kDataDescriptorZipFile, for look for
// an entry whose name is "name" and whose size is 12 (contents =
@@ -688,7 +687,7 @@
ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0],
kZipFileWithBrokenLfhSignature.size()));
ZipArchiveHandle handle;
- ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle));
+ ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle, false));
}
class VectorReader : public zip_archive::Reader {
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 0827470..427dace 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -555,7 +555,9 @@
}
void llkAlarmHandler(int) {
- llkPanicKernel(false, ::getpid(), "alarm");
+ LOG(FATAL) << "alarm";
+ // NOTREACHED
+ llkPanicKernel(true, ::getpid(), "alarm");
}
milliseconds GetUintProperty(const std::string& key, milliseconds def) {
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 9483bb2..d5c40be 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -1404,7 +1404,7 @@
int count = 0;
char buffer[BIG_BUFFER];
-#define logcat_regex_prefix ___STRING(logcat) "_test"
+#define logcat_regex_prefix logcat_executable "_test"
snprintf(buffer, sizeof(buffer),
logcat_executable " --pid %d -d -e " logcat_regex_prefix "_a+b",
@@ -1550,7 +1550,7 @@
{
static const struct tag sync = { 2720, "sync" };
- static const char id[] = ___STRING(logcat) ".descriptive-sync";
+ static const char id[] = logcat_executable ".descriptive-sync";
{
android_log_event_list ctx(sync.tagNo);
ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
@@ -1665,7 +1665,7 @@
// Invent new entries because existing can not serve
EventTagMap* map = android_openEventTagMap(nullptr);
ASSERT_TRUE(nullptr != map);
- static const char name[] = ___STRING(logcat) ".descriptive-monotonic";
+ static const char name[] = logcat_executable ".descriptive-monotonic";
int myTag = android_lookupEventTagNum(map, name, "(new|1|s)",
ANDROID_LOG_UNKNOWN);
android_closeEventTagMap(map);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index fc8c960..18d5287 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -165,9 +165,14 @@
bug_num->assign("");
}
+ // Ensure the uid name is not null before passing it to the bug string.
if (uid >= AID_APP_START && uid <= AID_APP_END) {
- bug_num->append(" app=");
- bug_num->append(android::uidToName(uid));
+ char* uidname = android::uidToName(uid);
+ if (uidname) {
+ bug_num->append(" app=");
+ bug_num->append(uidname);
+ free(uidname);
+ }
}
}
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1715501..208d67f 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -204,6 +204,10 @@
goto skip;
}
+ if (me->mRelease) {
+ goto stop;
+ }
+
if (!me->mTail) {
goto ok;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 636daea..349168e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -269,6 +269,12 @@
# that they can be chown'd to system:system later on boot
write /sys/class/leds/vibrator/trigger "transient"
+ # This is used by Bionic to select optimized routines.
+ write /dev/cpu_variant:${ro.bionic.arch} ${ro.bionic.cpu_variant}
+ chmod 0444 /dev/cpu_variant:${ro.bionic.arch}
+ write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant}
+ chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch}
+
# Setup APEX mount point and its security context
mount tmpfs tmpfs /apex nodev noexec nosuid
chmod 0755 /apex
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 2f85dec..d47506c 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -72,7 +72,7 @@
/dev/diag_arm9 0660 radio radio
/dev/ttyMSM0 0600 bluetooth bluetooth
/dev/uhid 0660 uhid uhid
-/dev/uinput 0660 system bluetooth
+/dev/uinput 0660 uhid uhid
/dev/alarm 0664 system radio
/dev/rtc0 0640 system system
/dev/tty0 0660 root system
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 8c0b3d1..ca2421b 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -87,12 +87,21 @@
day_start_tp += chrono::seconds(perf_history.day_start_sec());
nr_samples = perf_history.nr_samples();
+ if (nr_samples < recent_perf.size()) {
+ recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end());
+ }
+ size_t i = 0;
for (auto bw : perf_history.recent_perf()) {
- recent_perf.push_back(bw);
+ if (i < recent_perf.size()) {
+ recent_perf[i] = bw;
+ } else {
+ recent_perf.push_back(bw);
+ }
+ ++i;
}
nr_days = perf_history.nr_days();
- int i = 0;
+ i = 0;
for (auto bw : perf_history.daily_perf()) {
daily_perf[i++] = bw;
}