Merge "Multi-threaded Keystore"
diff --git a/adb/adb.h b/adb/adb.h
index 8c37c4b..e2911e8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -59,7 +59,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 41
+#define ADB_SERVER_VERSION 40
using TransportId = uint64_t;
class atransport;
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/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/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 49baf36..e380c84 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -136,8 +136,8 @@
io_service_t usbDevice;
io_service_t usbInterface;
IOCFPlugInInterface **plugInInterface = NULL;
- IOUSBInterfaceInterface220 **iface = NULL;
- IOUSBDeviceInterface197 **dev = NULL;
+ IOUSBInterfaceInterface500 **iface = NULL;
+ IOUSBDeviceInterface500 **dev = NULL;
HRESULT result;
SInt32 score;
uint32_t locationId;
@@ -163,7 +163,7 @@
//* This gets us the interface object
result = (*plugInInterface)->QueryInterface(
plugInInterface,
- CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
+ CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID500), (LPVOID*)&iface);
//* We only needed the plugin to get the interface, so discard it
(*plugInInterface)->Release(plugInInterface);
if (result || !iface) {
@@ -209,7 +209,7 @@
}
result = (*plugInInterface)->QueryInterface(plugInInterface,
- CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
+ CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500), (LPVOID*)&dev);
//* only needed this to query the plugin
(*plugInInterface)->Release(plugInInterface);
if (result || !dev) {
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.cpp b/adb/transport.cpp
index 03a9f30..c2d4917 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1013,9 +1013,10 @@
#if ADB_HOST
kFeatureApex
#endif
- // Increment ADB_SERVER_VERSION whenever the feature list changes to
- // make sure that the adb client and server features stay in sync
- // (http://b/24370690).
+ // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
+ // to know about. Otherwise, the client can be stuck running an old
+ // version of the server even after upgrading their copy of adb.
+ // (http://b/24370690)
};
return *features;
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/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/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 625e047..3e090d7 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -56,7 +56,6 @@
#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 <platform_tools_version.h>
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_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7c6093e..31affbe 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)) {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 49ecc06..a1de005 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <sys/vfs.h>
#include <unistd.h>
@@ -56,13 +57,17 @@
using namespace android::dm;
using namespace android::fs_mgr;
-static bool fs_mgr_access(const std::string& path) {
+namespace {
+
+bool fs_mgr_access(const std::string& path) {
auto save_errno = errno;
auto ret = access(path.c_str(), F_OK) == 0;
errno = save_errno;
return ret;
}
+} // namespace
+
#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
bool fs_mgr_overlayfs_mount_all(fstab*) {
@@ -218,9 +223,12 @@
std::string fs_mgr_get_overlayfs_options(const std::string& mount_point) {
auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
if (candidate.empty()) return "";
-
- return "override_creds=off," + kLowerdirOption + mount_point + "," + kUpperdirOption +
- candidate + kUpperName + ",workdir=" + candidate + kWorkName;
+ auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName +
+ ",workdir=" + candidate + kWorkName;
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
+ ret += ",override_creds=off";
+ }
+ return ret;
}
const char* fs_mgr_mount_point(const char* mount_point) {
@@ -733,7 +741,7 @@
bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
auto ret = false;
- if (!fs_mgr_overlayfs_supports_override_creds()) return ret;
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
if (!fstab) return ret;
@@ -791,7 +799,7 @@
bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
if (change) *change = false;
auto ret = false;
- if (!fs_mgr_overlayfs_supports_override_creds()) return ret;
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
if (!fs_mgr_boot_completed()) {
errno = EBUSY;
PERROR << "setup";
@@ -854,7 +862,7 @@
for (const auto& overlay_mount_point : kOverlayMountPoints) {
ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
}
- if (!fs_mgr_overlayfs_supports_override_creds()) {
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
// After obligatory teardown to make sure everything is clean, but if
// we didn't want overlayfs in the the first place, we do not want to
// waste time on a reboot (or reboot request message).
@@ -905,7 +913,30 @@
return context;
}
-bool fs_mgr_overlayfs_supports_override_creds() {
+OverlayfsValidResult fs_mgr_overlayfs_valid() {
// Overlayfs available in the kernel, and patched for override_creds?
- return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
+ if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) {
+ return OverlayfsValidResult::kOverrideCredsRequired;
+ }
+ if (!fs_mgr_access("/sys/module/overlay")) {
+ return OverlayfsValidResult::kNotSupported;
+ }
+ struct utsname uts;
+ if (uname(&uts) == -1) {
+ return OverlayfsValidResult::kNotSupported;
+ }
+ int major, minor;
+ if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+ return OverlayfsValidResult::kNotSupported;
+ }
+ if (major < 4) {
+ return OverlayfsValidResult::kOk;
+ }
+ if (major > 4) {
+ return OverlayfsValidResult::kNotSupported;
+ }
+ if (minor > 6) {
+ return OverlayfsValidResult::kNotSupported;
+ }
+ return OverlayfsValidResult::kOk;
}
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index a9a69cd..e1815ff 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -87,8 +87,10 @@
return false;
}
- auto options =
- "override_creds=off,"s + kLowerdirOption + source_directory + ":" + vendor_mount_point;
+ auto options = kLowerdirOption + source_directory + ":" + vendor_mount_point;
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
+ options += ",override_creds=off";
+ }
auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," +
options + ")=";
auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
@@ -117,7 +119,7 @@
}
const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(overlay_top);
if (vendor_overlay_dirs.empty()) return true;
- if (!fs_mgr_overlayfs_supports_override_creds()) {
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
LINFO << "vendor overlay: kernel does not support overlayfs";
return false;
}
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 72202ab..deaf4cb 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -31,4 +31,10 @@
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
std::string fs_mgr_get_context(const std::string& mount_point);
-bool fs_mgr_overlayfs_supports_override_creds();
+
+enum class OverlayfsValidResult {
+ kNotSupported = 0,
+ kOk,
+ kOverrideCredsRequired,
+};
+OverlayfsValidResult fs_mgr_overlayfs_valid();
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 4007ad9..b6d6da1 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -113,18 +113,7 @@
if (!metadata) {
return nullptr;
}
- std::unique_ptr<MetadataBuilder> builder = New(*metadata.get());
- if (!builder) {
- return nullptr;
- }
- for (size_t i = 0; i < builder->block_devices_.size(); i++) {
- std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
- BlockDeviceInfo device_info;
- if (opener.GetInfo(partition_name, &device_info)) {
- builder->UpdateBlockDeviceInfo(i, device_info);
- }
- }
- return builder;
+ return New(*metadata.get(), &opener);
}
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
@@ -142,15 +131,70 @@
return builder;
}
-std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata) {
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata,
+ const IPartitionOpener* opener) {
std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
if (!builder->Init(metadata)) {
return nullptr;
}
+ if (opener) {
+ for (size_t i = 0; i < builder->block_devices_.size(); i++) {
+ std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
+ BlockDeviceInfo device_info;
+ if (opener->GetInfo(partition_name, &device_info)) {
+ builder->UpdateBlockDeviceInfo(i, device_info);
+ }
+ }
+ }
return builder;
}
-MetadataBuilder::MetadataBuilder() {
+std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener,
+ const std::string& source_partition,
+ uint32_t source_slot_number,
+ uint32_t target_slot_number) {
+ auto metadata = ReadMetadata(opener, source_partition, source_slot_number);
+ if (!metadata) {
+ 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));
+ }
+
+ auto new_block_devices = metadata->block_devices;
+
+ // 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);
+ std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
+ if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
+ continue;
+ }
+ 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;
+ 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 = new_block_devices;
+ return New(*metadata.get(), &opener);
+}
+
+MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
memset(&geometry_, 0, sizeof(geometry_));
geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
geometry_.struct_size = sizeof(geometry_);
@@ -492,8 +536,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;
}
}
@@ -564,7 +608,12 @@
metadata->geometry = geometry_;
// Assign this early so the extent table can read it.
- metadata->block_devices = block_devices_;
+ for (const auto& block_device : block_devices_) {
+ metadata->block_devices.emplace_back(block_device);
+ if (auto_slot_suffixing_) {
+ metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+ }
+ }
std::map<std::string, size_t> group_indices;
for (const auto& group : groups_) {
@@ -600,6 +649,9 @@
part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
part.num_extents = static_cast<uint32_t>(partition->extents().size());
part.attributes = partition->attributes();
+ if (auto_slot_suffixing_) {
+ part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED;
+ }
auto iter = group_indices.find(partition->group_name());
if (iter == group_indices.end()) {
@@ -836,5 +888,9 @@
return true;
}
+void MetadataBuilder::SetAutoSlotSuffixing() {
+ auto_slot_suffixing_ = true;
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 46bdfa4..9e64de1 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -62,7 +62,7 @@
}
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
- android::base::unique_fd fd(open(file, O_RDONLY));
+ android::base::unique_fd fd(open(file, O_RDONLY | O_CLOEXEC));
if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
return nullptr;
@@ -84,7 +84,7 @@
}
bool WriteToImageFile(const char* file, const LpMetadata& input) {
- android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+ android::base::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;
@@ -97,7 +97,6 @@
: metadata_(metadata),
geometry_(metadata.geometry),
block_size_(block_size),
- file_(nullptr, sparse_file_destroy),
images_(images) {
uint64_t total_size = GetTotalSuperPartitionSize(metadata);
if (block_size % LP_SECTOR_SIZE != 0) {
@@ -121,7 +120,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.
@@ -129,20 +128,32 @@
return;
}
- file_.reset(sparse_file_new(block_size_, total_size));
- if (!file_) {
- LERROR << "Could not allocate sparse file of size " << total_size;
+ for (const auto& block_device : metadata.block_devices) {
+ SparsePtr file(sparse_file_new(block_size_, block_device.size), sparse_file_destroy);
+ if (!file) {
+ LERROR << "Could not allocate sparse file of size " << block_device.size;
+ return;
+ }
+ device_images_.emplace_back(std::move(file));
}
}
+bool SparseBuilder::IsValid() const {
+ return device_images_.size() == metadata_.block_devices.size();
+}
+
bool SparseBuilder::Export(const char* file) {
- android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+ android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
if (fd < 0) {
PERROR << "open failed: " << file;
return false;
}
+ if (device_images_.size() > 1) {
+ LERROR << "Cannot export to a single image on retrofit builds.";
+ return false;
+ }
// No gzip compression; sparseify; no checksum.
- int ret = sparse_file_write(file_.get(), fd, false, true, false);
+ int ret = sparse_file_write(device_images_[0].get(), fd, false, true, false);
if (ret != 0) {
LERROR << "sparse_file_write failed (error code " << ret << ")";
return false;
@@ -150,13 +161,39 @@
return true;
}
-bool SparseBuilder::AddData(const std::string& blob, uint64_t sector) {
+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));
+ if (fd < 0) {
+ PERROR << "open failed: " << path;
+ return false;
+ }
+ // No gzip compression; sparseify; no checksum.
+ int ret = sparse_file_write(device_images_[i].get(), fd, false, true, false);
+ if (ret != 0) {
+ LERROR << "sparse_file_write failed (error code " << ret << ")";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SparseBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
uint32_t block;
if (!SectorToBlock(sector, &block)) {
return false;
}
void* data = const_cast<char*>(blob.data());
- int ret = sparse_file_add_data(file_.get(), data, blob.size(), block);
+ int ret = sparse_file_add_data(file, data, blob.size(), block);
if (ret != 0) {
LERROR << "sparse_file_add_data failed (error code " << ret << ")";
return false;
@@ -179,8 +216,12 @@
return true;
}
+uint64_t SparseBuilder::BlockToSector(uint64_t block) const {
+ return (block * block_size_) / LP_SECTOR_SIZE;
+}
+
bool SparseBuilder::Build() {
- if (sparse_file_add_fill(file_.get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
+ if (sparse_file_add_fill(device_images_[0].get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
LERROR << "Could not add initial sparse block for reserved zeroes";
return false;
}
@@ -194,7 +235,13 @@
for (size_t i = 0; i < geometry_.metadata_slot_count * 2; i++) {
all_metadata_ += metadata_blob;
}
- if (!AddData(all_metadata_, 0)) {
+
+ uint64_t first_sector = LP_PARTITION_RESERVED_BYTES / LP_SECTOR_SIZE;
+ if (!AddData(device_images_[0].get(), all_metadata_, first_sector)) {
+ return false;
+ }
+
+ if (!CheckExtentOrdering()) {
return false;
}
@@ -228,13 +275,10 @@
bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
const std::string& file) {
- if (partition.num_extents != 1) {
- LERROR << "Partition for new tables should not have more than one extent: "
- << GetPartitionName(partition);
- return false;
- }
+ // Track which extent we're processing.
+ uint32_t extent_index = partition.first_extent_index;
- const LpMetadataExtent& extent = metadata_.extents[partition.first_extent_index];
+ const LpMetadataExtent& extent = metadata_.extents[extent_index];
if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
LERROR << "Partition should only have linear extents: " << GetPartitionName(partition);
return false;
@@ -252,9 +296,11 @@
LERROR << "Could not compute image size";
return false;
}
- if (file_length > extent.num_sectors * LP_SECTOR_SIZE) {
+ uint64_t partition_size = ComputePartitionSize(partition);
+ if (file_length > partition_size) {
LERROR << "Image for partition '" << GetPartitionName(partition)
- << "' is greater than its size";
+ << "' is greater than its size (" << file_length << ", expected " << partition_size
+ << ")";
return false;
}
if (SeekFile64(fd, 0, SEEK_SET)) {
@@ -262,14 +308,39 @@
return false;
}
+ // We track the current logical sector and the position the current extent
+ // ends at.
+ uint64_t output_sector = 0;
+ uint64_t extent_last_sector = extent.num_sectors;
+
+ // We also track the output device and the current output block within that
+ // device.
uint32_t output_block;
if (!SectorToBlock(extent.target_data, &output_block)) {
return false;
}
+ sparse_file* output_device = device_images_[extent.target_source].get();
+ // Proceed to read the file and build sparse images.
uint64_t pos = 0;
uint64_t remaining = file_length;
while (remaining) {
+ // Check if we need to advance to the next extent.
+ if (output_sector == extent_last_sector) {
+ extent_index++;
+ if (extent_index >= partition.first_extent_index + partition.num_extents) {
+ LERROR << "image is larger than extent table";
+ return false;
+ }
+
+ const LpMetadataExtent& extent = metadata_.extents[extent_index];
+ extent_last_sector += extent.num_sectors;
+ output_device = device_images_[extent.target_source].get();
+ if (!SectorToBlock(extent.target_data, &output_block)) {
+ return false;
+ }
+ }
+
uint32_t buffer[block_size_ / sizeof(uint32_t)];
size_t read_size = remaining >= sizeof(buffer) ? sizeof(buffer) : size_t(remaining);
if (!android::base::ReadFully(fd, buffer, sizeof(buffer))) {
@@ -277,13 +348,13 @@
return false;
}
if (read_size != sizeof(buffer) || !HasFillValue(buffer, read_size / sizeof(uint32_t))) {
- int rv = sparse_file_add_fd(file_.get(), fd, pos, read_size, output_block);
+ int rv = sparse_file_add_fd(output_device, fd, pos, read_size, output_block);
if (rv) {
LERROR << "sparse_file_add_fd failed with code: " << rv;
return false;
}
} else {
- int rv = sparse_file_add_fill(file_.get(), buffer[0], read_size, output_block);
+ int rv = sparse_file_add_fill(output_device, buffer[0], read_size, output_block);
if (rv) {
LERROR << "sparse_file_add_fill failed with code: " << rv;
return false;
@@ -291,46 +362,76 @@
}
pos += read_size;
remaining -= read_size;
+ output_sector += block_size_ / LP_SECTOR_SIZE;
output_block++;
}
return true;
}
+uint64_t SparseBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
+ uint64_t sectors = 0;
+ for (size_t i = 0; i < partition.num_extents; i++) {
+ sectors += metadata_.extents[partition.first_extent_index + i].num_sectors;
+ }
+ return sectors * LP_SECTOR_SIZE;
+}
+
+// For simplicity, we don't allow serializing any configuration: extents must
+// be ordered, such that any extent at position I in the table occurs *before*
+// any extent after position I, for the same block device. We validate that
+// here.
+//
+// Without this, it would be more difficult to find the appropriate extent for
+// an output block. With this guarantee it is a linear walk.
+bool SparseBuilder::CheckExtentOrdering() {
+ std::vector<uint64_t> last_sectors(metadata_.block_devices.size());
+
+ for (const auto& extent : metadata_.extents) {
+ if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
+ LERROR << "Extents must all be type linear.";
+ return false;
+ }
+ if (extent.target_data <= last_sectors[extent.target_source]) {
+ LERROR << "Extents must appear in increasing order.";
+ return false;
+ }
+ if ((extent.num_sectors * LP_SECTOR_SIZE) % block_size_ != 0) {
+ LERROR << "Extents must be aligned to the block size.";
+ return false;
+ }
+ last_sectors[extent.target_source] = extent.target_data;
+ }
+ return true;
+}
+
int SparseBuilder::OpenImageFile(const std::string& file) {
- android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY));
+ android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
if (source_fd < 0) {
PERROR << "open image file failed: " << file;
return -1;
}
- std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> source(
- sparse_file_import(source_fd, true, true), sparse_file_destroy);
+ SparsePtr source(sparse_file_import(source_fd, true, true), sparse_file_destroy);
if (!source) {
int fd = source_fd.get();
temp_fds_.push_back(std::move(source_fd));
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();
}
@@ -340,5 +441,11 @@
return builder.IsValid() && builder.Build() && builder.Export(file);
}
+bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
+ uint32_t block_size, const std::map<std::string, std::string>& images) {
+ SparseBuilder builder(metadata, block_size, images);
+ return builder.IsValid() && builder.Build() && builder.ExportFiles(output_dir);
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
index a9ef8ce..44217a0 100644
--- a/fs_mgr/liblp/images.h
+++ b/fs_mgr/liblp/images.h
@@ -42,20 +42,26 @@
bool Build();
bool Export(const char* file);
- bool IsValid() const { return file_ != nullptr; }
+ bool ExportFiles(const std::string& dir);
+ bool IsValid() const;
- sparse_file* file() const { return file_.get(); }
+ using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
+ const std::vector<SparsePtr>& device_images() const { return device_images_; }
private:
- bool AddData(const std::string& blob, uint64_t sector);
+ bool AddData(sparse_file* file, const std::string& blob, uint64_t sector);
bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
int OpenImageFile(const std::string& file);
bool SectorToBlock(uint64_t sector, uint32_t* block);
+ uint64_t BlockToSector(uint64_t block) const;
+ bool CheckExtentOrdering();
+ uint64_t ComputePartitionSize(const LpMetadataPartition& partition) const;
const LpMetadata& metadata_;
const LpMetadataGeometry& geometry_;
uint32_t block_size_;
- std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
+
+ std::vector<SparsePtr> device_images_;
std::string all_metadata_;
std::map<std::string, std::string> images_;
std::vector<android::base::unique_fd> temp_fds_;
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index d5e3fed..59717d1 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -150,10 +150,24 @@
static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition,
uint32_t slot_number);
+ // This is when performing an A/B update. The source partition must be a
+ // super partition. On a normal device, the metadata for the source slot
+ // is imported and the target slot is ignored. On a retrofit device, the
+ // metadata may not have the target slot's devices listed yet, in which
+ // case, it is automatically upgraded to include all available block
+ // devices.
+ static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
+ const std::string& source_partition,
+ uint32_t source_slot_number,
+ uint32_t target_slot_number);
+
// Import an existing table for modification. If the table is not valid, for
// example it contains duplicate partition names, then nullptr is returned.
- // This method is for testing or changing off-line tables.
- static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
+ //
+ // If an IPartitionOpener is specified, then block device informatiom will
+ // be updated.
+ static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata,
+ const IPartitionOpener* opener = nullptr);
// Helper function for a single super partition, for tests.
static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
@@ -223,6 +237,9 @@
// Remove all partitions belonging to a group, then remove the group.
void RemoveGroupAndPartitions(const std::string& group_name);
+ // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag.
+ void SetAutoSlotSuffixing();
+
bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);
@@ -275,6 +292,7 @@
std::vector<std::unique_ptr<Partition>> partitions_;
std::vector<std::unique_ptr<PartitionGroup>> groups_;
std::vector<LpMetadataBlockDevice> block_devices_;
+ bool auto_slot_suffixing_;
};
// Read BlockDeviceInfo for a given block device. This always returns false
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 8723a7f..1af1e80 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -78,6 +78,14 @@
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
+// Similar to WriteToSparseFile, this will generate an image that can be
+// flashed to a device directly. However unlike WriteToSparseFile, it
+// is intended for retrofit devices, and will generate one sparse file per
+// block device (each named super_<name>.img) and placed in the specified
+// output folder.
+bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
+ uint32_t block_size, const std::map<std::string, std::string>& images);
+
// Helper to extract safe C++ strings from partition info.
std::string GetPartitionName(const LpMetadataPartition& partition);
std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group);
@@ -95,6 +103,7 @@
// Slot suffix helpers.
uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+std::string SlotSuffixForSlotNumber(uint32_t slot_number);
std::string GetPartitionSlotSuffix(const std::string& partition_name);
} // namespace fs_mgr
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 1e40df3..c2e25fb 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 8
+#define LP_METADATA_MAJOR_VERSION 9
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -47,10 +47,19 @@
* device mapper, the block device will be created as read-only.
*/
#define LP_PARTITION_ATTR_NONE 0x0
-#define LP_PARTITION_ATTR_READONLY 0x1
+#define LP_PARTITION_ATTR_READONLY (1 << 0)
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the partition name needs a slot suffix applied. The slot suffix is
+ * determined by the metadata slot number (0 = _a, 1 = _b).
+ */
+#define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
/* Mask that defines all valid attributes. */
-#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY)
+#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
/* Default name of the physical partition that holds logical partition entries.
* The layout of this partition will look like:
@@ -302,8 +311,21 @@
/* 24: Partition name in the GPT. Any unused characters must be 0. */
char partition_name[36];
+
+ /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
+ uint32_t flags;
} LpMetadataBlockDevice;
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the block device needs a slot suffix applied before being used with
+ * IPartitionOpener. The slot suffix is determined by the metadata slot number
+ * (0 = _a, 1 = _b).
+ */
+#define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 603e5c0..9acf23e 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -38,6 +38,7 @@
static const size_t kDiskSize = 131072;
static const size_t kMetadataSize = 512;
static const size_t kMetadataSlots = 2;
+static const BlockDeviceInfo kSuperInfo{"super", kDiskSize, 0, 0, 4096};
// Helper function for creating an in-memory file descriptor. This lets us
// simulate read/writing logical partition metadata as if we had a block device
@@ -79,6 +80,12 @@
return builder;
}
+class DefaultPartitionOpener final : public TestPartitionOpener {
+ public:
+ explicit DefaultPartitionOpener(int fd)
+ : TestPartitionOpener({{"super", fd}}, {{"super", kSuperInfo}}) {}
+};
+
static bool AddDefaultPartitions(MetadataBuilder* builder) {
Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_NONE);
if (!system) {
@@ -103,7 +110,7 @@
return {};
}
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
if (!FlashPartitionTable(opener, "super", *exported.get())) {
return {};
}
@@ -119,7 +126,7 @@
ASSERT_TRUE(GetDescriptorSize(fd, &size));
ASSERT_EQ(size, kDiskSize);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
// Verify that we can't read unwritten metadata.
ASSERT_EQ(ReadMetadata(opener, "super", 1), nullptr);
@@ -138,7 +145,7 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
EXPECT_FALSE(FlashPartitionTable(opener, "super", *exported.get()));
}
@@ -152,7 +159,7 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
// Export and flash.
unique_ptr<LpMetadata> exported = builder->Export();
@@ -198,7 +205,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
@@ -243,7 +250,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
// Make sure all slots are filled.
unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
@@ -262,7 +269,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
ASSERT_NE(imported, nullptr);
@@ -291,7 +298,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
LpMetadataGeometry geometry;
ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
@@ -310,7 +317,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
char corruption[LP_METADATA_GEOMETRY_SIZE];
memset(corruption, 0xff, sizeof(corruption));
@@ -330,7 +337,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
@@ -378,7 +385,7 @@
unique_fd fd = CreateFakeDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
// Check that we are able to write our table.
ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
@@ -487,7 +494,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
BadWriter writer;
@@ -515,7 +522,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
BadWriter writer;
@@ -544,7 +551,7 @@
unique_fd fd = CreateFlashedDisk();
ASSERT_GE(fd, 0);
- TestPartitionOpener opener({{"super", fd}});
+ DefaultPartitionOpener opener(fd);
BadWriter writer;
@@ -593,12 +600,14 @@
// Build the sparse file.
SparseBuilder sparse(*exported.get(), 512, {});
ASSERT_TRUE(sparse.IsValid());
- sparse_file_verbose(sparse.file());
ASSERT_TRUE(sparse.Build());
+ const auto& images = sparse.device_images();
+ ASSERT_EQ(images.size(), static_cast<size_t>(1));
+
// Write it to the fake disk.
ASSERT_NE(lseek(fd.get(), 0, SEEK_SET), -1);
- int ret = sparse_file_write(sparse.file(), fd.get(), false, false, false);
+ int ret = sparse_file_write(images[0].get(), fd.get(), false, false, false);
ASSERT_EQ(ret, 0);
// Verify that we can read both sets of metadata.
@@ -608,3 +617,74 @@
ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
}
+
+TEST(liblp, AutoSlotSuffixing) {
+ unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
+ ASSERT_NE(builder, nullptr);
+ ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+ builder->SetAutoSlotSuffixing();
+
+ auto fd = CreateFakeDisk();
+ ASSERT_GE(fd, 0);
+
+ // Note: we bind the same fd to both names, since we want to make sure the
+ // exact same bits are getting read back in each test.
+ TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
+ {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
+ auto exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+ ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));
+
+ auto metadata = ReadMetadata(opener, "super_b", 1);
+ ASSERT_NE(metadata, nullptr);
+ ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+ 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");
+
+ metadata = ReadMetadata(opener, "super_a", 0);
+ ASSERT_NE(metadata, nullptr);
+ ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+ 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");
+}
+
+TEST(liblp, UpdateRetrofit) {
+ unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
+ ASSERT_NE(builder, nullptr);
+ ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+ builder->SetAutoSlotSuffixing();
+
+ auto fd = CreateFakeDisk();
+ ASSERT_GE(fd, 0);
+
+ // Note: we bind the same fd to both names, since we want to make sure the
+ // exact same bits are getting read back in each test.
+ TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
+ {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
+ auto exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+ ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));
+
+ builder = MetadataBuilder::NewForUpdate(opener, "super_a", 0, 1);
+ 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");
+}
+
+TEST(liblp, UpdateNonRetrofit) {
+ unique_fd fd = CreateFlashedDisk();
+ ASSERT_GE(fd, 0);
+
+ DefaultPartitionOpener opener(fd);
+ auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
+ ASSERT_NE(builder, nullptr);
+ auto updated = builder->Export();
+ ASSERT_NE(updated, nullptr);
+ ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
+ EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super");
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index a02e746..b36ba0e 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -348,6 +348,38 @@
return ParseMetadata(geometry, fd);
}
+namespace {
+
+bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) {
+ std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+ for (auto& partition : metadata->partitions) {
+ if (!(partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED)) {
+ continue;
+ }
+ std::string partition_name = GetPartitionName(partition) + slot_suffix;
+ if (partition_name.size() > sizeof(partition.name)) {
+ LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+ return false;
+ }
+ strncpy(partition.name, partition_name.c_str(), sizeof(partition.name));
+ partition.attributes &= ~LP_PARTITION_ATTR_SLOT_SUFFIXED;
+ }
+ for (auto& block_device : metadata->block_devices) {
+ if (!(block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED)) {
+ continue;
+ }
+ std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix;
+ if (!UpdateBlockDevicePartitionName(&block_device, partition_name)) {
+ LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+ return false;
+ }
+ block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+ }
+ return true;
+}
+
+} // namespace
+
std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
const std::string& super_partition, uint32_t slot_number) {
android::base::unique_fd fd = opener.Open(super_partition, O_RDONLY);
@@ -360,18 +392,30 @@
if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
return nullptr;
}
-
if (slot_number >= geometry.metadata_slot_count) {
LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number";
return nullptr;
}
- // Read the primary copy, and if that fails, try the backup.
- std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
- if (metadata) {
- return metadata;
+ std::vector<int64_t> offsets = {
+ GetPrimaryMetadataOffset(geometry, slot_number),
+ GetBackupMetadataOffset(geometry, slot_number),
+ };
+ std::unique_ptr<LpMetadata> metadata;
+
+ for (const auto& offset : offsets) {
+ if (SeekFile64(fd, offset, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed, offset " << offset;
+ continue;
+ }
+ if ((metadata = ParseMetadata(geometry, fd)) != nullptr) {
+ break;
+ }
}
- return ReadBackupMetadata(fd, geometry, slot_number);
+ if (!metadata || !AdjustMetadataForSlot(metadata.get(), slot_number)) {
+ return nullptr;
+ }
+ return metadata;
}
std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number) {
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index d5d5188..7a2490b 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -38,7 +38,9 @@
bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry);
bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry);
-// These functions assume a valid geometry and slot number.
+// These functions assume a valid geometry and slot number, and do not obey
+// auto-slot-suffixing. They are used for tests and for checking whether
+// the metadata is coherent across primary and backup copies.
std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
uint32_t slot_number);
std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index cce90a3..4f20b6b 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -132,5 +132,18 @@
return (suffix == "_a" || suffix == "_b") ? suffix : "";
}
+std::string SlotSuffixForSlotNumber(uint32_t slot_number) {
+ CHECK(slot_number == 0 || slot_number == 1);
+ return (slot_number == 0) ? "_a" : "_b";
+}
+
+bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name) {
+ if (name.size() > sizeof(device->partition_name)) {
+ return false;
+ }
+ strncpy(device->partition_name, name.c_str(), sizeof(device->partition_name));
+ return true;
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 65e643b..55ecb5a 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -84,6 +84,9 @@
return aligned;
}
+// Update names from C++ strings.
+bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 0fa4590..15f7fff 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -32,6 +32,11 @@
EXPECT_EQ(SlotNumberForSlotSuffix("_d"), 0);
}
+TEST(liblp, SlotSuffixForSlotNumber) {
+ EXPECT_EQ(SlotSuffixForSlotNumber(0), "_a");
+ EXPECT_EQ(SlotSuffixForSlotNumber(1), "_b");
+}
+
TEST(liblp, GetMetadataOffset) {
LpMetadataGeometry geometry = {LP_METADATA_GEOMETRY_MAGIC,
sizeof(geometry),
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index f4c9b99..e72cdfa 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -83,7 +83,7 @@
// Perform sanity checks so we don't accidentally overwrite valid metadata
// with potentially invalid metadata, or random partition data with metadata.
static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
- std::string* blob) {
+ const std::string& slot_suffix, std::string* blob) {
const LpMetadataHeader& header = metadata.header;
const LpMetadataGeometry& geometry = metadata.geometry;
@@ -114,6 +114,15 @@
}
for (const auto& block_device : metadata.block_devices) {
std::string partition_name = GetBlockDevicePartitionName(block_device);
+ if (block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) {
+ if (slot_suffix.empty()) {
+ LERROR << "Block device " << partition_name << " requires a slot suffix,"
+ << " which could not be derived from the super partition name.";
+ return false;
+ }
+ partition_name += slot_suffix;
+ }
+
if ((block_device.first_logical_sector + 1) * LP_SECTOR_SIZE > block_device.size) {
LERROR << "Block device " << partition_name << " has invalid first sector "
<< block_device.first_logical_sector << " for size " << block_device.size;
@@ -234,11 +243,16 @@
return false;
}
+ // This is only used in update_engine and fastbootd, where the super
+ // partition should be specified as a name (or by-name link), and
+ // therefore, we should be able to extract a slot suffix.
+ std::string slot_suffix = GetPartitionSlotSuffix(super_partition);
+
// Before writing geometry and/or logical partition tables, perform some
// basic checks that the geometry and tables are coherent, and will fit
// on the given block device.
std::string metadata_blob;
- if (!ValidateAndSerializeMetadata(opener, metadata, &metadata_blob)) {
+ if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &metadata_blob)) {
return false;
}
@@ -299,11 +313,13 @@
return false;
}
+ std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+
// Before writing geometry and/or logical partition tables, perform some
// basic checks that the geometry and tables are coherent, and will fit
// on the given block device.
std::string blob;
- if (!ValidateAndSerializeMetadata(opener, metadata, &blob)) {
+ if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &blob)) {
return false;
}
@@ -335,7 +351,7 @@
// synchronize the backup copy. This guarantees that a partial write
// still leaves one copy intact.
std::string old_blob;
- if (!ValidateAndSerializeMetadata(opener, *primary.get(), &old_blob)) {
+ if (!ValidateAndSerializeMetadata(opener, *primary.get(), slot_suffix, &old_blob)) {
LERROR << "Error serializing primary metadata to repair corrupted backup";
return false;
}
@@ -347,7 +363,7 @@
// The backup copy is coherent, and the primary is not. Sync it for
// safety.
std::string old_blob;
- if (!ValidateAndSerializeMetadata(opener, *backup.get(), &old_blob)) {
+ if (!ValidateAndSerializeMetadata(opener, *backup.get(), slot_suffix, &old_blob)) {
LERROR << "Error serializing primary metadata to repair corrupted backup";
return false;
}
diff --git a/init/README.md b/init/README.md
index 2c531df..5c07ac1 100644
--- a/init/README.md
+++ b/init/README.md
@@ -275,6 +275,10 @@
since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
this file has more details on the order.
+`parse_apex_configs`
+ Parses config file(s) from the mounted APEXes. Intented to be used only once
+ when apexd notifies the mount event by setting apexd.status to ready.
+
`priority <priority>`
> Scheduling priority of the service process. This value has to be in range
-20 to 19. Default priority is 0. Priority is set via setpriority().
@@ -328,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 5d62c0b..5676f92 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
+#include <glob.h>
#include <linux/loop.h>
#include <linux/module.h>
#include <mntent.h>
@@ -1053,6 +1054,39 @@
{{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
}
+static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
+ glob_t glob_result;
+ // @ is added to filter out the later paths, which are bind mounts of the places
+ // 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) {
+ globfree(&glob_result);
+ return Error() << "glob pattern '" << glob_pattern << "' failed";
+ }
+ std::vector<std::string> configs;
+ Parser parser = CreateServiceOnlyParser(ServiceList::GetInstance());
+ for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+ configs.emplace_back(glob_result.gl_pathv[i]);
+ }
+ globfree(&glob_result);
+
+ bool success = true;
+ for (const auto& c : configs) {
+ if (c.back() == '/') {
+ // skip if directory
+ continue;
+ }
+ success &= parser.ParseConfigFile(c);
+ }
+ ServiceList::GetInstance().MarkServicesUpdate();
+ if (success) {
+ return Success();
+ } else {
+ return Error() << "Could not parse apex configs";
+ }
+}
+
// Builtin-function-map start
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1090,6 +1124,7 @@
// mount and umount are run in the same context as mount_all for symmetry.
{"mount_all", {1, kMax, {false, do_mount_all}}},
{"mount", {3, kMax, {false, do_mount}}},
+ {"parse_apex_configs", {0, 0, {false, do_parse_apex_configs}}},
{"umount", {1, 1, {false, do_umount}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"restart", {1, 1, {false, do_restart}}},
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 13a9d08..1e434d2 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -17,6 +17,7 @@
#include "first_stage_mount.h"
#include <stdlib.h>
+#include <sys/mount.h>
#include <unistd.h>
#include <chrono>
@@ -123,18 +124,8 @@
return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
}
-static bool ForceNormalBoot() {
- static bool force_normal_boot = []() {
- std::string cmdline;
- android::base::ReadFileToString("/proc/cmdline", &cmdline);
- return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
- }();
-
- return force_normal_boot;
-}
-
static bool IsRecoveryMode() {
- return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0;
+ return access("/system/bin/recovery", F_OK) == 0;
}
// Class Definitions
@@ -403,11 +394,6 @@
[](const auto& rec) { return rec->mount_point == "/system"s; });
if (system_partition != mount_fstab_recs_.end()) {
- if (ForceNormalBoot()) {
- free((*system_partition)->mount_point);
- (*system_partition)->mount_point = strdup("/system_recovery_mount");
- }
-
if (!MountPartition(*system_partition)) {
return false;
}
@@ -574,7 +560,7 @@
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) {
+ if (!inserted && (links[0] != it->second)) {
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.";
diff --git a/init/init.cpp b/init/init.cpp
index 90803f7..e7dbc11 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -132,6 +132,14 @@
return parser;
}
+// parser that only accepts new services
+Parser CreateServiceOnlyParser(ServiceList& service_list) {
+ Parser parser;
+
+ parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
+ return parser;
+}
+
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
diff --git a/init/init.h b/init/init.h
index f244ad7..65405aa 100644
--- a/init/init.h
+++ b/init/init.h
@@ -38,6 +38,7 @@
extern std::vector<std::string> late_import_paths;
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
+Parser CreateServiceOnlyParser(ServiceList& service_list);
void HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index d81ca5c..c2c6868 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <dirent.h>
+#include <fcntl.h>
#include <paths.h>
#include <stdlib.h>
#include <sys/mount.h>
@@ -26,19 +28,72 @@
#include <vector>
#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <cutils/android_reboot.h>
#include <private/android_filesystem_config.h>
#include "first_stage_mount.h"
#include "reboot_utils.h"
+#include "switch_root.h"
#include "util.h"
using android::base::boot_clock;
+using namespace std::literals;
+
namespace android {
namespace init {
+namespace {
+
+void FreeRamdisk(DIR* dir, dev_t dev) {
+ int dfd = dirfd(dir);
+
+ dirent* de;
+ while ((de = readdir(dir)) != nullptr) {
+ if (de->d_name == "."s || de->d_name == ".."s) {
+ continue;
+ }
+
+ bool is_dir = false;
+
+ if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
+ struct stat info;
+ if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
+ continue;
+ }
+
+ if (info.st_dev != dev) {
+ continue;
+ }
+
+ if (S_ISDIR(info.st_mode)) {
+ is_dir = true;
+ auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
+ if (fd >= 0) {
+ auto subdir =
+ std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
+ if (subdir) {
+ FreeRamdisk(subdir.get(), dev);
+ } else {
+ close(fd);
+ }
+ }
+ }
+ }
+ unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
+ }
+}
+
+bool ForceNormalBoot() {
+ std::string cmdline;
+ android::base::ReadFileToString("/proc/cmdline", &cmdline);
+ return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
+}
+
+} // namespace
+
int main(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
@@ -117,10 +172,41 @@
LOG(INFO) << "init first stage started!";
+ auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
+ if (!old_root_dir) {
+ PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
+ }
+
+ struct stat old_root_info;
+ if (stat("/", &old_root_info) != 0) {
+ PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
+ old_root_dir.reset();
+ }
+
+ if (ForceNormalBoot()) {
+ mkdir("/first_stage_ramdisk", 0755);
+ // SwitchRoot() must be called with a mount point as the target, so we bind mount the
+ // target directory to itself here.
+ if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
+ LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
+ }
+ SwitchRoot("/first_stage_ramdisk");
+ }
+
if (!DoFirstStageMount()) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
+ struct stat new_root_info;
+ if (stat("/", &new_root_info) != 0) {
+ PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
+ old_root_dir.reset();
+ }
+
+ if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
+ FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
+ }
+
SetInitAvbVersionInRecovery();
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
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/parser.h b/init/parser.h
index 2454b6a..f30bda7 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -72,6 +72,7 @@
Parser();
bool ParseConfig(const std::string& path);
+ bool ParseConfigFile(const std::string& path);
void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
void AddSingleLineParser(const std::string& prefix, LineCallback callback);
@@ -82,7 +83,6 @@
private:
void ParseData(const std::string& filename, std::string* data);
- bool ParseConfigFile(const std::string& path);
bool ParseConfigDir(const std::string& path);
std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
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/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/switch_root.cpp b/init/switch_root.cpp
index 0e59b57..575b67f 100644
--- a/init/switch_root.cpp
+++ b/init/switch_root.cpp
@@ -16,7 +16,6 @@
#include "switch_root.h"
-#include <dirent.h>
#include <fcntl.h>
#include <mntent.h>
#include <sys/mount.h>
@@ -35,45 +34,6 @@
namespace {
-void FreeRamdisk(DIR* dir, dev_t dev) {
- int dfd = dirfd(dir);
-
- dirent* de;
- while ((de = readdir(dir)) != nullptr) {
- if (de->d_name == "."s || de->d_name == ".."s) {
- continue;
- }
-
- bool is_dir = false;
-
- if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
- struct stat info;
- if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
- continue;
- }
-
- if (info.st_dev != dev) {
- continue;
- }
-
- if (S_ISDIR(info.st_mode)) {
- is_dir = true;
- auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
- if (fd >= 0) {
- auto subdir =
- std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
- if (subdir) {
- FreeRamdisk(subdir.get(), dev);
- } else {
- close(fd);
- }
- }
- }
- }
- unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
- }
-}
-
std::vector<std::string> GetMounts(const std::string& new_root) {
auto fp = std::unique_ptr<std::FILE, decltype(&endmntent)>{setmntent("/proc/mounts", "re"),
endmntent};
@@ -112,24 +72,16 @@
void SwitchRoot(const std::string& new_root) {
auto mounts = GetMounts(new_root);
+ LOG(INFO) << "Switching root to '" << new_root << "'";
+
for (const auto& mount_path : mounts) {
auto new_mount_path = new_root + mount_path;
+ mkdir(new_mount_path.c_str(), 0755);
if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
}
}
- auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
- if (!old_root_dir) {
- PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
- }
-
- struct stat old_root_info;
- if (stat("/", &old_root_info) != 0) {
- PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
- old_root_dir.reset();
- }
-
if (chdir(new_root.c_str()) != 0) {
PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
}
@@ -141,10 +93,6 @@
if (chroot(".") != 0) {
PLOG(FATAL) << "Unable to chroot to new root";
}
-
- if (old_root_dir) {
- FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
- }
}
} // 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/fs_config.cpp b/libcutils/fs_config.cpp
index bd5f26f..ee52f5e 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -60,7 +60,7 @@
// way up to the root.
static const struct fs_path_config android_dirs[] = {
- // clang-format off
+ // clang-format off
{ 00770, AID_SYSTEM, AID_CACHE, 0, "cache" },
{ 00555, AID_ROOT, AID_ROOT, 0, "config" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
@@ -80,17 +80,18 @@
{ 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
{ 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" },
- { 00755, AID_ROOT, AID_SHELL, 0, "product/bin" },
+ { 00751, AID_ROOT, AID_SHELL, 0, "product/bin" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin" },
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" },
- { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" },
+ { 00751, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
- { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" },
+ { 00751, AID_ROOT, AID_SHELL, 0, "system/xbin" },
+ { 00751, AID_ROOT, AID_SHELL, 0, "vendor/bin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
{ 00755, AID_ROOT, AID_ROOT, 0, 0 },
- // clang-format on
+ // clang-format on
};
#ifndef __ANDROID_VNDK__
auto __for_testing_only__android_dirs = android_dirs;
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/Android.bp b/libmemunreachable/Android.bp
index 248a9d2..b78a4c4 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -46,12 +46,6 @@
static_libs: ["libunwind_llvm"],
},
},
-
- // TODO(b/78118944), clang lld link flags do not work with special link
- // rules for libunwind_llvm yet. Linked aosp_arm-eng image failed to
- // boot up in the emulator.
- use_clang_lld: false,
-
export_include_dirs: ["include"],
local_include_dirs: ["include"],
}
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..f3b4679 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>
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/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/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 0ea7d5d..500a531 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>
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 025e3c3..636daea 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -801,3 +801,6 @@
service flash_recovery /system/bin/install-recovery.sh
class main
oneshot
+
+on property:apexd.status=ready
+ parse_apex_configs
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index 971b9f4..f49bdf7 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -25,6 +25,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include <string>
+
#include <libminijail.h>
#include <scoped_minijail.h>
@@ -214,7 +216,8 @@
minijail_keep_supplementary_gids(j.get());
minijail_enter(j.get());
- if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
+ std::string seinfo = std::string(info.seinfo) + ":fromRunAs";
+ if (selinux_android_setcontext(uid, 0, seinfo.c_str(), pkgname) < 0) {
error(1, errno, "couldn't set SELinux security context");
}