Merge "libsnapshot: Don't compare strings for snapshot state."
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index faad03d..66cba12 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -16,6 +16,7 @@
#pragma once
+#include <charconv>
#include <condition_variable>
#include <mutex>
#include <string>
@@ -112,33 +113,17 @@
// Base-10 stroll on a string_view.
template <typename T>
inline bool ParseUint(T* result, std::string_view str, std::string_view* remaining = nullptr) {
- if (str.empty() || !isdigit(str[0])) {
+ T value;
+ const auto res = std::from_chars(str.begin(), str.end(), value);
+ if (res.ec != std::errc{}) {
return false;
}
-
- T value = 0;
- std::string_view::iterator it;
- constexpr T max = std::numeric_limits<T>::max();
- for (it = str.begin(); it != str.end() && isdigit(*it); ++it) {
- if (value > max / 10) {
- return false;
- }
-
- value *= 10;
-
- T digit = *it - '0';
- if (value > max - digit) {
- return false;
- }
-
- value += digit;
+ if (res.ptr != str.end() && !remaining) {
+ return false;
+ }
+ if (remaining) {
+ *remaining = std::string_view(res.ptr, str.end() - res.ptr);
}
*result = value;
- if (remaining) {
- *remaining = str.substr(it - str.begin());
- } else {
- return it == str.end();
- }
-
return true;
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 599e0e6..fe2bdfe 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1704,10 +1704,23 @@
error_exit("tcpip: invalid port: %s", argv[1]);
}
return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
+ } else if (!strcmp(argv[0], "remount")) {
+ FeatureSet features;
+ std::string error;
+ if (!adb_get_feature_set(&features, &error)) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+
+ if (CanUseFeature(features, kFeatureRemountShell)) {
+ const char* arg[2] = {"shell", "remount"};
+ return adb_shell(2, arg);
+ } else {
+ return adb_connect_command("remount:");
+ }
}
// clang-format off
- else if (!strcmp(argv[0], "remount") ||
- !strcmp(argv[0], "reboot") ||
+ else if (!strcmp(argv[0], "reboot") ||
!strcmp(argv[0], "reboot-bootloader") ||
!strcmp(argv[0], "reboot-fastboot") ||
!strcmp(argv[0], "usb") ||
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index ce494ee..6bd7855 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -48,6 +48,8 @@
dup2(fd, STDERR_FILENO);
execl(kRemountCmd, kRemountCmd, cmd.empty() ? nullptr : cmd.c_str(), nullptr);
+ const char* msg = "failed to exec remount\n";
+ write(STDERR_FILENO, msg, strlen(msg));
_exit(errno);
}
@@ -83,6 +85,6 @@
}
void remount_service(unique_fd fd, const std::string& cmd) {
- const char* success = do_remount(fd.get(), cmd) ? "succeeded" : "failed";
- WriteFdFmt(fd.get(), "remount %s\n", success);
+ do_remount(fd.get(), cmd);
+ // The remount command will print success or failure for us.
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index b0e7fa0..b08a13b 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -91,11 +91,14 @@
extern int adb_open(const char* path, int options);
extern int adb_creat(const char* path, int mode);
extern int adb_read(borrowed_fd fd, void* buf, int len);
+extern int adb_pread(borrowed_fd fd, void* buf, int len, off64_t offset);
extern int adb_write(borrowed_fd fd, const void* buf, int len);
+extern int adb_pwrite(borrowed_fd fd, const void* buf, int len, off64_t offset);
extern int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where);
extern int adb_shutdown(borrowed_fd fd, int direction = SHUT_RDWR);
extern int adb_close(int fd);
extern int adb_register_socket(SOCKET s);
+extern HANDLE adb_get_os_handle(borrowed_fd fd);
// See the comments for the !defined(_WIN32) version of unix_close().
static __inline__ int unix_close(int fd) {
@@ -115,6 +118,9 @@
#undef read
#define read ___xxx_read
+#undef pread
+#define pread ___xxx_pread
+
// See the comments for the !defined(_WIN32) version of unix_write().
static __inline__ int unix_write(borrowed_fd fd, const void* buf, size_t len) {
return write(fd.get(), buf, len);
@@ -122,6 +128,9 @@
#undef write
#define write ___xxx_write
+#undef pwrite
+#define pwrite ___xxx_pwrite
+
// See the comments for the !defined(_WIN32) version of unix_lseek().
static __inline__ int unix_lseek(borrowed_fd fd, int pos, int where) {
return lseek(fd.get(), pos, where);
@@ -415,6 +424,14 @@
return TEMP_FAILURE_RETRY(read(fd.get(), buf, len));
}
+static __inline__ int adb_pread(int fd, void* buf, size_t len, off64_t offset) {
+#if defined(__APPLE__)
+ return TEMP_FAILURE_RETRY(pread(fd, buf, len, offset));
+#else
+ return TEMP_FAILURE_RETRY(pread64(fd, buf, len, offset));
+#endif
+}
+
// Like unix_read(), but does not handle EINTR.
static __inline__ int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len) {
return read(fd.get(), buf, len);
@@ -422,12 +439,25 @@
#undef read
#define read ___xxx_read
+#undef pread
+#define pread ___xxx_pread
static __inline__ int adb_write(borrowed_fd fd, const void* buf, size_t len) {
return TEMP_FAILURE_RETRY(write(fd.get(), buf, len));
}
+
+static __inline__ int adb_pwrite(int fd, const void* buf, size_t len, off64_t offset) {
+#if defined(__APPLE__)
+ return TEMP_FAILURE_RETRY(pwrite(fd, buf, len, offset));
+#else
+ return TEMP_FAILURE_RETRY(pwrite64(fd, buf, len, offset));
+#endif
+}
+
#undef write
#define write ___xxx_write
+#undef pwrite
+#define pwrite ___xxx_pwrite
static __inline__ int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where) {
#if defined(__APPLE__)
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index dc2525c..4d6cf3d 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -60,6 +60,7 @@
int (*_fh_read)(FH, void*, int);
int (*_fh_write)(FH, const void*, int);
int (*_fh_writev)(FH, const adb_iovec*, int);
+ intptr_t (*_fh_get_os_handle)(FH);
} FHClassRec;
static void _fh_file_init(FH);
@@ -68,14 +69,11 @@
static int _fh_file_read(FH, void*, int);
static int _fh_file_write(FH, const void*, int);
static int _fh_file_writev(FH, const adb_iovec*, int);
+static intptr_t _fh_file_get_os_handle(FH f);
static const FHClassRec _fh_file_class = {
- _fh_file_init,
- _fh_file_close,
- _fh_file_lseek,
- _fh_file_read,
- _fh_file_write,
- _fh_file_writev,
+ _fh_file_init, _fh_file_close, _fh_file_lseek, _fh_file_read,
+ _fh_file_write, _fh_file_writev, _fh_file_get_os_handle,
};
static void _fh_socket_init(FH);
@@ -84,14 +82,11 @@
static int _fh_socket_read(FH, void*, int);
static int _fh_socket_write(FH, const void*, int);
static int _fh_socket_writev(FH, const adb_iovec*, int);
+static intptr_t _fh_socket_get_os_handle(FH f);
static const FHClassRec _fh_socket_class = {
- _fh_socket_init,
- _fh_socket_close,
- _fh_socket_lseek,
- _fh_socket_read,
- _fh_socket_write,
- _fh_socket_writev,
+ _fh_socket_init, _fh_socket_close, _fh_socket_lseek, _fh_socket_read,
+ _fh_socket_write, _fh_socket_writev, _fh_socket_get_os_handle,
};
#if defined(assert)
@@ -331,6 +326,10 @@
return li.QuadPart;
}
+static intptr_t _fh_file_get_os_handle(FH f) {
+ return reinterpret_cast<intptr_t>(f->u.handle);
+}
+
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -456,6 +455,26 @@
return f->clazz->_fh_read(f, buf, len);
}
+int adb_pread(borrowed_fd fd, void* buf, int len, off64_t offset) {
+ OVERLAPPED overlapped = {};
+ overlapped.Offset = static_cast<DWORD>(offset);
+ overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+ DWORD bytes_read;
+ if (!::ReadFile(adb_get_os_handle(fd), buf, static_cast<DWORD>(len), &bytes_read,
+ &overlapped)) {
+ D("adb_pread: could not read %d bytes from FD %d", len, fd.get());
+ switch (::GetLastError()) {
+ case ERROR_IO_PENDING:
+ errno = EAGAIN;
+ return -1;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ return static_cast<int>(bytes_read);
+}
+
int adb_write(borrowed_fd fd, const void* buf, int len) {
FH f = _fh_from_int(fd, __func__);
@@ -478,6 +497,25 @@
return f->clazz->_fh_writev(f, iov, iovcnt);
}
+int adb_pwrite(borrowed_fd fd, const void* buf, int len, off64_t offset) {
+ OVERLAPPED params = {};
+ params.Offset = static_cast<DWORD>(offset);
+ params.OffsetHigh = static_cast<DWORD>(offset >> 32);
+ DWORD bytes_written = 0;
+ if (!::WriteFile(adb_get_os_handle(fd), buf, len, &bytes_written, ¶ms)) {
+ D("adb_pwrite: could not write %d bytes to FD %d", len, fd.get());
+ switch (::GetLastError()) {
+ case ERROR_IO_PENDING:
+ errno = EAGAIN;
+ return -1;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ return static_cast<int>(bytes_written);
+}
+
int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where) {
FH f = _fh_from_int(fd, __func__);
if (!f) {
@@ -500,6 +538,20 @@
return 0;
}
+HANDLE adb_get_os_handle(borrowed_fd fd) {
+ FH f = _fh_from_int(fd, __func__);
+
+ if (!f) {
+ errno = EBADF;
+ return nullptr;
+ }
+
+ D("adb_get_os_handle: %s", f->name);
+ const intptr_t intptr_handle = f->clazz->_fh_get_os_handle(f);
+ const HANDLE handle = reinterpret_cast<const HANDLE>(intptr_handle);
+ return handle;
+}
+
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -694,6 +746,10 @@
return static_cast<int>(bytes_written);
}
+static intptr_t _fh_socket_get_os_handle(FH f) {
+ return f->u.socket;
+}
+
/**************************************************************************/
/**************************************************************************/
/***** *****/
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 3d1d620..d9749ac 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -73,6 +73,7 @@
const char* const kFeatureAbb = "abb";
const char* const kFeatureFixedPushSymlinkTimestamp = "fixed_push_symlink_timestamp";
const char* const kFeatureAbbExec = "abb_exec";
+const char* const kFeatureRemountShell = "remount_shell";
namespace {
@@ -1049,6 +1050,7 @@
kFeatureAbb,
kFeatureFixedPushSymlinkTimestamp,
kFeatureAbbExec,
+ kFeatureRemountShell,
// 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.
diff --git a/adb/transport.h b/adb/transport.h
index f4490ed..245037e 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -69,6 +69,7 @@
extern const char* const kFeatureAbb;
// adbd properly updates symlink timestamps on push.
extern const char* const kFeatureFixedPushSymlinkTimestamp;
+extern const char* const kFeatureRemountShell;
TransportId NextTransportId();
diff --git a/base/include/android-base/endian.h b/base/include/android-base/endian.h
index 10efaa3..2d0f614 100644
--- a/base/include/android-base/endian.h
+++ b/base/include/android-base/endian.h
@@ -18,6 +18,9 @@
/* A cross-platform equivalent of bionic's <sys/endian.h>. */
+/* For __BIONIC__ and __GLIBC__ */
+#include <sys/cdefs.h>
+
#if defined(__BIONIC__)
#include <sys/endian.h>
@@ -38,6 +41,9 @@
#define betoh16(x) be16toh(x)
#define betoh32(x) be32toh(x)
#define betoh64(x) be64toh(x)
+#define letoh16(x) le16toh(x)
+#define letoh32(x) le32toh(x)
+#define letoh64(x) le64toh(x)
#else
@@ -45,10 +51,8 @@
/* macOS has some of the basics. */
#include <sys/_endian.h>
#else
-/* Windows really has nothing. */
-#define LITTLE_ENDIAN __LITTLE_ENDIAN
-#define BIG_ENDIAN __BIG_ENDIAN
-#define BYTE_ORDER __BYTE_ORDER
+/* Windows has even less. */
+#include <sys/param.h>
#define htons(x) __builtin_bswap16(x)
#define htonl(x) __builtin_bswap32(x)
#define ntohs(x) __builtin_bswap16(x)
diff --git a/base/include/android-base/mapped_file.h b/base/include/android-base/mapped_file.h
index 2ab49ab..6a19f1b 100644
--- a/base/include/android-base/mapped_file.h
+++ b/base/include/android-base/mapped_file.h
@@ -28,15 +28,17 @@
#include <windows.h>
#define PROT_READ 1
#define PROT_WRITE 2
+using os_handle = HANDLE;
#else
#include <sys/mman.h>
+using os_handle = int;
#endif
namespace android {
namespace base {
/**
- * A region of a file mapped into memory, also known as MmapFile.
+ * A region of a file mapped into memory (for grepping: also known as MmapFile or file mapping).
*/
class MappedFile {
public:
@@ -49,16 +51,33 @@
int prot);
/**
+ * Same thing, but using the raw OS file handle instead of a CRT wrapper.
+ */
+ static MappedFile FromOsHandle(os_handle h, off64_t offset, size_t length, int prot);
+
+ /**
* Removes the mapping.
*/
~MappedFile();
- char* data() { return base_ + offset_; }
- size_t size() { return size_; }
+ /**
+ * Not copyable but movable.
+ */
+ MappedFile(MappedFile&& other);
+ MappedFile& operator=(MappedFile&& other);
+
+ char* data() const { return base_ + offset_; }
+ size_t size() const { return size_; }
+
+ bool isValid() const { return base_ != nullptr; }
+
+ explicit operator bool() const { return isValid(); }
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile);
+ void Close();
+
char* base_;
size_t size_;
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index f60de56..862b73b 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -16,13 +16,15 @@
#include "android-base/mapped_file.h"
-#include <errno.h>
+#include <utility>
-#include "android-base/unique_fd.h"
+#include <errno.h>
namespace android {
namespace base {
+static constexpr char kEmptyBuffer[] = {'0'};
+
static off64_t InitPageSize() {
#if defined(_WIN32)
SYSTEM_INFO si;
@@ -35,51 +37,86 @@
std::unique_ptr<MappedFile> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
int prot) {
- static off64_t page_size = InitPageSize();
+#if defined(_WIN32)
+ auto file =
+ FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
+#else
+ auto file = FromOsHandle(fd.get(), offset, length, prot);
+#endif
+ return file ? std::make_unique<MappedFile>(std::move(file)) : std::unique_ptr<MappedFile>{};
+}
+
+MappedFile MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length, int prot) {
+ static const off64_t page_size = InitPageSize();
size_t slop = offset % page_size;
off64_t file_offset = offset - slop;
off64_t file_length = length + slop;
#if defined(_WIN32)
- HANDLE handle =
- CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), nullptr,
- (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
+ HANDLE handle = CreateFileMappingW(
+ h, nullptr, (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
if (handle == nullptr) {
// http://b/119818070 "app crashes when reading asset of zero length".
// Return a MappedFile that's only valid for reading the size.
- if (length == 0) {
- return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0, nullptr});
+ if (length == 0 && ::GetLastError() == ERROR_FILE_INVALID) {
+ return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0, nullptr};
}
- return nullptr;
+ return MappedFile(nullptr, 0, 0, nullptr);
}
void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
file_offset, file_length);
if (base == nullptr) {
CloseHandle(handle);
- return nullptr;
+ return MappedFile(nullptr, 0, 0, nullptr);
}
- return std::unique_ptr<MappedFile>(
- new MappedFile{static_cast<char*>(base), length, slop, handle});
+ return MappedFile{static_cast<char*>(base), length, slop, handle};
#else
- void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd.get(), file_offset);
+ void* base = mmap(nullptr, file_length, prot, MAP_SHARED, h, file_offset);
if (base == MAP_FAILED) {
// http://b/119818070 "app crashes when reading asset of zero length".
// mmap fails with EINVAL for a zero length region.
if (errno == EINVAL && length == 0) {
- return std::unique_ptr<MappedFile>(new MappedFile{nullptr, 0, 0});
+ return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0};
}
- return nullptr;
+ return MappedFile(nullptr, 0, 0);
}
- return std::unique_ptr<MappedFile>(new MappedFile{static_cast<char*>(base), length, slop});
+ return MappedFile{static_cast<char*>(base), length, slop};
#endif
}
+MappedFile::MappedFile(MappedFile&& other)
+ : base_(std::exchange(other.base_, nullptr)),
+ size_(std::exchange(other.size_, 0)),
+ offset_(std::exchange(other.offset_, 0))
+#ifdef _WIN32
+ ,
+ handle_(std::exchange(other.handle_, nullptr))
+#endif
+{
+}
+
+MappedFile& MappedFile::operator=(MappedFile&& other) {
+ Close();
+ base_ = std::exchange(other.base_, nullptr);
+ size_ = std::exchange(other.size_, 0);
+ offset_ = std::exchange(other.offset_, 0);
+#ifdef _WIN32
+ handle_ = std::exchange(other.handle_, nullptr);
+#endif
+ return *this;
+}
+
MappedFile::~MappedFile() {
+ Close();
+}
+
+void MappedFile::Close() {
#if defined(_WIN32)
- if (base_ != nullptr) UnmapViewOfFile(base_);
+ if (base_ != nullptr && size_ != 0) UnmapViewOfFile(base_);
if (handle_ != nullptr) CloseHandle(handle_);
+ handle_ = nullptr;
#else
- if (base_ != nullptr) munmap(base_, size_ + offset_);
+ if (base_ != nullptr && size_ != 0) munmap(base_, size_ + offset_);
#endif
base_ = nullptr;
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
index cfde73c..3629108 100644
--- a/base/mapped_file_test.cpp
+++ b/base/mapped_file_test.cpp
@@ -44,5 +44,8 @@
ASSERT_TRUE(tf.fd != -1);
auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
- ASSERT_EQ(0u, m->size());
+ ASSERT_NE(nullptr, m);
+ EXPECT_TRUE((bool)*m);
+ EXPECT_EQ(0u, m->size());
+ EXPECT_NE(nullptr, m->data());
}
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 149bee3..93bba68 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -82,13 +82,7 @@
void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
const char* file, unsigned int line, const char* message) {
- static const char log_characters[] = "VD\0WEFF";
- if (severity < sizeof(log_characters)) {
- auto severity_char = log_characters[severity];
- if (severity_char) fprintf(stderr, "%c ", severity_char);
- }
fprintf(stderr, "%s\n", message);
-
static auto logd = android::base::LogdLogger();
logd(id, severity, tag, file, line, message);
}
@@ -107,11 +101,9 @@
} // namespace
-int main(int argc, char* argv[]) {
- android::base::InitLogging(argv, MyLogger);
-
+static int do_remount(int argc, char* argv[]) {
enum {
- SUCCESS,
+ SUCCESS = 0,
NOT_USERDEBUG,
BADARG,
NOT_ROOT,
@@ -165,7 +157,7 @@
// Make sure we are root.
if (::getuid() != 0) {
- LOG(ERROR) << "must be run as root";
+ LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
return NOT_ROOT;
}
@@ -390,3 +382,10 @@
return retval;
}
+
+int main(int argc, char* argv[]) {
+ android::base::InitLogging(argv, MyLogger);
+ int result = do_remount(argc, argv);
+ printf("remount %s\n", result ? "failed" : "succeeded");
+ return result;
+}
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 777743c..6dc288e 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -140,7 +140,7 @@
}
if (opener) {
for (size_t i = 0; i < builder->block_devices_.size(); i++) {
- std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
+ std::string partition_name = builder->GetBlockDevicePartitionName(i);
BlockDeviceInfo device_info;
if (opener->GetInfo(partition_name, &device_info)) {
builder->UpdateBlockDeviceInfo(i, device_info);
@@ -164,7 +164,7 @@
// name and system properties.
// See comments for UpdateMetadataForOtherSuper.
auto super_device = GetMetadataSuperBlockDevice(*metadata.get());
- if (GetBlockDevicePartitionName(*super_device) != "super" &&
+ if (android::fs_mgr::GetBlockDevicePartitionName(*super_device) != "super" &&
IsRetrofitDynamicPartitionsDevice()) {
if (!UpdateMetadataForOtherSuper(metadata.get(), source_slot_number, target_slot_number)) {
return nullptr;
@@ -192,7 +192,8 @@
// Translate block devices.
auto source_block_devices = std::move(metadata->block_devices);
for (const auto& source_block_device : source_block_devices) {
- std::string partition_name = GetBlockDevicePartitionName(source_block_device);
+ std::string partition_name =
+ android::fs_mgr::GetBlockDevicePartitionName(source_block_device);
std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
// This should never happen. It means that the source metadata
@@ -375,7 +376,7 @@
block_devices_.emplace_back(out);
}
}
- if (GetBlockDevicePartitionName(block_devices_[0]) != super_partition) {
+ if (GetBlockDevicePartitionName(0) != super_partition) {
LERROR << "No super partition was specified.";
return false;
}
@@ -458,7 +459,7 @@
return nullptr;
}
-PartitionGroup* MetadataBuilder::FindGroup(const std::string& group_name) {
+PartitionGroup* MetadataBuilder::FindGroup(std::string_view group_name) {
for (const auto& group : groups_) {
if (group->name() == group_name) {
return group.get();
@@ -582,8 +583,7 @@
CHECK_NE(sectors_per_block, 0);
CHECK(sectors_needed % sectors_per_block == 0);
- if (IsABDevice() && !IsRetrofitMetadata() &&
- GetPartitionSlotSuffix(partition->name()) == "_b") {
+ if (IsABDevice() && ShouldHalveSuper() && GetPartitionSlotSuffix(partition->name()) == "_b") {
// Allocate "a" partitions top-down and "b" partitions bottom-up, to
// minimize fragmentation during OTA.
free_regions = PrioritizeSecondHalfOfSuper(free_regions);
@@ -849,7 +849,7 @@
bool MetadataBuilder::FindBlockDeviceByName(const std::string& partition_name,
uint32_t* index) const {
for (size_t i = 0; i < block_devices_.size(); i++) {
- if (GetBlockDevicePartitionName(block_devices_[i]) == partition_name) {
+ if (GetBlockDevicePartitionName(i) == partition_name) {
*index = i;
return true;
}
@@ -974,7 +974,8 @@
// Note: we don't compare alignment, since it's a performance thing and
// won't affect whether old extents continue to work.
return first.first_logical_sector == second.first_logical_sector && first.size == second.size &&
- GetBlockDevicePartitionName(first) == GetBlockDevicePartitionName(second);
+ android::fs_mgr::GetBlockDevicePartitionName(first) ==
+ android::fs_mgr::GetBlockDevicePartitionName(second);
}
bool MetadataBuilder::ImportPartitions(const LpMetadata& metadata,
@@ -1056,8 +1057,9 @@
false);
}
-bool MetadataBuilder::IsRetrofitMetadata() const {
- return GetBlockDevicePartitionName(block_devices_[0]) != LP_METADATA_DEFAULT_PARTITION_NAME;
+bool MetadataBuilder::ShouldHalveSuper() const {
+ return GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME &&
+ !IPropertyFetcher::GetInstance()->GetBoolProperty("ro.virtual_ab.enabled", false);
}
bool MetadataBuilder::AddLinearExtent(Partition* partition, const std::string& block_device,
@@ -1083,7 +1085,7 @@
return partitions;
}
-bool MetadataBuilder::ChangePartitionGroup(Partition* partition, const std::string& group_name) {
+bool MetadataBuilder::ChangePartitionGroup(Partition* partition, std::string_view group_name) {
if (!FindGroup(group_name)) {
LERROR << "Partition cannot change to unknown group: " << group_name;
return false;
@@ -1121,5 +1123,11 @@
return true;
}
+std::string MetadataBuilder::GetBlockDevicePartitionName(uint64_t index) const {
+ return index < block_devices_.size()
+ ? android::fs_mgr::GetBlockDevicePartitionName(block_devices_[index])
+ : "";
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 6d27873..b3c13e6 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -35,7 +35,7 @@
IPropertyFetcher::OverrideForTesting(std::make_unique<NiceMock<MockPropertyFetcher>>());
}
-MockPropertyFetcher* GetMockedInstance() {
+MockPropertyFetcher* GetMockedPropertyFetcher() {
return static_cast<MockPropertyFetcher*>(IPropertyFetcher::GetInstance());
}
@@ -789,7 +789,7 @@
// A and B slots should be allocated from separate halves of the partition,
// to mitigate allocating too many extents. (b/120433288)
- ON_CALL(*GetMockedInstance(), GetProperty("ro.boot.slot_suffix", _))
+ ON_CALL(*GetMockedPropertyFetcher(), GetProperty("ro.boot.slot_suffix", _))
.WillByDefault(Return("_a"));
auto builder = MetadataBuilder::New(device_info, 65536, 2);
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 3b229bd..c3f6e91 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -128,7 +128,7 @@
private:
void ShrinkTo(uint64_t aligned_size);
- void set_group_name(const std::string& group_name) { group_name_ = group_name; }
+ void set_group_name(std::string_view group_name) { group_name_ = group_name; }
std::string name_;
std::string group_name_;
@@ -227,7 +227,7 @@
Partition* FindPartition(const std::string& name);
// Find a group by name. If no group is found, nullptr is returned.
- PartitionGroup* FindGroup(const std::string& name);
+ PartitionGroup* FindGroup(std::string_view name);
// Add a predetermined extent to a partition.
bool AddLinearExtent(Partition* partition, const std::string& block_device,
@@ -252,7 +252,7 @@
// the metadata is exported, to avoid errors during potential group and
// size shuffling operations. This will return false if the new group does
// not exist.
- bool ChangePartitionGroup(Partition* partition, const std::string& group_name);
+ bool ChangePartitionGroup(Partition* partition, std::string_view group_name);
// Changes the size of a partition group. Size constraints will not be
// checked until metadata is exported, to avoid errors during group
@@ -287,6 +287,9 @@
// Return true if a block device is found, else false.
bool HasBlockDevice(const std::string& partition_name) const;
+ // Return the name of the block device at |index|.
+ std::string GetBlockDevicePartitionName(uint64_t index) const;
+
private:
MetadataBuilder();
MetadataBuilder(const MetadataBuilder&) = delete;
@@ -314,8 +317,8 @@
// Return true if the device is retrofitting dynamic partitions.
static bool IsRetrofitDynamicPartitionsDevice();
- // Return true if "this" metadata represents a metadata on a retrofit device.
- bool IsRetrofitMetadata() const;
+ // Return true if _b partitions should be prioritized at the second half of the device.
+ bool ShouldHalveSuper() const;
bool ValidatePartitionGroups() const;
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 2990863..3dace25 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -668,7 +668,7 @@
}
TEST(liblp, UpdateRetrofit) {
- ON_CALL(*GetMockedInstance(), GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
+ ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
.WillByDefault(Return(true));
unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
@@ -700,7 +700,7 @@
}
TEST(liblp, UpdateNonRetrofit) {
- ON_CALL(*GetMockedInstance(), GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
+ ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.boot.dynamic_partitions_retrofit", _))
.WillByDefault(Return(false));
unique_fd fd = CreateFlashedDisk();
diff --git a/fs_mgr/liblp/mock_property_fetcher.h b/fs_mgr/liblp/mock_property_fetcher.h
index eb91de2..0c28710 100644
--- a/fs_mgr/liblp/mock_property_fetcher.h
+++ b/fs_mgr/liblp/mock_property_fetcher.h
@@ -44,4 +44,4 @@
} // namespace fs_mgr
} // namespace android
-android::fs_mgr::MockPropertyFetcher* GetMockedInstance();
+android::fs_mgr::MockPropertyFetcher* GetMockedPropertyFetcher();
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 746987e..128a4f9 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -32,9 +32,14 @@
whole_static_libs: [
"libext2_uuid",
"libext4_utils",
- "libfiemap",
"libfstab",
],
+ header_libs: [
+ "libfiemap_headers",
+ ],
+ export_header_lib_headers: [
+ "libfiemap_headers",
+ ],
export_include_dirs: ["include"],
}
@@ -49,7 +54,7 @@
name: "libsnapshot",
defaults: ["libsnapshot_defaults"],
srcs: [":libsnapshot_sources"],
- static_libs: [
+ whole_static_libs: [
"libfiemap_binder",
],
}
@@ -59,6 +64,9 @@
defaults: ["libsnapshot_defaults"],
srcs: [":libsnapshot_sources"],
recovery_available: true,
+ whole_static_libs: [
+ "libfiemap_passthrough",
+ ],
}
cc_test {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 88800ed..fef5c06 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -313,7 +313,8 @@
// There may be an extra device, since the kernel doesn't let us have a
// snapshot and linear target in the same table.
auto dm_name = GetSnapshotDeviceName(name, status);
- if (name != dm_name && !dm.DeleteDevice(dm_name)) {
+ if (name != dm_name && dm.GetState(dm_name) != DmDeviceState::INVALID &&
+ !dm.DeleteDevice(dm_name)) {
LOG(ERROR) << "Could not delete inner snapshot device: " << dm_name;
return false;
}
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 642f2c1..397d8e5 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -890,14 +890,37 @@
# If reboot too soon after fresh flash, could trip device update failure logic
wait_for_screen
# Can we test remount -R command?
+OVERLAYFS_BACKING="cache mnt/scratch"
overlayfs_supported=true
-if [ "orange" = "`get_property ro.boot.verifiedbootstate`" -a \
- "2" = "`get_property partition.system.verified`" ]; then
+if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
+ "2" != "`get_property partition.system.verified`" ]; then
restore() {
${overlayfs_supported} || return 0
inFastboot &&
fastboot reboot &&
- adb_wait ${ADB_WAIT}
+ adb_wait ${ADB_WAIT} ||
+ true
+ if inAdb; then
+ reboot=false
+ for d in ${OVERLAYFS_BACKING}; do
+ if adb_su ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
+ adb_su rm -rf /${d}/overlay </dev/null
+ reboot=true
+ fi
+ done
+ if ${reboot}; then
+ adb_reboot &&
+ adb_wait ${ADB_WAIT}
+ fi
+ fi
+ }
+else
+ restore() {
+ ${overlayfs_supported} || return 0
+ inFastboot &&
+ fastboot reboot &&
+ adb_wait ${ADB_WAIT} ||
+ true
inAdb &&
adb_root &&
adb enable-verity >/dev/null 2>/dev/null &&
@@ -956,7 +979,6 @@
# So lets do our best to surgically wipe the overlayfs state without
# having to go through enable-verity transition.
reboot=false
-OVERLAYFS_BACKING="cache mnt/scratch"
for d in ${OVERLAYFS_BACKING}; do
if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
echo "${ORANGE}[ WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2
@@ -1468,7 +1490,7 @@
}
dd if=/dev/zero of=${img} bs=4096 count=16 2>/dev/null &&
fastboot_wait ${FASTBOOT_WAIT} ||
- die "reboot into fastboot `usb_status`"
+ die "reboot into fastboot to flash scratch `usb_status`"
fastboot flash --force ${scratch_partition} ${img}
err=${?}
cleanup
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
new file mode 100644
index 0000000..c592c37
--- /dev/null
+++ b/init/README.ueventd.md
@@ -0,0 +1,112 @@
+# Ueventd
+-------
+Ueventd manages `/dev`, sets permissions for `/sys`, and handles firmware uevents. It has default
+behavior described below, along with a scripting language that allows customizing this behavior,
+built on the same parser as init.
+
+Ueventd has one generic customization parameter, the size of rcvbuf_size for the ueventd socket. It
+is customized by the `uevent_socket_rcvbuf_size` parameter, which takes the format of
+
+ uevent_socket_rcvbuf_size <size>
+For example
+
+ uevent_socket_rcvbuf_size 16M
+Sets the uevent socket rcvbuf_size to 16 megabytes.
+
+## /dev
+----
+Ueventd listens to the kernel uevent sockets and creates/deletes nodes in `/dev` based on the
+incoming add/remove uevents. It defaults to using `0600` mode and `root` user/group. It always
+creates the nodes with the SELabel from the current loaded SEPolicy. It has three default behaviors
+for the node path:
+
+ 1. Block devices are created as `/dev/block/<basename uevent DEVPATH>`. There are symlinks created
+ to this node at `/dev/block/<type>/<parent device>/<basename uevent DEVPATH>`,
+ `/dev/block/<type>/<parent device>/by-name/<uevent PARTNAME>`, and `/dev/block/by-name/<uevent
+ PARTNAME>` if the device is a boot device.
+ 2. USB devices are created as `/dev/<uevent DEVNAME>` if `DEVNAME` was specified for the uevent,
+ otherwise as `/dev/bus/usb/<bus_id>/<device_id>` where `bus_id` is `uevent MINOR / 128 + 1` and
+ `device_id` is `uevent MINOR % 128 + 1`.
+ 3. All other devices are created as `/dev/<basename uevent DEVPATH>`
+
+The permissions can be modified using a ueventd.rc script and a line that beings with `/dev`. These
+lines take the format of
+
+ devname mode uid gid
+For example
+
+ /dev/null 0666 root root
+When `/dev/null` is created, its mode will be set to `0666`, its user to `root` and its group to
+`root`.
+
+The path can be modified using a ueventd.rc script and a `subsystem` section. There are three to set
+for a subsystem: the subsystem name, which device name to use, and which directory to place the
+device in. The section takes the below format of
+
+ subsystem <subsystem_name>
+ devname uevent_devname|uevent_devpath
+ [dirname <directory>]
+
+`subsystem_name` is used to match uevent `SUBSYSTEM` value
+
+`devname` takes one of two options
+ 1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME`
+ 2. `uevent_devpath` specified that the name of the node will be basename uevent `DEVPATH`
+
+`dirname` is an optional parameter that specifies a directory within `/dev` where the node will be
+created.
+
+For example
+
+ subsystem sound
+ devname uevent_devpath
+ dirname /dev/snd
+Indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/<basename uevent
+DEVPATH>`.
+
+## /sys
+----
+Ueventd by default takes no action for `/sys`, however it can be instructed to set permissions for
+certain files in `/sys` when matching uevents are generated. This is done using a ueventd.rc script
+and a line that begins with `/sys`. These lines take the format of
+
+ nodename attr mode uid gid
+For example
+
+ /sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system
+When a uevent that matches the pattern `/sys/devices/system/cpu/cpu*` is sent, the matching sysfs
+attribute, `cpufreq/scaling_max_freq`, will have its mode set to `0664`, its user to to `system` and
+its group set to `system`.
+
+Note that `*` matches as a wildcard and can be used anywhere in a path.
+
+## Firmware loading
+----------------
+Ueventd automatically serves firmware requests by searching through a list of firmware directories
+for a file matching the uevent `FIRMWARE`. It then forks a process to serve this firmware to the
+kernel.
+
+The list of firmware directories is customized by a `firmware_directories` line in a ueventd.rc
+file. This line takes the format of
+
+ firmware_directories <firmware_directory> [ <firmware_directory> ]*
+For example
+
+ firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/
+Adds those 4 directories, in that order to the list of firmware directories that will be tried by
+ueventd. Note that this option always accumulates to the list; it is not possible to remove previous
+entries.
+
+Ueventd will wait until after `post-fs` in init, to keep retrying before believing the firmwares are
+not present.
+
+## Coldboot
+--------
+Ueventd must create devices in `/dev` for all devices that have already sent their uevents before
+ueventd has started. To do so, when ueventd is started it does what it calls a 'coldboot' on `/sys`,
+in which it writes 'add' to every 'uevent' file that it finds in `/sys/class`, `/sys/block`, and
+`/sys/devices`. This causes the kernel to regenerate the uevents for these paths, and thus for
+ueventd to create the nodes.
+
+For boot time purposes, this is done in parallel across a set of child processes. `ueventd.cpp` in
+this directory contains documentation on how the parallelization is done.
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index b60c450..fd2d766 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -121,9 +121,9 @@
_exit(127);
}
ioctl(fd, TIOCSCTTY, 0);
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
close(fd);
const char* path = "/system/bin/sh";
@@ -291,6 +291,10 @@
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
+ auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 143cdfd..fd42256 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -523,6 +523,7 @@
// This function initializes SELinux then execs init to run in the init SELinux context.
int SetupSelinux(char** argv) {
+ SetStdioToDevNull(argv);
InitKernelLogging(argv);
if (REBOOT_BOOTLOADER_ON_PANIC) {
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index 2d6ce85..8937636 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -22,18 +22,6 @@
__BEGIN_DECLS
-/*
- * Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
- * to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
- *
- * The library_search_path is the search path for anonymous namespace. The anonymous namespace
- * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
- * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
- */
-extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
- const char* library_search_path);
-
-
enum {
/* A regular namespace is the namespace with a custom search path that does
* not impose any restrictions on the location of native libraries.
@@ -62,8 +50,18 @@
*/
ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
- ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
- ANDROID_NAMESPACE_TYPE_ISOLATED,
+ /* This flag instructs linker to use this namespace as the anonymous
+ * namespace. The anonymous namespace is used in the case when linker cannot
+ * identify the caller of dlopen/dlsym. This happens for the code not loaded
+ * by dynamic linker; for example calls from the mono-compiled code. There can
+ * be only one anonymous namespace in a process. If there already is an
+ * anonymous namespace in the process, using this flag when creating a new
+ * namespace causes an error.
+ */
+ ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS = 0x10000000,
+
+ ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED =
+ ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED,
};
/*
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index a9eea8c..7f5768c 100644
--- a/libnativeloader/library_namespaces.cpp
+++ b/libnativeloader/library_namespaces.cpp
@@ -159,13 +159,6 @@
}
}
- // Initialize the anonymous namespace with the first non-empty library path.
- Result<void> ret;
- if (!library_path.empty() && !initialized_ &&
- !(ret = InitPublicNamespace(library_path.c_str()))) {
- return ret.error();
- }
-
LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr,
"There is already a namespace associated with this classloader");
@@ -215,13 +208,22 @@
// Create the app namespace
NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
- auto app_ns =
- NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns,
- is_shared, target_sdk_version < 24 /* is_greylist_enabled */);
+ // Heuristic: the first classloader with non-empty library_path is assumed to
+ // be the main classloader for app
+ // TODO(b/139178525) remove this heuristic by determining this in LoadedApk (or its
+ // friends) and then passing it down to here.
+ bool is_main_classloader = app_main_namespace_ == nullptr && !library_path.empty();
+ // Policy: the namespace for the main classloader is also used as the
+ // anonymous namespace.
+ bool also_used_as_anonymous = is_main_classloader;
+ // Note: this function is executed with g_namespaces_mutex held, thus no
+ // racing here.
+ auto app_ns = NativeLoaderNamespace::Create(
+ namespace_name, library_path, permitted_path, parent_ns, is_shared,
+ target_sdk_version < 24 /* is_greylist_enabled */, also_used_as_anonymous);
if (!app_ns) {
return app_ns.error();
}
-
// ... and link to other namespaces to allow access to some public libraries
bool is_bridged = app_ns->IsBridged();
@@ -278,6 +280,9 @@
}
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
+ if (is_main_classloader) {
+ app_main_namespace_ = &(*app_ns);
+ }
return &(namespaces_.back().second);
}
@@ -295,32 +300,6 @@
return nullptr;
}
-Result<void> LibraryNamespaces::InitPublicNamespace(const char* library_path) {
- // Ask native bride if this apps library path should be handled by it
- bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
-
- // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
- // code is one example) unknown to linker in which case linker uses anonymous
- // namespace. The second argument specifies the search path for the anonymous
- // namespace which is the library_path of the classloader.
- initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(),
- is_native_bridge ? nullptr : library_path);
- if (!initialized_) {
- return Error() << dlerror();
- }
-
- // and now initialize native bridge namespaces if necessary.
- if (NativeBridgeInitialized()) {
- initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(),
- is_native_bridge ? library_path : nullptr);
- if (!initialized_) {
- return Error() << NativeBridgeGetError();
- }
- }
-
- return {};
-}
-
NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
jobject class_loader) {
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h
index e54bc0a..7b3efff 100644
--- a/libnativeloader/library_namespaces.h
+++ b/libnativeloader/library_namespaces.h
@@ -38,7 +38,7 @@
// object for a given ClassLoader.
class LibraryNamespaces {
public:
- LibraryNamespaces() : initialized_(false) {}
+ LibraryNamespaces() : initialized_(false), app_main_namespace_(nullptr) {}
LibraryNamespaces(LibraryNamespaces&&) = default;
LibraryNamespaces(const LibraryNamespaces&) = delete;
@@ -48,6 +48,7 @@
void Reset() {
namespaces_.clear();
initialized_ = false;
+ app_main_namespace_ = nullptr;
}
Result<NativeLoaderNamespace*> Create(JNIEnv* env, uint32_t target_sdk_version,
jobject class_loader, bool is_shared, jstring dex_path,
@@ -59,6 +60,7 @@
NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
bool initialized_;
+ NativeLoaderNamespace* app_main_namespace_;
std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
};
diff --git a/libnativeloader/native_loader_namespace.cpp b/libnativeloader/native_loader_namespace.cpp
index 4add6e6..a81fddf 100644
--- a/libnativeloader/native_loader_namespace.cpp
+++ b/libnativeloader/native_loader_namespace.cpp
@@ -85,7 +85,8 @@
Result<NativeLoaderNamespace> NativeLoaderNamespace::Create(
const std::string& name, const std::string& search_paths, const std::string& permitted_paths,
- const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled) {
+ const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled,
+ bool also_used_as_anonymous) {
bool is_bridged = false;
if (parent != nullptr) {
is_bridged = parent->IsBridged();
@@ -100,7 +101,17 @@
}
const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns;
+ // All namespaces for apps are isolated
uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;
+
+ // The namespace is also used as the anonymous namespace
+ // which is used when the linker fails to determine the caller address
+ if (also_used_as_anonymous) {
+ type |= ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
+ }
+
+ // Bundled apps have access to all system libraries that are currently loaded
+ // in the default namespace
if (is_shared) {
type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
diff --git a/libnativeloader/native_loader_namespace.h b/libnativeloader/native_loader_namespace.h
index 29b759c..7200ee7 100644
--- a/libnativeloader/native_loader_namespace.h
+++ b/libnativeloader/native_loader_namespace.h
@@ -39,7 +39,8 @@
const std::string& search_paths,
const std::string& permitted_paths,
const NativeLoaderNamespace* parent, bool is_shared,
- bool is_greylist_enabled);
+ bool is_greylist_enabled,
+ bool also_used_as_anonymous);
NativeLoaderNamespace(NativeLoaderNamespace&&) = default;
NativeLoaderNamespace(const NativeLoaderNamespace&) = default;
diff --git a/libnativeloader/native_loader_test.cpp b/libnativeloader/native_loader_test.cpp
index b939eee..a641109 100644
--- a/libnativeloader/native_loader_test.cpp
+++ b/libnativeloader/native_loader_test.cpp
@@ -331,7 +331,8 @@
// expected output (.. for the default test inputs)
std::string expected_namespace_name = "classloader-namespace";
- uint64_t expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
+ uint64_t expected_namespace_flags =
+ ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
std::string expected_library_path = library_path;
std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
std::string expected_parent_namespace = "platform";
@@ -356,17 +357,6 @@
EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(AnyNumber());
EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(AnyNumber());
- if (IsBridged()) {
- EXPECT_CALL(*mock,
- mock_init_anonymous_namespace(false, StrEq(default_public_libraries()), nullptr))
- .WillOnce(Return(true));
-
- EXPECT_CALL(*mock, NativeBridgeInitialized()).WillOnce(Return(true));
- }
-
- EXPECT_CALL(*mock, mock_init_anonymous_namespace(
- Eq(IsBridged()), StrEq(default_public_libraries()), StrEq(library_path)))
- .WillOnce(Return(true));
EXPECT_CALL(*mock, mock_create_namespace(
Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
StrEq(expected_library_path), expected_namespace_flags,
@@ -443,7 +433,7 @@
dex_path = "/system/app/foo/foo.apk";
is_shared = true;
- expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+ expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
SetExpectations();
RunTest();
}
@@ -452,7 +442,7 @@
dex_path = "/vendor/app/foo/foo.apk";
is_shared = true;
- expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+ expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
SetExpectations();
RunTest();
}
@@ -475,7 +465,7 @@
dex_path = "/product/app/foo/foo.apk";
is_shared = true;
- expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+ expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
SetExpectations();
RunTest();
}
@@ -485,7 +475,7 @@
is_shared = true;
target_sdk_version = 30;
- expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED;
+ expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
SetExpectations();
RunTest();
}
@@ -512,6 +502,22 @@
RunTest();
}
+TEST_P(NativeLoaderTest_Create, NamespaceForSharedLibIsNotUsedAsAnonymousNamespace) {
+ if (IsBridged()) {
+ // There is no shared lib in translated arch
+ // TODO(jiyong): revisit this
+ return;
+ }
+ // compared to apks, for java shared libs, library_path is empty; java shared
+ // libs don't have their own native libs. They use platform's.
+ library_path = "";
+ expected_library_path = library_path;
+ // no ALSO_USED_AS_ANONYMOUS
+ expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
+ SetExpectations();
+ RunTest();
+}
+
TEST_P(NativeLoaderTest_Create, TwoApks) {
SetExpectations();
const uint32_t second_app_target_sdk_version = 29;
@@ -523,6 +529,8 @@
const std::string expected_second_app_permitted_path =
std::string("/data:/mnt/expand:") + second_app_permitted_path;
const std::string expected_second_app_parent_namespace = "classloader-namespace";
+ // no ALSO_USED_AS_ANONYMOUS
+ const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
// The scenario is that second app is loaded by the first app.
// So the first app's classloader (`classloader`) is parent of the second
@@ -532,10 +540,10 @@
// namespace for the second app is created. Its parent is set to the namespace
// of the first app.
- EXPECT_CALL(*mock, mock_create_namespace(Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
- StrEq(second_app_library_path), expected_namespace_flags,
- StrEq(expected_second_app_permitted_path),
- NsEq(dex_path.c_str())))
+ EXPECT_CALL(*mock, mock_create_namespace(
+ Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
+ StrEq(second_app_library_path), expected_second_namespace_flags,
+ StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str())))
.WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
.WillRepeatedly(Return(true));
@@ -568,7 +576,5 @@
INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
-// TODO(b/130388701#comment22) add a test for anonymous namespace
-
} // namespace nativeloader
} // namespace android
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index 5b8179f..c5c4960 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -17,6 +17,7 @@
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE 1
+#include <algorithm>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
@@ -48,13 +49,6 @@
#define off64_t off_t
#endif
-#define min(a, b) \
- ({ \
- typeof(a) _a = (a); \
- typeof(b) _b = (b); \
- (_a < _b) ? _a : _b; \
- })
-
#define SPARSE_HEADER_MAJOR_VER 1
#define SPARSE_HEADER_MINOR_VER 0
#define SPARSE_HEADER_LEN (sizeof(sparse_header_t))
@@ -231,7 +225,7 @@
struct output_file_gz* outgz = to_output_file_gz(out);
while (len > 0) {
- ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX));
+ ret = gzwrite(outgz->gz_fd, data, std::min<unsigned int>(len, (unsigned int)INT_MAX));
if (ret == 0) {
error("gzwrite %s", gzerror(outgz->gz_fd, nullptr));
return -1;
@@ -268,7 +262,7 @@
int ret;
while (off > 0) {
- to_write = min(off, (int64_t)INT_MAX);
+ to_write = std::min(off, (int64_t)INT_MAX);
ret = outc->write(outc->priv, nullptr, to_write);
if (ret < 0) {
return ret;
@@ -470,7 +464,7 @@
}
while (len) {
- write_len = min(len, out->block_size);
+ write_len = std::min(len, out->block_size);
ret = out->ops->write(out, out->fill_buf, write_len);
if (ret < 0) {
return ret;
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 3321425..a639592 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -633,15 +633,15 @@
namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
+namespace.neuralnetworks.links = system
+namespace.neuralnetworks.link.system.shared_libs = libc.so
+namespace.neuralnetworks.link.system.shared_libs += libcgrouprc.so
+namespace.neuralnetworks.link.system.shared_libs += libdl.so
+namespace.neuralnetworks.link.system.shared_libs += liblog.so
+namespace.neuralnetworks.link.system.shared_libs += libm.so
+namespace.neuralnetworks.link.system.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.system.shared_libs += libsync.so
+namespace.neuralnetworks.link.system.shared_libs += libvndksupport.so
###############################################################################
# Namespace config for native tests that need access to both system and vendor
@@ -795,5 +795,3 @@
namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
-
-namespace.default.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 86d8042..4d34b67 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -121,6 +121,9 @@
mkdir /mnt/media_rw 0750 root media_rw
mkdir /mnt/user 0755 root root
mkdir /mnt/user/0 0755 root root
+ mkdir /mnt/user/0/self 0755 root root
+ mkdir /mnt/user/0/emulated 0755 root root
+ mkdir /mnt/user/0/emulated/0 0755 root root
mkdir /mnt/expand 0771 system system
mkdir /mnt/appfuse 0711 root root
@@ -367,9 +370,6 @@
# Once everything is setup, no need to modify /.
# The bind+remount combination allows this to work in containers.
mount rootfs rootfs / remount bind ro nodev
- # Mount default storage into root namespace
- mount none /mnt/runtime/default /storage bind rec
- mount none none /storage slave rec
# Make sure /sys/kernel/debug (if present) is labeled properly
# Note that tracefs may be mounted under debug, so we need to cross filesystems
@@ -642,6 +642,22 @@
chown root system /dev/fscklogs/log
chmod 0770 /dev/fscklogs/log
+# Switch between sdcardfs and FUSE depending on persist property
+# TODO: Move this to ro property before launch because FDE devices
+# interact with persistent properties differently during boot
+on zygote-start && property:persist.sys.fuse=true
+ # Mount default storage into root namespace
+ mount none /mnt/user/0 /storage bind rec
+ mount none none /storage slave rec
+on zygote-start && property:persist.sys.fuse=false
+ # Mount default storage into root namespace
+ mount none /mnt/runtime/default /storage bind rec
+ mount none none /storage slave rec
+on zygote-start && property:persist.sys.fuse=""
+ # Mount default storage into root namespace
+ mount none /mnt/runtime/default /storage bind rec
+ mount none none /storage slave rec
+
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted