Store soname as a std::string.
Once upon a time (and, indeed, to this very day if you're on LP32) the
soinfo struct used a fixed-length buffer for the soname. This caused
some issues, mainly with app developers who accidentally included a full
Windows "C:\My Computer\...\libfoo.so" style path. To avoid all this we
switched to just pointing into the ELF file itself, where the DT_SONAME
is already stored as a NUL-terminated string. And all was well for many
years.
Now though, we've seen a bunch of slow startup traces from dogfood where
`dlopen("libnativebridge.so")` in a cold start takes 125-200ms on a recent
device, despite no IO contention. Even though libnativebridge.so is only
20KiB.
Measurement showed that every library whose soname we check required
pulling in a whole page just for the (usually) very short string. Worse,
there's readahead. In one trace we saw 18 pages of libhwui.so pulled
in just for `"libhwui.so\0"`. In fact, there were 3306 pages (~13MiB)
added to the page cache during `dlopen("libnativebridge.so")`. 13MiB for
a 20KiB shared library!
This is the obvious change to use a std::string to copy the sonames
instead. This will dirty slightly more memory, but massively improve
locality.
Testing with the same pathological setup took `dlopen("libnativebridge.so")`
down from 192ms to 819us.
Bug: http://b/177102905
Test: tested with a pathologically modified kernel
Change-Id: I33837f4706adc25f93c6fa6013e8ba970911dfb9
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 60fd242..f44cb1c 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -695,7 +695,7 @@
if (has_min_version(2)) {
soname_ = soname;
}
- strlcpy(old_name_, soname_, sizeof(old_name_));
+ strlcpy(old_name_, soname_.c_str(), sizeof(old_name_));
#else
soname_ = soname;
#endif
@@ -704,12 +704,12 @@
const char* soinfo::get_soname() const {
#if defined(__work_around_b_24465209__)
if (has_min_version(2)) {
- return soname_;
+ return soname_.c_str();
} else {
return old_name_;
}
#else
- return soname_;
+ return soname_.c_str();
#endif
}