diff --git a/tests/Android.mk b/tests/Android.mk index 9db372ad0..3aef5bb25 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -252,8 +252,12 @@ bionic-unit-tests_ldflags := \ -Wl,--export-dynamic \ -Wl,-u,DlSymTestFunction \ +bionic-unit-tests_c_includes := \ + $(call include-path-for, libpagemap) \ + bionic-unit-tests_shared_libraries_target := \ libdl \ + libpagemap \ module := bionic-unit-tests module_tag := optional diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 4b2a5e23c..b56fc4102 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -24,8 +24,11 @@ #include #include #include +#include #include +#include + #define ASSERT_DL_NOTNULL(ptr) \ ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror() @@ -209,6 +212,8 @@ protected: EXPECT_EQ(4, f()); } + void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out); + android_dlextinfo extinfo_; char relro_file_[PATH_MAX]; }; @@ -230,3 +235,121 @@ TEST_F(DlExtRelroSharingTest, RelroFileEmpty) { ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME)); } + +TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) { + ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME)); + int relro_fd = open(relro_file_, O_RDONLY); + ASSERT_NOERROR(relro_fd); + extinfo_.flags |= ANDROID_DLEXT_USE_RELRO; + extinfo_.relro_fd = relro_fd; + int pipefd[2]; + ASSERT_NOERROR(pipe(pipefd)); + + size_t without_sharing, with_sharing; + ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing)); + ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing)); + + // We expect the sharing to save at least 10% of the total PSS. In practice + // it saves 40%+ for this test. + size_t expected_size = without_sharing - (without_sharing/10); + EXPECT_LT(with_sharing, expected_size); +} + +void getPss(pid_t pid, size_t* pss_out) { + pm_kernel_t* kernel; + ASSERT_EQ(0, pm_kernel_create(&kernel)); + + pm_process_t* process; + ASSERT_EQ(0, pm_process_create(kernel, pid, &process)); + + pm_map_t** maps; + size_t num_maps; + ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps)); + + size_t total_pss = 0; + for (size_t i = 0; i < num_maps; i++) { + pm_memusage_t usage; + ASSERT_EQ(0, pm_map_usage(maps[i], &usage)); + total_pss += usage.pss; + } + *pss_out = total_pss; + + free(maps); + pm_process_destroy(process); + pm_kernel_destroy(kernel); +} + +void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, + size_t* pss_out) { + const int CHILDREN = 20; + + // Create children + pid_t childpid[CHILDREN]; + int childpipe[CHILDREN]; + for (int i=0; i