Merge "Fix more endian.h issues"
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/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/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 52aad12..746987e 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -33,6 +33,7 @@
"libext2_uuid",
"libext4_utils",
"libfiemap",
+ "libfstab",
],
export_include_dirs: ["include"],
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index f7608dc..4fb6808 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -71,11 +71,7 @@
virtual ~IDeviceInfo() {}
virtual std::string GetGsidDir() const = 0;
virtual std::string GetMetadataDir() const = 0;
-
- // Return true if the device is currently running off snapshot devices,
- // indicating that we have booted after applying (but not merging) an
- // OTA.
- virtual bool IsRunningSnapshot() const = 0;
+ virtual std::string GetSlotSuffix() const = 0;
};
~SnapshotManager();
@@ -93,6 +89,11 @@
// state != Initiated or None.
bool CancelUpdate();
+ // Mark snapshot writes as having completed. After this, new snapshots cannot
+ // be created, and the device must either cancel the OTA (either before
+ // rebooting or after rolling back), or merge the OTA.
+ bool FinishedSnapshotWrites();
+
// Initiate a merge on all snapshot devices. This should only be used after an
// update has been marked successful after booting.
bool InitiateMerge();
@@ -261,6 +262,9 @@
bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status);
std::string GetSnapshotStatusFilePath(const std::string& name);
+ std::string GetSnapshotBootIndicatorPath();
+ void RemoveSnapshotBootIndicator();
+
// Return the name of the device holding the "snapshot" or "snapshot-merge"
// target. This may not be the final device presented via MapSnapshot(), if
// for example there is a linear segment.
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 63a01f3..75a1f26 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -27,6 +27,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/ext4_utils.h>
+#include <fstab/fstab.h>
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
@@ -48,18 +49,15 @@
// Unit is sectors, this is a 4K chunk.
static constexpr uint32_t kSnapshotChunkSize = 8;
+static constexpr char kSnapshotBootIndicatorFile[] = "snapshot-boot";
+
class DeviceInfo final : public SnapshotManager::IDeviceInfo {
public:
std::string GetGsidDir() const override { return "ota"s; }
std::string GetMetadataDir() const override { return "/metadata/ota"s; }
- bool IsRunningSnapshot() const override;
+ std::string GetSlotSuffix() const override { return fs_mgr_get_slot_suffix(); }
};
-bool DeviceInfo::IsRunningSnapshot() const {
- // :TODO: implement this check.
- return true;
-}
-
// Note: IIMageManager is an incomplete type in the header, so the default
// destructor doesn't work.
SnapshotManager::~SnapshotManager() {}
@@ -115,6 +113,27 @@
return true;
}
+bool SnapshotManager::FinishedSnapshotWrites() {
+ auto lock = LockExclusive();
+ if (!lock) return false;
+
+ if (ReadUpdateState(lock.get()) != UpdateState::Initiated) {
+ LOG(ERROR) << "Can only transition to the Unverified state from the Initiated state.";
+ return false;
+ }
+
+ // This file acts as both a quick indicator for init (it can use access(2)
+ // to decide how to do first-stage mounts), and it stores the old slot, so
+ // we can tell whether or not we performed a rollback.
+ auto contents = device_->GetSlotSuffix();
+ auto boot_file = GetSnapshotBootIndicatorPath();
+ if (!android::base::WriteStringToFile(contents, boot_file)) {
+ PLOG(ERROR) << "write failed: " << boot_file;
+ return false;
+ }
+ return WriteUpdateState(lock.get(), UpdateState::Unverified);
+}
+
bool SnapshotManager::CreateSnapshot(LockedFile* lock, const std::string& name,
uint64_t device_size, uint64_t snapshot_size,
uint64_t cow_size) {
@@ -339,8 +358,16 @@
LOG(ERROR) << "Cannot begin a merge if an update has not been verified";
return false;
}
- if (!device_->IsRunningSnapshot()) {
- LOG(ERROR) << "Cannot begin a merge if the device is not booted off a snapshot";
+
+ std::string old_slot;
+ auto boot_file = GetSnapshotBootIndicatorPath();
+ if (!android::base::ReadFileToString(boot_file, &old_slot)) {
+ LOG(ERROR) << "Could not determine the previous slot; aborting merge";
+ return false;
+ }
+ auto new_slot = device_->GetSlotSuffix();
+ if (new_slot == old_slot) {
+ LOG(ERROR) << "Device cannot merge while booting off old slot " << old_slot;
return false;
}
@@ -676,7 +703,23 @@
return UpdateState::MergeCompleted;
}
+std::string SnapshotManager::GetSnapshotBootIndicatorPath() {
+ return metadata_dir_ + "/" + kSnapshotBootIndicatorFile;
+}
+
+void SnapshotManager::RemoveSnapshotBootIndicator() {
+ // It's okay if this fails - first-stage init performs a deeper check after
+ // reading the indicator file, so it's not a problem if it still exists
+ // after the update completes.
+ auto boot_file = GetSnapshotBootIndicatorPath();
+ if (unlink(boot_file.c_str()) == -1 && errno != ENOENT) {
+ PLOG(ERROR) << "unlink " << boot_file;
+ }
+}
+
void SnapshotManager::AcknowledgeMergeSuccess(LockedFile* lock) {
+ RemoveSnapshotBootIndicator();
+
if (!WriteUpdateState(lock, UpdateState::None)) {
// We'll try again next reboot, ad infinitum.
return;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 4903224..34ea331 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -43,12 +43,12 @@
public:
std::string GetGsidDir() const override { return "ota/test"s; }
std::string GetMetadataDir() const override { return "/metadata/ota/test"s; }
- bool IsRunningSnapshot() const override { return is_running_snapshot_; }
+ std::string GetSlotSuffix() const override { return slot_suffix_; }
- void set_is_running_snapshot(bool value) { is_running_snapshot_ = value; }
+ void set_slot_suffix(const std::string& suffix) { slot_suffix_ = suffix; }
private:
- bool is_running_snapshot_;
+ std::string slot_suffix_;
};
std::unique_ptr<SnapshotManager> sm;
@@ -60,7 +60,7 @@
protected:
void SetUp() override {
- test_device->set_is_running_snapshot(false);
+ test_device->set_slot_suffix("_a");
if (sm->GetUpdateState() != UpdateState::None) {
CleanupTestArtifacts();
@@ -189,15 +189,9 @@
}
TEST_F(SnapshotTest, NoMergeBeforeReboot) {
- ASSERT_TRUE(AcquireLock());
+ ASSERT_TRUE(sm->FinishedSnapshotWrites());
- // Set the state to Unverified, as if we finished an update.
- ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Unverified));
-
- // Release the lock.
- lock_ = nullptr;
-
- // Merge should fail, since we didn't mark the device as rebooted.
+ // Merge should fail, since the slot hasn't changed.
ASSERT_FALSE(sm->InitiateMerge());
}
@@ -231,7 +225,7 @@
// Release the lock.
lock_ = nullptr;
- test_device->set_is_running_snapshot(true);
+ test_device->set_slot_suffix("_b");
ASSERT_TRUE(sm->InitiateMerge());
// The device should have been switched to a snapshot-merge target.
@@ -273,13 +267,12 @@
unique_fd fd(open(cow_path.c_str(), O_RDONLY | O_CLOEXEC));
ASSERT_GE(fd, 0);
- // Set the state to Unverified, as if we finished an update.
- ASSERT_TRUE(sm->WriteUpdateState(lock_.get(), UpdateState::Unverified));
-
// Release the lock.
lock_ = nullptr;
- test_device->set_is_running_snapshot(true);
+ ASSERT_TRUE(sm->FinishedSnapshotWrites());
+
+ test_device->set_slot_suffix("_b");
ASSERT_TRUE(sm->InitiateMerge());
// COW cannot be removed due to open fd, so expect a soft failure.
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..84cabde 100644
--- a/libnativeloader/library_namespaces.h
+++ b/libnativeloader/library_namespaces.h
@@ -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/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 3321425..46e9920 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -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%