Add API to set page size compat mode
Adding APIs in libdl to set linker global which will be used to set the page size compat mode for particular app.
Test: atest bionic-unit-tests
Test: atest CtsBionicTestCases
Bug: 371049373
Change-Id: I20f0fe9ece5db833568edf27ec268edf999f1741
diff --git a/libdl/libdl_android.cpp b/libdl/libdl_android.cpp
index 47a164a..f0959eb 100644
--- a/libdl/libdl_android.cpp
+++ b/libdl/libdl_android.cpp
@@ -59,6 +59,9 @@
__attribute__((__weak__, visibility("default")))
struct android_namespace_t* __loader_android_get_exported_namespace(const char* name);
+__attribute__((__weak__, visibility("default"))) void __loader_android_set_16kb_appcompat_mode(
+ bool enable_app_compat);
+
// Proxy calls to bionic loader
__attribute__((__weak__))
void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
@@ -115,4 +118,8 @@
return __loader_android_get_exported_namespace(name);
}
+__attribute__((__weak__)) void android_set_16kb_appcompat_mode(bool enable_app_compat) {
+ __loader_android_set_16kb_appcompat_mode(enable_app_compat);
+}
+
} // extern "C"
diff --git a/libdl/libdl_android.map.txt b/libdl/libdl_android.map.txt
index 7afcd9c..efbc841 100644
--- a/libdl/libdl_android.map.txt
+++ b/libdl/libdl_android.map.txt
@@ -24,6 +24,7 @@
android_init_anonymous_namespace; # apex
android_link_namespaces; # apex
android_set_application_target_sdk_version; # apex
+ android_set_16kb_appcompat_mode; #apex
local:
*;
};
diff --git a/linker/Android.bp b/linker/Android.bp
index a06ca29..37157fd 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -494,6 +494,7 @@
"linker_mapped_file_fragment.cpp",
"linker_sdk_versions.cpp",
"linker_dlwarning.cpp",
+ "linker_phdr_16kib_compat.cpp"
],
static_libs: [
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index fee19f4..4f5e1f7 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -89,6 +89,7 @@
const void* caller_addr) __LINKER_PUBLIC__;
void __loader_add_thread_local_dtor(void* dso_handle) __LINKER_PUBLIC__;
void __loader_remove_thread_local_dtor(void* dso_handle) __LINKER_PUBLIC__;
+void __loader_android_set_16kb_appcompat_mode(bool enable_app_compat) __LINKER_PUBLIC__;
libc_shared_globals* __loader_shared_globals() __LINKER_PUBLIC__;
#if defined(__arm__)
_Unwind_Ptr __loader_dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) __LINKER_PUBLIC__;
@@ -301,6 +302,11 @@
decrement_dso_handle_reference_counter(dso_handle);
}
+void __loader_android_set_16kb_appcompat_mode(bool enable_app_compat) {
+ ScopedPthreadMutexLocker locker(&g_dl_mutex);
+ set_16kb_appcompat_mode(enable_app_compat);
+}
+
libc_shared_globals* __loader_shared_globals() {
return __libc_shared_globals();
}
diff --git a/linker/ld_android.cpp b/linker/ld_android.cpp
index 1c03106..c938a16 100644
--- a/linker/ld_android.cpp
+++ b/linker/ld_android.cpp
@@ -55,6 +55,7 @@
__strong_alias(__loader_add_thread_local_dtor, __internal_linker_error);
__strong_alias(__loader_remove_thread_local_dtor, __internal_linker_error);
__strong_alias(__loader_shared_globals, __internal_linker_error);
+__strong_alias(__loader_android_set_16kb_appcompat_mode, __internal_linker_error);
#if defined(__arm__)
__strong_alias(__loader_dl_unwind_find_exidx, __internal_linker_error);
#endif
diff --git a/linker/linker.arm.map b/linker/linker.arm.map
index b805cd6..edfa249 100644
--- a/linker/linker.arm.map
+++ b/linker/linker.arm.map
@@ -25,6 +25,7 @@
__loader_shared_globals;
rtld_db_dlactivity;
__loader_android_handle_signal;
+ __loader_android_set_16kb_appcompat_mode;
local:
*;
};
diff --git a/linker/linker.generic.map b/linker/linker.generic.map
index 4d7f236..2beae65 100644
--- a/linker/linker.generic.map
+++ b/linker/linker.generic.map
@@ -24,6 +24,7 @@
__loader_shared_globals;
rtld_db_dlactivity;
__loader_android_handle_signal;
+ __loader_android_set_16kb_appcompat_mode;
local:
*;
};
diff --git a/linker/linker.h b/linker/linker.h
index ac2222d..a2424c6 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -108,6 +108,9 @@
bool get_transparent_hugepages_supported();
+void set_16kb_appcompat_mode(bool enable_app_compat);
+bool get_16kb_appcompat_mode();
+
enum {
/* A regular namespace is the namespace with a custom search path that does
* not impose any restrictions on the location of native libraries.
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 7691031..4cbaa2e 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -183,7 +183,8 @@
// It cannot be cached since the developer may toggle app compat on/off.
// This check will be removed once app compat is made the default on 16KiB devices.
should_use_16kib_app_compat_ =
- ::android::base::GetBoolProperty("bionic.linker.16kb.app_compat.enabled", false);
+ ::android::base::GetBoolProperty("bionic.linker.16kb.app_compat.enabled", false) ||
+ get_16kb_appcompat_mode();
}
return did_read_;
diff --git a/linker/linker_phdr_16kib_compat.cpp b/linker/linker_phdr_16kib_compat.cpp
index a4d8459..bad20ba 100644
--- a/linker/linker_phdr_16kib_compat.cpp
+++ b/linker/linker_phdr_16kib_compat.cpp
@@ -42,10 +42,20 @@
#include <string>
+static bool g_enable_16kb_app_compat;
+
static inline bool segment_contains_prefix(const ElfW(Phdr)* segment, const ElfW(Phdr)* prefix) {
return segment && prefix && segment->p_vaddr == prefix->p_vaddr;
}
+void set_16kb_appcompat_mode(bool enable_app_compat) {
+ g_enable_16kb_app_compat = enable_app_compat;
+}
+
+bool get_16kb_appcompat_mode() {
+ return g_enable_16kb_app_compat;
+}
+
/*
* Returns true if the ELF contains at most 1 RELRO segment; and populates @relro_phdr
* with the relro phdr or nullptr if none.
diff --git a/tests/page_size_16kib_compat_test.cpp b/tests/page_size_16kib_compat_test.cpp
index 9aecfba..a5d91b8 100644
--- a/tests/page_size_16kib_compat_test.cpp
+++ b/tests/page_size_16kib_compat_test.cpp
@@ -30,6 +30,8 @@
#include <android-base/properties.h>
+extern "C" void android_set_16kb_appcompat_mode(bool enable_app_compat);
+
TEST(PageSize16KiBCompatTest, ElfAlignment4KiB_LoadElf) {
if (getpagesize() != 0x4000) {
GTEST_SKIP() << "This test is only applicable to 16kB page-size devices";
@@ -44,3 +46,17 @@
if (app_compat_enabled) CallTestFunction(handle);
}
+
+TEST(PageSize16KiBCompatTest, ElfAlignment4KiB_LoadElf_perAppOption) {
+ if (getpagesize() != 0x4000) {
+ GTEST_SKIP() << "This test is only applicable to 16kB page-size devices";
+ }
+
+ android_set_16kb_appcompat_mode(true);
+ std::string lib = GetTestLibRoot() + "/libtest_elf_max_page_size_4kib.so";
+ void* handle = nullptr;
+
+ OpenTestLibrary(lib, false /*should_fail*/, &handle);
+ CallTestFunction(handle);
+ android_set_16kb_appcompat_mode(false);
+}