Merge "Load selinux compat file if it exists"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 2dd22b3..24d4292 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1048,9 +1048,9 @@
// New transport selection protocol:
// This is essentially identical to the previous version, except it returns the selected
// transport id to the caller as well.
- if (ConsumePrefix(&service, "tport:")) {
+ if (android::base::ConsumePrefix(&service, "tport:")) {
legacy = false;
- if (ConsumePrefix(&service, "serial:")) {
+ if (android::base::ConsumePrefix(&service, "serial:")) {
serial_storage = service;
serial = serial_storage.c_str();
} else if (service == "usb") {
@@ -1064,7 +1064,7 @@
// Selection by id is unimplemented, since you obviously already know the transport id
// you're connecting to.
} else {
- if (ConsumePrefix(&service, "transport-id:")) {
+ if (android::base::ConsumePrefix(&service, "transport-id:")) {
if (!ParseUint(&transport_id, service)) {
SendFail(reply_fd, "invalid transport id");
return HostRequestResult::Handled;
@@ -1075,7 +1075,7 @@
type = kTransportLocal;
} else if (service == "transport-any") {
type = kTransportAny;
- } else if (ConsumePrefix(&service, "transport:")) {
+ } else if (android::base::ConsumePrefix(&service, "transport:")) {
serial_storage = service;
serial = serial_storage.c_str();
}
@@ -1216,7 +1216,7 @@
}
// Indicates a new emulator instance has started.
- if (ConsumePrefix(&service, "emulator:")) {
+ if (android::base::ConsumePrefix(&service, "emulator:")) {
unsigned int port;
if (!ParseUint(&port, service)) {
LOG(ERROR) << "received invalid port for emulator: " << service;
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 5800a62..8b0dcee 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -141,11 +141,3 @@
return true;
}
-
-inline bool ConsumePrefix(std::string_view* str, std::string_view prefix) {
- if (str->starts_with(prefix)) {
- str->remove_prefix(prefix.size());
- return true;
- }
- return false;
-}
diff --git a/adb/daemon/abb.cpp b/adb/daemon/abb.cpp
index eeac41a..aa75bb1 100644
--- a/adb/daemon/abb.cpp
+++ b/adb/daemon/abb.cpp
@@ -17,6 +17,7 @@
#include <sys/wait.h>
#include <android-base/cmsg.h>
+#include <android-base/strings.h>
#include <cmd.h>
#include "adb.h"
@@ -87,9 +88,9 @@
std::string_view name = data;
auto protocol = SubprocessProtocol::kShell;
- if (ConsumePrefix(&name, "abb:")) {
+ if (android::base::ConsumePrefix(&name, "abb:")) {
protocol = SubprocessProtocol::kShell;
- } else if (ConsumePrefix(&name, "abb_exec:")) {
+ } else if (android::base::ConsumePrefix(&name, "abb_exec:")) {
protocol = SubprocessProtocol::kNone;
} else {
LOG(FATAL) << "Unknown command prefix for abb: " << data;
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index e82a51f..0e70d47 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -229,17 +229,13 @@
static bool handle_send_file(int s, const char* path, uint32_t* timestamp, uid_t uid, gid_t gid,
uint64_t capabilities, mode_t mode, std::vector<char>& buffer,
bool do_unlink) {
+ int rc;
syncmsg msg;
__android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);
unique_fd fd(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
- if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED) <
- 0) {
- D("[ Failed to fadvise: %d ]", errno);
- }
-
if (fd < 0 && errno == ENOENT) {
if (!secure_mkdirs(Dirname(path))) {
SendSyncFailErrno(s, "secure_mkdirs failed");
@@ -270,6 +266,12 @@
fchmod(fd.get(), mode);
}
+ rc = posix_fadvise(fd.get(), 0, 0,
+ POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED);
+ if (rc != 0) {
+ D("[ Failed to fadvise: %s ]", strerror(rc));
+ }
+
while (true) {
if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
@@ -464,8 +466,9 @@
return false;
}
- if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE) < 0) {
- D("[ Failed to fadvise: %d ]", errno);
+ int rc = posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
+ if (rc != 0) {
+ D("[ Failed to fadvise: %s ]", strerror(rc));
}
syncmsg msg;
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index b0cc450..e6f4499 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -223,13 +223,13 @@
return create_jdwp_service_socket();
} else if (name == "track-jdwp") {
return create_jdwp_tracker_service_socket();
- } else if (ConsumePrefix(&name, "sink:")) {
+ } else if (android::base::ConsumePrefix(&name, "sink:")) {
uint64_t byte_count = 0;
if (!ParseUint(&byte_count, name)) {
return nullptr;
}
return new SinkSocket(byte_count);
- } else if (ConsumePrefix(&name, "source:")) {
+ } else if (android::base::ConsumePrefix(&name, "source:")) {
uint64_t byte_count = 0;
if (!ParseUint(&byte_count, name)) {
return nullptr;
@@ -250,11 +250,11 @@
#if defined(__ANDROID__)
if (name.starts_with("framebuffer:")) {
return create_service_thread("fb", framebuffer_service);
- } else if (ConsumePrefix(&name, "remount:")) {
+ } else if (android::base::ConsumePrefix(&name, "remount:")) {
std::string arg(name);
return create_service_thread("remount",
std::bind(remount_service, std::placeholders::_1, arg));
- } else if (ConsumePrefix(&name, "reboot:")) {
+ } else if (android::base::ConsumePrefix(&name, "reboot:")) {
std::string arg(name);
return create_service_thread("reboot",
std::bind(reboot_service, std::placeholders::_1, arg));
@@ -262,7 +262,7 @@
return create_service_thread("root", restart_root_service);
} else if (name.starts_with("unroot:")) {
return create_service_thread("unroot", restart_unroot_service);
- } else if (ConsumePrefix(&name, "backup:")) {
+ } else if (android::base::ConsumePrefix(&name, "backup:")) {
std::string cmd = "/system/bin/bu backup ";
cmd += name;
return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
@@ -275,7 +275,7 @@
} else if (name.starts_with("enable-verity:")) {
return create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
std::placeholders::_1, true));
- } else if (ConsumePrefix(&name, "tcpip:")) {
+ } else if (android::base::ConsumePrefix(&name, "tcpip:")) {
std::string str(name);
int port;
@@ -289,22 +289,22 @@
}
#endif
- if (ConsumePrefix(&name, "dev:")) {
+ if (android::base::ConsumePrefix(&name, "dev:")) {
return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
- } else if (ConsumePrefix(&name, "jdwp:")) {
+ } else if (android::base::ConsumePrefix(&name, "jdwp:")) {
pid_t pid;
if (!ParseUint(&pid, name)) {
return unique_fd{};
}
return create_jdwp_connection_fd(pid);
- } else if (ConsumePrefix(&name, "shell")) {
+ } else if (android::base::ConsumePrefix(&name, "shell")) {
return ShellService(name, transport);
- } else if (ConsumePrefix(&name, "exec:")) {
+ } else if (android::base::ConsumePrefix(&name, "exec:")) {
return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,
SubprocessProtocol::kNone);
} else if (name.starts_with("sync:")) {
return create_service_thread("sync", file_sync_service);
- } else if (ConsumePrefix(&name, "reverse:")) {
+ } else if (android::base::ConsumePrefix(&name, "reverse:")) {
return reverse_service(name, transport);
} else if (name == "reconnect") {
return create_service_thread(
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index 889229f..49dce66 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -111,8 +111,11 @@
WriteFdFmt(fd, "%s overlayfs for %s\n", enable ? "disabling" : "using", mount_point);
}
} else if (errno) {
- WriteFdFmt(fd, "Overlayfs %s for %s failed with error %s\n", enable ? "teardown" : "setup",
- mount_point, strerror(errno));
+ int expected_errno = enable ? EBUSY : ENOENT;
+ if (errno != expected_errno) {
+ WriteFdFmt(fd, "Overlayfs %s for %s failed with error %s\n",
+ enable ? "teardown" : "setup", mount_point, strerror(errno));
+ }
}
WriteFdFmt(fd, "Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
return true;
diff --git a/adb/services.cpp b/adb/services.cpp
index 46cab6e..6185aa6 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -202,7 +202,7 @@
return create_device_tracker(false);
} else if (name == "track-devices-l") {
return create_device_tracker(true);
- } else if (ConsumePrefix(&name, "wait-for-")) {
+ } else if (android::base::ConsumePrefix(&name, "wait-for-")) {
std::shared_ptr<state_info> sinfo = std::make_shared<state_info>();
if (sinfo == nullptr) {
fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
@@ -212,11 +212,11 @@
sinfo->serial = serial;
sinfo->transport_id = transport_id;
- if (ConsumePrefix(&name, "local")) {
+ if (android::base::ConsumePrefix(&name, "local")) {
sinfo->transport_type = kTransportLocal;
- } else if (ConsumePrefix(&name, "usb")) {
+ } else if (android::base::ConsumePrefix(&name, "usb")) {
sinfo->transport_type = kTransportUsb;
- } else if (ConsumePrefix(&name, "any")) {
+ } else if (android::base::ConsumePrefix(&name, "any")) {
sinfo->transport_type = kTransportAny;
} else {
return nullptr;
@@ -243,7 +243,7 @@
unique_fd fd = create_service_thread(
"wait", [sinfo](unique_fd fd) { wait_for_state(std::move(fd), sinfo.get()); });
return create_local_socket(std::move(fd));
- } else if (ConsumePrefix(&name, "connect:")) {
+ } else if (android::base::ConsumePrefix(&name, "connect:")) {
std::string host(name);
unique_fd fd = create_service_thread(
"connect", std::bind(connect_service, std::placeholders::_1, host));
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 8a2bf9a..75993b3 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -31,6 +31,8 @@
#include <string>
#include <vector>
+#include <android-base/strings.h>
+
#if !ADB_HOST
#include <android-base/properties.h>
#include <log/log_properties.h>
@@ -755,26 +757,26 @@
#if ADB_HOST
service = std::string_view(s->smart_socket_data).substr(4);
- if (ConsumePrefix(&service, "host-serial:")) {
+ if (android::base::ConsumePrefix(&service, "host-serial:")) {
// serial number should follow "host:" and could be a host:port string.
if (!internal::parse_host_service(&serial, &service, service)) {
LOG(ERROR) << "SS(" << s->id << "): failed to parse host service: " << service;
goto fail;
}
- } else if (ConsumePrefix(&service, "host-transport-id:")) {
+ } else if (android::base::ConsumePrefix(&service, "host-transport-id:")) {
if (!ParseUint(&transport_id, service, &service)) {
LOG(ERROR) << "SS(" << s->id << "): failed to parse host transport id: " << service;
return -1;
}
- if (!ConsumePrefix(&service, ":")) {
+ if (!android::base::ConsumePrefix(&service, ":")) {
LOG(ERROR) << "SS(" << s->id << "): host-transport-id without command";
return -1;
}
- } else if (ConsumePrefix(&service, "host-usb:")) {
+ } else if (android::base::ConsumePrefix(&service, "host-usb:")) {
type = kTransportUsb;
- } else if (ConsumePrefix(&service, "host-local:")) {
+ } else if (android::base::ConsumePrefix(&service, "host-local:")) {
type = kTransportLocal;
- } else if (ConsumePrefix(&service, "host:")) {
+ } else if (android::base::ConsumePrefix(&service, "host:")) {
type = kTransportAny;
} else {
service = std::string_view{};
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 8e9716f..b1c22c9 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -18,6 +18,7 @@
#include <sstream>
#include <string>
+#include <string_view>
#include <vector>
namespace android {
@@ -68,5 +69,21 @@
// Tests whether 'lhs' equals 'rhs', ignoring case.
bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs);
+// Removes `prefix` from the start of the given string and returns true (if
+// it was present), false otherwise.
+inline bool ConsumePrefix(std::string_view* s, std::string_view prefix) {
+ if (!StartsWith(*s, prefix)) return false;
+ s->remove_prefix(prefix.size());
+ return true;
+}
+
+// Removes `suffix` from the end of the given string and returns true (if
+// it was present), false otherwise.
+inline bool ConsumeSuffix(std::string_view* s, std::string_view suffix) {
+ if (!EndsWith(*s, suffix)) return false;
+ s->remove_suffix(suffix.size());
+ return true;
+}
+
} // namespace base
} // namespace android
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 9d74094..ca3c0b8 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -295,3 +295,19 @@
TEST(strings, ubsan_28729303) {
android::base::Split("/dev/null", ":");
}
+
+TEST(strings, ConsumePrefix) {
+ std::string_view s{"foo.bar"};
+ ASSERT_FALSE(android::base::ConsumePrefix(&s, "bar."));
+ ASSERT_EQ("foo.bar", s);
+ ASSERT_TRUE(android::base::ConsumePrefix(&s, "foo."));
+ ASSERT_EQ("bar", s);
+}
+
+TEST(strings, ConsumeSuffix) {
+ std::string_view s{"foo.bar"};
+ ASSERT_FALSE(android::base::ConsumeSuffix(&s, ".foo"));
+ ASSERT_EQ("foo.bar", s);
+ ASSERT_TRUE(android::base::ConsumeSuffix(&s, ".bar"));
+ ASSERT_EQ("foo", s);
+}
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 4ee9624..ffde114 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -121,9 +121,14 @@
shared_libs: [
"libbootloader_message",
"libbase",
+ "libcutils",
"libcrypto",
+ "libext4_utils",
"libfec",
"libfs_mgr",
+ "liblog",
+ "liblp",
+ "libselinux",
],
header_libs: [
"libcutils_headers",
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index e46e497..71c4072 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -646,6 +646,25 @@
return true;
}
+static void TruncatePartitionsWithSuffix(MetadataBuilder* builder, const std::string& suffix) {
+ auto& dm = DeviceMapper::Instance();
+
+ // Remove <other> partitions
+ for (const auto& group : builder->ListGroups()) {
+ for (const auto& part : builder->ListPartitionsInGroup(group)) {
+ const auto& name = part->name();
+ if (!android::base::EndsWith(name, suffix)) {
+ continue;
+ }
+ if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name, 2s)) {
+ continue;
+ }
+ builder->ResizePartition(builder->FindPartition(name), 0);
+ }
+ }
+}
+
+// This is where we find and steal backing storage from the system.
bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device,
bool* partition_exists, bool* change) {
*scratch_device = fs_mgr_overlayfs_scratch_device();
@@ -692,15 +711,24 @@
// the adb remount overrides :-( .
auto margin_size = uint64_t(3 * 256 * 1024);
BlockDeviceInfo info;
- if (builder->GetBlockDeviceInfo(partition_name, &info)) {
+ if (builder->GetBlockDeviceInfo(fs_mgr_get_super_partition_name(slot_number), &info)) {
margin_size = 3 * info.logical_block_size;
}
partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size),
partition_size / 2);
if (partition_size > partition->size()) {
if (!builder->ResizePartition(partition, partition_size)) {
- LERROR << "resize " << partition_name;
- return false;
+ // Try to free up space by deallocating partitions in the other slot.
+ TruncatePartitionsWithSuffix(builder.get(), fs_mgr_get_other_slot_suffix());
+
+ partition_size =
+ builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
+ partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size),
+ partition_size / 2);
+ if (!builder->ResizePartition(partition, partition_size)) {
+ LERROR << "resize " << partition_name;
+ return false;
+ }
}
if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
changed = true;
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index cbe2008..00334bc 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -249,6 +249,7 @@
// Check verity and optionally setup overlayfs backing.
auto reboot_later = false;
+ auto user_please_reboot_later = false;
auto uses_overlayfs = fs_mgr_overlayfs_valid() != OverlayfsValidResult::kNotSupported;
for (auto it = partitions.begin(); it != partitions.end();) {
auto& entry = *it;
@@ -262,7 +263,7 @@
false);
avb_ops_user_free(ops);
if (ret) {
- LOG(WARNING) << "Disable verity for " << mount_point;
+ LOG(WARNING) << "Disabling verity for " << mount_point;
reboot_later = can_reboot;
if (reboot_later) {
// w/o overlayfs available, also check for dedupe
@@ -272,20 +273,22 @@
}
reboot(false);
}
+ user_please_reboot_later = true;
} else if (fs_mgr_set_blk_ro(entry.blk_device, false)) {
fec::io fh(entry.blk_device.c_str(), O_RDWR);
if (fh && fh.set_verity_status(false)) {
- LOG(WARNING) << "Disable verity for " << mount_point;
+ LOG(WARNING) << "Disabling verity for " << mount_point;
reboot_later = can_reboot;
if (reboot_later && !uses_overlayfs) {
++it;
continue;
}
+ user_please_reboot_later = true;
}
}
}
}
- LOG(ERROR) << "Skipping " << mount_point;
+ LOG(ERROR) << "Skipping " << mount_point << " for remount";
it = partitions.erase(it);
continue;
}
@@ -307,6 +310,10 @@
if (partitions.empty()) {
if (reboot_later) reboot(false);
+ if (user_please_reboot_later) {
+ LOG(INFO) << "Now reboot your device for settings to take effect";
+ return 0;
+ }
LOG(WARNING) << "No partitions to remount";
return retval;
}
@@ -383,6 +390,10 @@
}
if (reboot_later) reboot(false);
+ if (user_please_reboot_later) {
+ LOG(INFO) << "Now reboot your device for settings to take effect";
+ return 0;
+ }
return retval;
}
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index b2f0ed9..935590d 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -122,9 +122,10 @@
*
* Most callers should use
* [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
- * `<assert.h>` instead, or the `__assert` and `__assert2` functions provided by
- * bionic if more control is needed. They support automatically including the
- * source filename and line number more conveniently than this function.
+ * `<assert.h>` instead, or the `__assert` and `__assert2` functions
+ * provided by bionic if more control is needed. They support automatically
+ * including the source filename and line number more conveniently than this
+ * function.
*/
void __android_log_assert(const char* cond, const char* tag, const char* fmt,
...)
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 66cb49f..4d65b50 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -17,7 +17,9 @@
name: "libnativeloader",
defaults: ["libnativeloader-defaults"],
host_supported: true,
- srcs: ["native_loader.cpp"],
+ srcs: [
+ "native_loader.cpp",
+ ],
shared_libs: [
"libnativehelper",
"liblog",
@@ -26,6 +28,9 @@
],
target: {
android: {
+ srcs: [
+ "library_namespaces.cpp",
+ ],
shared_libs: [
"libdl_android",
],
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
new file mode 100644
index 0000000..3c4911f
--- /dev/null
+++ b/libnativeloader/library_namespaces.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "library_namespaces.h"
+
+#include <dirent.h>
+#include <dlfcn.h>
+
+#include <regex>
+#include <string>
+#include <vector>
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "android-base/properties.h"
+#include "android-base/strings.h"
+#include "nativehelper/ScopedUtfChars.h"
+#include "nativeloader/dlext_namespaces.h"
+
+namespace android {
+
+namespace {
+using namespace std::string_literals;
+
+constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] = "/etc/public.libraries.txt";
+constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-";
+constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen =
+ sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1;
+constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt";
+constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen =
+ sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1;
+constexpr const char kPublicNativeLibrariesVendorConfig[] = "/vendor/etc/public.libraries.txt";
+constexpr const char kLlndkNativeLibrariesSystemConfigPathFromRoot[] = "/etc/llndk.libraries.txt";
+constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] = "/etc/vndksp.libraries.txt";
+
+const std::vector<const std::string> kRuntimePublicLibraries = {
+ "libicuuc.so",
+ "libicui18n.so",
+};
+
+// The device may be configured to have the vendor libraries loaded to a separate namespace.
+// For historical reasons this namespace was named sphal but effectively it is intended
+// to use to load vendor libraries to separate namespace with controlled interface between
+// vendor and system namespaces.
+constexpr const char* kVendorNamespaceName = "sphal";
+constexpr const char* kVndkNamespaceName = "vndk";
+constexpr const char* kDefaultNamespaceName = "default";
+constexpr const char* kPlatformNamespaceName = "platform";
+constexpr const char* kRuntimeNamespaceName = "runtime";
+
+// classloader-namespace is a linker namespace that is created for the loaded
+// app. To be specific, it is created for the app classloader. When
+// System.load() is called from a Java class that is loaded from the
+// classloader, the classloader-namespace namespace associated with that
+// classloader is selected for dlopen. The namespace is configured so that its
+// search path is set to the app-local JNI directory and it is linked to the
+// platform namespace with the names of libs listed in the public.libraries.txt.
+// This way an app can only load its own JNI libraries along with the public libs.
+constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
+// Same thing for vendor APKs.
+constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
+
+// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
+// System.load() with an absolute path which is outside of the classloader library search path.
+// This list includes all directories app is allowed to access this way.
+constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
+
+#if defined(__LP64__)
+constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64";
+constexpr const char* kVendorLibPath = "/vendor/lib64";
+constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64";
+#else
+constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib";
+constexpr const char* kVendorLibPath = "/vendor/lib";
+constexpr const char* kProductLibPath = "/product/lib:/system/product/lib";
+#endif
+
+const std::regex kVendorDexPathRegex("(^|:)/vendor/");
+const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
+
+// Define origin of APK if it is from vendor partition or product partition
+typedef enum {
+ APK_ORIGIN_DEFAULT = 0,
+ APK_ORIGIN_VENDOR = 1,
+ APK_ORIGIN_PRODUCT = 2,
+} ApkOrigin;
+
+bool is_debuggable() {
+ bool debuggable = false;
+ debuggable = android::base::GetBoolProperty("ro.debuggable", false);
+ return debuggable;
+}
+
+std::string vndk_version_str() {
+ std::string version = android::base::GetProperty("ro.vndk.version", "");
+ if (version != "" && version != "current") {
+ return "." + version;
+ }
+ return "";
+}
+
+void insert_vndk_version_str(std::string* file_name) {
+ CHECK(file_name != nullptr);
+ size_t insert_pos = file_name->find_last_of(".");
+ if (insert_pos == std::string::npos) {
+ insert_pos = file_name->length();
+ }
+ file_name->insert(insert_pos, vndk_version_str());
+}
+
+const std::function<bool(const std::string&, std::string*)> always_true =
+ [](const std::string&, std::string*) { return true; };
+
+bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
+ const std::function<bool(const std::string& /* soname */,
+ std::string* /* error_msg */)>& check_soname,
+ std::string* error_msg = nullptr) {
+ // Read list of public native libraries from the config file.
+ std::string file_content;
+ if (!base::ReadFileToString(configFile, &file_content)) {
+ if (error_msg) *error_msg = strerror(errno);
+ return false;
+ }
+
+ std::vector<std::string> lines = base::Split(file_content, "\n");
+
+ for (auto& line : lines) {
+ auto trimmed_line = base::Trim(line);
+ if (trimmed_line[0] == '#' || trimmed_line.empty()) {
+ continue;
+ }
+ size_t space_pos = trimmed_line.rfind(' ');
+ if (space_pos != std::string::npos) {
+ std::string type = trimmed_line.substr(space_pos + 1);
+ if (type != "32" && type != "64") {
+ if (error_msg) *error_msg = "Malformed line: " + line;
+ return false;
+ }
+#if defined(__LP64__)
+ // Skip 32 bit public library.
+ if (type == "32") {
+ continue;
+ }
+#else
+ // Skip 64 bit public library.
+ if (type == "64") {
+ continue;
+ }
+#endif
+ trimmed_line.resize(space_pos);
+ }
+
+ if (check_soname(trimmed_line, error_msg)) {
+ sonames->push_back(trimmed_line);
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
+ if (dir != nullptr) {
+ // Failing to opening the dir is not an error, which can happen in
+ // webview_zygote.
+ while (struct dirent* ent = readdir(dir.get())) {
+ if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
+ continue;
+ }
+ const std::string filename(ent->d_name);
+ if (android::base::StartsWith(filename, kPublicNativeLibrariesExtensionConfigPrefix) &&
+ android::base::EndsWith(filename, kPublicNativeLibrariesExtensionConfigSuffix)) {
+ const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen;
+ const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen;
+ const std::string company_name = filename.substr(start, end - start);
+ const std::string config_file_path = dirname + "/"s + filename;
+ LOG_ALWAYS_FATAL_IF(
+ company_name.empty(),
+ "Error extracting company name from public native library list file path \"%s\"",
+ config_file_path.c_str());
+
+ std::string error_msg;
+
+ LOG_ALWAYS_FATAL_IF(
+ !ReadConfig(config_file_path, sonames,
+ [&company_name](const std::string& soname, std::string* error_msg) {
+ if (android::base::StartsWith(soname, "lib") &&
+ android::base::EndsWith(soname, "." + company_name + ".so")) {
+ return true;
+ } else {
+ *error_msg = "Library name \"" + soname +
+ "\" does not end with the company name: " + company_name +
+ ".";
+ return false;
+ }
+ },
+ &error_msg),
+ "Error reading public native library list from \"%s\": %s", config_file_path.c_str(),
+ error_msg.c_str());
+ }
+ }
+ }
+}
+
+/**
+ * Remove the public libs in runtime namespace
+ */
+void removePublicLibsIfExistsInRuntimeApex(std::vector<std::string>& sonames) {
+ for (const std::string& lib_name : kRuntimePublicLibraries) {
+ std::string path(kRuntimeApexLibPath);
+ path.append("/").append(lib_name);
+
+ struct stat s;
+ // Do nothing if the path in /apex does not exist.
+ // Runtime APEX must be mounted since libnativeloader is in the same APEX
+ if (stat(path.c_str(), &s) != 0) {
+ continue;
+ }
+
+ auto it = std::find(sonames.begin(), sonames.end(), lib_name);
+ if (it != sonames.end()) {
+ sonames.erase(it);
+ }
+ }
+}
+
+jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
+ jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
+ jmethodID get_parent =
+ env->GetMethodID(class_loader_class, "getParent", "()Ljava/lang/ClassLoader;");
+
+ return env->CallObjectMethod(class_loader, get_parent);
+}
+
+ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
+ ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
+
+ if (dex_path != nullptr) {
+ ScopedUtfChars dex_path_utf_chars(env, dex_path);
+
+ if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
+ apk_origin = APK_ORIGIN_VENDOR;
+ }
+
+ if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
+ LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
+ "Dex path contains both vendor and product partition : %s",
+ dex_path_utf_chars.c_str());
+
+ apk_origin = APK_ORIGIN_PRODUCT;
+ }
+ }
+ return apk_origin;
+}
+
+} // namespace
+
+void LibraryNamespaces::Initialize() {
+ // Once public namespace is initialized there is no
+ // point in running this code - it will have no effect
+ // on the current list of public libraries.
+ if (initialized_) {
+ return;
+ }
+
+ std::vector<std::string> sonames;
+ const char* android_root_env = getenv("ANDROID_ROOT");
+ std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
+ std::string public_native_libraries_system_config =
+ root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
+ std::string runtime_public_libraries = base::Join(kRuntimePublicLibraries, ":");
+ std::string llndk_native_libraries_system_config =
+ root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot;
+ std::string vndksp_native_libraries_system_config =
+ root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot;
+
+ std::string product_public_native_libraries_dir = "/product/etc";
+
+ std::string error_msg;
+ LOG_ALWAYS_FATAL_IF(
+ !ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg),
+ "Error reading public native library list from \"%s\": %s",
+ public_native_libraries_system_config.c_str(), error_msg.c_str());
+
+ // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
+ // variable to add libraries to the list. This is intended for platform tests only.
+ if (is_debuggable()) {
+ const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
+ if (additional_libs != nullptr && additional_libs[0] != '\0') {
+ std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
+ std::copy(additional_libs_vector.begin(), additional_libs_vector.end(),
+ std::back_inserter(sonames));
+ // Apply the same list to the runtime namespace, since some libraries
+ // might reside there.
+ CHECK(sizeof(kRuntimePublicLibraries) > 0);
+ runtime_public_libraries = runtime_public_libraries + ':' + additional_libs;
+ }
+ }
+
+ // Remove the public libs in the runtime namespace.
+ // These libs are listed in public.android.txt, but we don't want the rest of android
+ // in default namespace to dlopen the libs.
+ // For example, libicuuc.so is exposed to classloader namespace from runtime namespace.
+ // Unfortunately, it does not have stable C symbols, and default namespace should only use
+ // stable symbols in libandroidicu.so. http://b/120786417
+ removePublicLibsIfExistsInRuntimeApex(sonames);
+
+ // android_init_namespaces() expects all the public libraries
+ // to be loaded so that they can be found by soname alone.
+ //
+ // TODO(dimitry): this is a bit misleading since we do not know
+ // if the vendor public library is going to be opened from /vendor/lib
+ // we might as well end up loading them from /system/lib or /product/lib
+ // For now we rely on CTS test to catch things like this but
+ // it should probably be addressed in the future.
+ for (const auto& soname : sonames) {
+ LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
+ "Error preloading public library %s: %s", soname.c_str(), dlerror());
+ }
+
+ system_public_libraries_ = base::Join(sonames, ':');
+ runtime_public_libraries_ = runtime_public_libraries;
+
+ // read /system/etc/public.libraries-<companyname>.txt which contain partner defined
+ // system libs that are exposed to apps. The libs in the txt files must be
+ // named as lib<name>.<companyname>.so.
+ sonames.clear();
+ ReadExtensionLibraries(base::Dirname(public_native_libraries_system_config).c_str(), &sonames);
+ oem_public_libraries_ = base::Join(sonames, ':');
+
+ // read /product/etc/public.libraries-<companyname>.txt which contain partner defined
+ // product libs that are exposed to apps.
+ sonames.clear();
+ ReadExtensionLibraries(product_public_native_libraries_dir.c_str(), &sonames);
+ product_public_libraries_ = base::Join(sonames, ':');
+
+ // Insert VNDK version to llndk and vndksp config file names.
+ insert_vndk_version_str(&llndk_native_libraries_system_config);
+ insert_vndk_version_str(&vndksp_native_libraries_system_config);
+
+ sonames.clear();
+ ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
+ system_llndk_libraries_ = base::Join(sonames, ':');
+
+ sonames.clear();
+ ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true);
+ system_vndksp_libraries_ = base::Join(sonames, ':');
+
+ sonames.clear();
+ // This file is optional, quietly ignore if the file does not exist.
+ ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr);
+
+ vendor_public_libraries_ = base::Join(sonames, ':');
+}
+
+NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
+ jobject class_loader, bool is_shared,
+ jstring dex_path, jstring java_library_path,
+ jstring java_permitted_path,
+ std::string* error_msg) {
+ std::string library_path; // empty string by default.
+
+ if (java_library_path != nullptr) {
+ ScopedUtfChars library_path_utf_chars(env, java_library_path);
+ library_path = library_path_utf_chars.c_str();
+ }
+
+ ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
+
+ // (http://b/27588281) This is a workaround for apps using custom
+ // classloaders and calling System.load() with an absolute path which
+ // is outside of the classloader library search path.
+ //
+ // This part effectively allows such a classloader to access anything
+ // under /data and /mnt/expand
+ std::string permitted_path = kWhitelistedDirectories;
+
+ if (java_permitted_path != nullptr) {
+ ScopedUtfChars path(env, java_permitted_path);
+ if (path.c_str() != nullptr && path.size() > 0) {
+ permitted_path = permitted_path + ":" + path.c_str();
+ }
+ }
+
+ // Initialize the anonymous namespace with the first non-empty library path.
+ if (!library_path.empty() && !initialized_ &&
+ !InitPublicNamespace(library_path.c_str(), error_msg)) {
+ return nullptr;
+ }
+
+ bool found = FindNamespaceByClassLoader(env, class_loader);
+
+ LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader");
+
+ uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
+ if (is_shared) {
+ namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
+ }
+
+ if (target_sdk_version < 24) {
+ namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
+ }
+
+ NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+
+ bool is_native_bridge = false;
+
+ if (parent_ns != nullptr) {
+ is_native_bridge = !parent_ns->is_android_namespace();
+ } else if (!library_path.empty()) {
+ is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
+ }
+
+ std::string system_exposed_libraries = system_public_libraries_;
+ const char* namespace_name = kClassloaderNamespaceName;
+ android_namespace_t* vndk_ns = nullptr;
+ if ((apk_origin == APK_ORIGIN_VENDOR ||
+ (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
+ !is_shared) {
+ LOG_FATAL_IF(is_native_bridge,
+ "Unbundled vendor / product apk must not use translated architecture");
+
+ // For vendor / product apks, give access to the vendor / product lib even though
+ // they are treated as unbundled; the libs and apks are still bundled
+ // together in the vendor / product partition.
+ const char* origin_partition;
+ const char* origin_lib_path;
+
+ switch (apk_origin) {
+ case APK_ORIGIN_VENDOR:
+ origin_partition = "vendor";
+ origin_lib_path = kVendorLibPath;
+ break;
+ case APK_ORIGIN_PRODUCT:
+ origin_partition = "product";
+ origin_lib_path = kProductLibPath;
+ break;
+ default:
+ origin_partition = "unknown";
+ origin_lib_path = "";
+ }
+
+ LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture",
+ origin_partition);
+
+ library_path = library_path + ":" + origin_lib_path;
+ permitted_path = permitted_path + ":" + origin_lib_path;
+
+ // Also give access to LLNDK libraries since they are available to vendors
+ system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str();
+
+ // Give access to VNDK-SP libraries from the 'vndk' namespace.
+ vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
+ if (vndk_ns == nullptr) {
+ ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition);
+ }
+
+ // Different name is useful for debugging
+ namespace_name = kVendorClassloaderNamespaceName;
+ ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
+ origin_partition, library_path.c_str());
+ } else {
+ // oem and product public libraries are NOT available to vendor apks, otherwise it
+ // would be system->vendor violation.
+ if (!oem_public_libraries_.empty()) {
+ system_exposed_libraries = system_exposed_libraries + ':' + oem_public_libraries_;
+ }
+ if (!product_public_libraries_.empty()) {
+ system_exposed_libraries = system_exposed_libraries + ':' + product_public_libraries_;
+ }
+ }
+ std::string runtime_exposed_libraries = runtime_public_libraries_;
+
+ NativeLoaderNamespace native_loader_ns;
+ if (!is_native_bridge) {
+ // The platform namespace is called "default" for binaries in /system and
+ // "platform" for those in the Runtime APEX. Try "platform" first since
+ // "default" always exists.
+ android_namespace_t* platform_ns = android_get_exported_namespace(kPlatformNamespaceName);
+ if (platform_ns == nullptr) {
+ platform_ns = android_get_exported_namespace(kDefaultNamespaceName);
+ }
+
+ android_namespace_t* android_parent_ns;
+ if (parent_ns != nullptr) {
+ android_parent_ns = parent_ns->get_android_ns();
+ } else {
+ // Fall back to the platform namespace if no parent is found.
+ android_parent_ns = platform_ns;
+ }
+
+ android_namespace_t* ns =
+ android_create_namespace(namespace_name, nullptr, library_path.c_str(), namespace_type,
+ permitted_path.c_str(), android_parent_ns);
+ if (ns == nullptr) {
+ *error_msg = dlerror();
+ return nullptr;
+ }
+
+ // Note that when vendor_ns is not configured this function will return nullptr
+ // and it will result in linking vendor_public_libraries_ to the default namespace
+ // which is expected behavior in this case.
+ android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName);
+
+ android_namespace_t* runtime_ns = android_get_exported_namespace(kRuntimeNamespaceName);
+
+ if (!android_link_namespaces(ns, platform_ns, system_exposed_libraries.c_str())) {
+ *error_msg = dlerror();
+ return nullptr;
+ }
+
+ // Runtime apex does not exist in host, and under certain build conditions.
+ if (runtime_ns != nullptr) {
+ if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
+ *error_msg = dlerror();
+ return nullptr;
+ }
+ }
+
+ if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
+ // vendor apks are allowed to use VNDK-SP libraries.
+ if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
+ *error_msg = dlerror();
+ return nullptr;
+ }
+ }
+
+ if (!vendor_public_libraries_.empty()) {
+ if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
+ *error_msg = dlerror();
+ return nullptr;
+ }
+ }
+
+ native_loader_ns = NativeLoaderNamespace(ns);
+ } else {
+ // Same functionality as in the branch above, but calling through native bridge.
+
+ native_bridge_namespace_t* platform_ns =
+ NativeBridgeGetExportedNamespace(kPlatformNamespaceName);
+ if (platform_ns == nullptr) {
+ platform_ns = NativeBridgeGetExportedNamespace(kDefaultNamespaceName);
+ }
+
+ native_bridge_namespace_t* native_bridge_parent_namespace;
+ if (parent_ns != nullptr) {
+ native_bridge_parent_namespace = parent_ns->get_native_bridge_ns();
+ } else {
+ native_bridge_parent_namespace = platform_ns;
+ }
+
+ native_bridge_namespace_t* ns =
+ NativeBridgeCreateNamespace(namespace_name, nullptr, library_path.c_str(), namespace_type,
+ permitted_path.c_str(), native_bridge_parent_namespace);
+ if (ns == nullptr) {
+ *error_msg = NativeBridgeGetError();
+ return nullptr;
+ }
+
+ native_bridge_namespace_t* vendor_ns = NativeBridgeGetExportedNamespace(kVendorNamespaceName);
+ native_bridge_namespace_t* runtime_ns = NativeBridgeGetExportedNamespace(kRuntimeNamespaceName);
+
+ if (!NativeBridgeLinkNamespaces(ns, platform_ns, system_exposed_libraries.c_str())) {
+ *error_msg = NativeBridgeGetError();
+ return nullptr;
+ }
+
+ // Runtime apex does not exist in host, and under certain build conditions.
+ if (runtime_ns != nullptr) {
+ if (!NativeBridgeLinkNamespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
+ *error_msg = NativeBridgeGetError();
+ return nullptr;
+ }
+ }
+ if (!vendor_public_libraries_.empty()) {
+ if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
+ *error_msg = NativeBridgeGetError();
+ return nullptr;
+ }
+ }
+
+ native_loader_ns = NativeLoaderNamespace(ns);
+ }
+
+ namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
+
+ return &(namespaces_.back().second);
+}
+
+NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env,
+ jobject class_loader) {
+ auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
+ [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
+ return env->IsSameObject(value.first, class_loader);
+ });
+ if (it != namespaces_.end()) {
+ return &it->second;
+ }
+
+ return nullptr;
+}
+
+bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::string* error_msg) {
+ // 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(system_public_libraries_.c_str(),
+ is_native_bridge ? nullptr : library_path);
+ if (!initialized_) {
+ *error_msg = dlerror();
+ return false;
+ }
+
+ // and now initialize native bridge namespaces if necessary.
+ if (NativeBridgeInitialized()) {
+ initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries_.c_str(),
+ is_native_bridge ? library_path : nullptr);
+ if (!initialized_) {
+ *error_msg = NativeBridgeGetError();
+ }
+ }
+
+ return initialized_;
+}
+
+NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
+ jobject class_loader) {
+ jobject parent_class_loader = GetParentClassLoader(env, class_loader);
+
+ while (parent_class_loader != nullptr) {
+ NativeLoaderNamespace* ns;
+ if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
+ return ns;
+ }
+
+ parent_class_loader = GetParentClassLoader(env, parent_class_loader);
+ }
+
+ return nullptr;
+}
+
+} // namespace android
diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h
new file mode 100644
index 0000000..353b5fc
--- /dev/null
+++ b/libnativeloader/library_namespaces.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+#if !defined(__ANDROID__)
+#error "Not available for host"
+#endif
+
+#include "native_loader_namespace.h"
+
+#include <list>
+#include <string>
+
+#include "jni.h"
+
+namespace android {
+
+// LibraryNamespaces is a singleton object that manages NativeLoaderNamespace
+// objects for an app process. Its main job is to create (and configure) a new
+// NativeLoaderNamespace object for a Java ClassLoader, and to find an existing
+// object for a given ClassLoader.
+class LibraryNamespaces {
+ public:
+ LibraryNamespaces() : initialized_(false) {}
+
+ LibraryNamespaces(LibraryNamespaces&&) = default;
+ LibraryNamespaces(const LibraryNamespaces&) = delete;
+ LibraryNamespaces& operator=(const LibraryNamespaces&) = delete;
+
+ void Initialize();
+ void Reset() { namespaces_.clear(); }
+ NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
+ bool is_shared, jstring dex_path, jstring java_library_path,
+ jstring java_permitted_path, std::string* error_msg);
+ NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+
+ private:
+ bool InitPublicNamespace(const char* library_path, std::string* error_msg);
+ NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+
+ bool initialized_;
+ std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
+ std::string system_public_libraries_;
+ std::string runtime_public_libraries_;
+ std::string vendor_public_libraries_;
+ std::string oem_public_libraries_;
+ std::string product_public_libraries_;
+ std::string system_llndk_libraries_;
+ std::string system_vndksp_libraries_;
+};
+
+} // namespace android
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 1012ea0..ed98714 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -15,742 +15,59 @@
*/
#include "nativeloader/native_loader.h"
-#include <nativehelper/ScopedUtfChars.h>
+#define LOG_TAG "nativeloader"
#include <dlfcn.h>
-#ifdef __ANDROID__
-#define LOG_TAG "libnativeloader"
-#include "nativeloader/dlext_namespaces.h"
-#include "log/log.h"
-#endif
-#include <dirent.h>
#include <sys/types.h>
-#include "nativebridge/native_bridge.h"
-#include <algorithm>
-#include <list>
#include <memory>
#include <mutex>
-#include <regex>
#include <string>
#include <vector>
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/strings.h>
-
-#ifdef __BIONIC__
-#include <android-base/properties.h>
+#include "android-base/file.h"
+#include "android-base/macros.h"
+#include "android-base/strings.h"
+#ifdef __ANDROID__
+#include "library_namespaces.h"
+#include "log/log.h"
+#include "nativeloader/dlext_namespaces.h"
#endif
-
-#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
- "%s:%d: %s CHECK '" #predicate "' failed.",\
- __FILE__, __LINE__, __FUNCTION__)
-
-using namespace std::string_literals;
+#include "nativebridge/native_bridge.h"
+#include "nativehelper/ScopedUtfChars.h"
namespace android {
+namespace {
#if defined(__ANDROID__)
-struct NativeLoaderNamespace {
- public:
- NativeLoaderNamespace()
- : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
+constexpr const char* kApexPath = "/apex/";
- explicit NativeLoaderNamespace(android_namespace_t* ns)
- : android_ns_(ns), native_bridge_ns_(nullptr) { }
+std::mutex g_namespaces_mutex;
+LibraryNamespaces* g_namespaces = new LibraryNamespaces;
- explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
- : android_ns_(nullptr), native_bridge_ns_(ns) { }
-
- NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
- NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
-
- NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
-
- android_namespace_t* get_android_ns() const {
- CHECK(native_bridge_ns_ == nullptr);
- return android_ns_;
+android_namespace_t* FindExportedNamespace(const char* caller_location) {
+ std::string location = caller_location;
+ // Lots of implicit assumptions here: we expect `caller_location` to be of the form:
+ // /apex/com.android...modulename/...
+ //
+ // And we extract from it 'modulename', which is the name of the linker namespace.
+ if (android::base::StartsWith(location, kApexPath)) {
+ size_t slash_index = location.find_first_of('/', strlen(kApexPath));
+ LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
+ "Error finding namespace of apex: no slash in path %s", caller_location);
+ size_t dot_index = location.find_last_of('.', slash_index);
+ LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
+ "Error finding namespace of apex: no dot in apex name %s", caller_location);
+ std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
+ android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
+ LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
+ "Error finding namespace of apex: no namespace called %s", name.c_str());
+ return boot_namespace;
}
-
- native_bridge_namespace_t* get_native_bridge_ns() const {
- CHECK(android_ns_ == nullptr);
- return native_bridge_ns_;
- }
-
- bool is_android_namespace() const {
- return native_bridge_ns_ == nullptr;
- }
-
- private:
- // Only one of them can be not null
- android_namespace_t* android_ns_;
- native_bridge_namespace_t* native_bridge_ns_;
-};
-
-static constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] =
- "/etc/public.libraries.txt";
-static constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-";
-static constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen =
- sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1;
-static constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt";
-static constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen =
- sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1;
-static constexpr const char kPublicNativeLibrariesVendorConfig[] =
- "/vendor/etc/public.libraries.txt";
-static constexpr const char kLlndkNativeLibrariesSystemConfigPathFromRoot[] =
- "/etc/llndk.libraries.txt";
-static constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] =
- "/etc/vndksp.libraries.txt";
-
-static const std::vector<const std::string> kRuntimePublicLibraries = {
- "libicuuc.so",
- "libicui18n.so",
-};
-
-// The device may be configured to have the vendor libraries loaded to a separate namespace.
-// For historical reasons this namespace was named sphal but effectively it is intended
-// to use to load vendor libraries to separate namespace with controlled interface between
-// vendor and system namespaces.
-static constexpr const char* kVendorNamespaceName = "sphal";
-
-static constexpr const char* kVndkNamespaceName = "vndk";
-
-static constexpr const char* kDefaultNamespaceName = "default";
-static constexpr const char* kPlatformNamespaceName = "platform";
-static constexpr const char* kRuntimeNamespaceName = "runtime";
-
-// classloader-namespace is a linker namespace that is created for the loaded
-// app. To be specific, it is created for the app classloader. When
-// System.load() is called from a Java class that is loaded from the
-// classloader, the classloader-namespace namespace associated with that
-// classloader is selected for dlopen. The namespace is configured so that its
-// search path is set to the app-local JNI directory and it is linked to the
-// platform namespace with the names of libs listed in the public.libraries.txt.
-// This way an app can only load its own JNI libraries along with the public libs.
-static constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
-// Same thing for vendor APKs.
-static constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
-
-// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
-// System.load() with an absolute path which is outside of the classloader library search path.
-// This list includes all directories app is allowed to access this way.
-static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
-
-static constexpr const char* kApexPath = "/apex/";
-
-#if defined(__LP64__)
-static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64";
-static constexpr const char* kVendorLibPath = "/vendor/lib64";
-static constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64";
-#else
-static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib";
-static constexpr const char* kVendorLibPath = "/vendor/lib";
-static constexpr const char* kProductLibPath = "/product/lib:/system/product/lib";
-#endif
-
-static const std::regex kVendorDexPathRegex("(^|:)/vendor/");
-static const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
-
-// Define origin of APK if it is from vendor partition or product partition
-typedef enum {
- APK_ORIGIN_DEFAULT = 0,
- APK_ORIGIN_VENDOR = 1,
- APK_ORIGIN_PRODUCT = 2,
-} ApkOrigin;
-
-static bool is_debuggable() {
- bool debuggable = false;
-#ifdef __BIONIC__
- debuggable = android::base::GetBoolProperty("ro.debuggable", false);
-#endif
- return debuggable;
+ return nullptr;
}
-
-static std::string vndk_version_str() {
-#ifdef __BIONIC__
- std::string version = android::base::GetProperty("ro.vndk.version", "");
- if (version != "" && version != "current") {
- return "." + version;
- }
-#endif
- return "";
-}
-
-static void insert_vndk_version_str(std::string* file_name) {
- CHECK(file_name != nullptr);
- size_t insert_pos = file_name->find_last_of(".");
- if (insert_pos == std::string::npos) {
- insert_pos = file_name->length();
- }
- file_name->insert(insert_pos, vndk_version_str());
-}
-
-static const std::function<bool(const std::string&, std::string*)> always_true =
- [](const std::string&, std::string*) { return true; };
-
-class LibraryNamespaces {
- public:
- LibraryNamespaces() : initialized_(false) { }
-
- NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
- bool is_shared, jstring dex_path, jstring java_library_path,
- jstring java_permitted_path, std::string* error_msg) {
- std::string library_path; // empty string by default.
-
- if (java_library_path != nullptr) {
- ScopedUtfChars library_path_utf_chars(env, java_library_path);
- library_path = library_path_utf_chars.c_str();
- }
-
- ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
-
- // (http://b/27588281) This is a workaround for apps using custom
- // classloaders and calling System.load() with an absolute path which
- // is outside of the classloader library search path.
- //
- // This part effectively allows such a classloader to access anything
- // under /data and /mnt/expand
- std::string permitted_path = kWhitelistedDirectories;
-
- if (java_permitted_path != nullptr) {
- ScopedUtfChars path(env, java_permitted_path);
- if (path.c_str() != nullptr && path.size() > 0) {
- permitted_path = permitted_path + ":" + path.c_str();
- }
- }
-
- // Initialize the anonymous namespace with the first non-empty library path.
- if (!library_path.empty() && !initialized_ &&
- !InitPublicNamespace(library_path.c_str(), error_msg)) {
- return nullptr;
- }
-
- bool found = FindNamespaceByClassLoader(env, class_loader);
-
- LOG_ALWAYS_FATAL_IF(found,
- "There is already a namespace associated with this classloader");
-
- uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
- if (is_shared) {
- namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
- }
-
- if (target_sdk_version < 24) {
- namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
- }
-
- NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
-
- bool is_native_bridge = false;
-
- if (parent_ns != nullptr) {
- is_native_bridge = !parent_ns->is_android_namespace();
- } else if (!library_path.empty()) {
- is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
- }
-
- std::string system_exposed_libraries = system_public_libraries_;
- const char* namespace_name = kClassloaderNamespaceName;
- android_namespace_t* vndk_ns = nullptr;
- if ((apk_origin == APK_ORIGIN_VENDOR ||
- (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
- !is_shared) {
- LOG_FATAL_IF(is_native_bridge,
- "Unbundled vendor / product apk must not use translated architecture");
-
- // For vendor / product apks, give access to the vendor / product lib even though
- // they are treated as unbundled; the libs and apks are still bundled
- // together in the vendor / product partition.
- const char* origin_partition;
- const char* origin_lib_path;
-
- switch (apk_origin) {
- case APK_ORIGIN_VENDOR:
- origin_partition = "vendor";
- origin_lib_path = kVendorLibPath;
- break;
- case APK_ORIGIN_PRODUCT:
- origin_partition = "product";
- origin_lib_path = kProductLibPath;
- break;
- default:
- origin_partition = "unknown";
- origin_lib_path = "";
- }
-
- LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture",
- origin_partition);
-
- library_path = library_path + ":" + origin_lib_path;
- permitted_path = permitted_path + ":" + origin_lib_path;
-
- // Also give access to LLNDK libraries since they are available to vendors
- system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str();
-
- // Give access to VNDK-SP libraries from the 'vndk' namespace.
- vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
- if (vndk_ns == nullptr) {
- ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition);
- }
-
- // Different name is useful for debugging
- namespace_name = kVendorClassloaderNamespaceName;
- ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
- origin_partition, library_path.c_str());
- } else {
- // oem and product public libraries are NOT available to vendor apks, otherwise it
- // would be system->vendor violation.
- if (!oem_public_libraries_.empty()) {
- system_exposed_libraries = system_exposed_libraries + ':' + oem_public_libraries_;
- }
- if (!product_public_libraries_.empty()) {
- system_exposed_libraries = system_exposed_libraries + ':' + product_public_libraries_;
- }
- }
-
- std::string runtime_exposed_libraries = runtime_public_libraries_;
-
- NativeLoaderNamespace native_loader_ns;
- if (!is_native_bridge) {
- // The platform namespace is called "default" for binaries in /system and
- // "platform" for those in the Runtime APEX. Try "platform" first since
- // "default" always exists.
- android_namespace_t* platform_ns = android_get_exported_namespace(kPlatformNamespaceName);
- if (platform_ns == nullptr) {
- platform_ns = android_get_exported_namespace(kDefaultNamespaceName);
- }
-
- android_namespace_t* android_parent_ns;
- if (parent_ns != nullptr) {
- android_parent_ns = parent_ns->get_android_ns();
- } else {
- // Fall back to the platform namespace if no parent is found.
- android_parent_ns = platform_ns;
- }
-
- android_namespace_t* ns = android_create_namespace(namespace_name,
- nullptr,
- library_path.c_str(),
- namespace_type,
- permitted_path.c_str(),
- android_parent_ns);
- if (ns == nullptr) {
- *error_msg = dlerror();
- return nullptr;
- }
-
- // Note that when vendor_ns is not configured this function will return nullptr
- // and it will result in linking vendor_public_libraries_ to the default namespace
- // which is expected behavior in this case.
- android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName);
-
- android_namespace_t* runtime_ns = android_get_exported_namespace(kRuntimeNamespaceName);
-
- if (!android_link_namespaces(ns, platform_ns, system_exposed_libraries.c_str())) {
- *error_msg = dlerror();
- return nullptr;
- }
-
- // Runtime apex does not exist in host, and under certain build conditions.
- if (runtime_ns != nullptr) {
- if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
- *error_msg = dlerror();
- return nullptr;
- }
- }
-
- if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
- // vendor apks are allowed to use VNDK-SP libraries.
- if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
- *error_msg = dlerror();
- return nullptr;
- }
- }
-
- if (!vendor_public_libraries_.empty()) {
- if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
- *error_msg = dlerror();
- return nullptr;
- }
- }
-
- native_loader_ns = NativeLoaderNamespace(ns);
- } else {
- // Same functionality as in the branch above, but calling through native bridge.
-
- native_bridge_namespace_t* platform_ns =
- NativeBridgeGetExportedNamespace(kPlatformNamespaceName);
- if (platform_ns == nullptr) {
- platform_ns = NativeBridgeGetExportedNamespace(kDefaultNamespaceName);
- }
-
- native_bridge_namespace_t* native_bridge_parent_namespace;
- if (parent_ns != nullptr) {
- native_bridge_parent_namespace = parent_ns->get_native_bridge_ns();
- } else {
- native_bridge_parent_namespace = platform_ns;
- }
-
- native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
- nullptr,
- library_path.c_str(),
- namespace_type,
- permitted_path.c_str(),
- native_bridge_parent_namespace);
- if (ns == nullptr) {
- *error_msg = NativeBridgeGetError();
- return nullptr;
- }
-
- native_bridge_namespace_t* vendor_ns = NativeBridgeGetExportedNamespace(kVendorNamespaceName);
- native_bridge_namespace_t* runtime_ns =
- NativeBridgeGetExportedNamespace(kRuntimeNamespaceName);
-
- if (!NativeBridgeLinkNamespaces(ns, platform_ns, system_exposed_libraries.c_str())) {
- *error_msg = NativeBridgeGetError();
- return nullptr;
- }
-
- // Runtime apex does not exist in host, and under certain build conditions.
- if (runtime_ns != nullptr) {
- if (!NativeBridgeLinkNamespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
- *error_msg = NativeBridgeGetError();
- return nullptr;
- }
- }
- if (!vendor_public_libraries_.empty()) {
- if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
- *error_msg = NativeBridgeGetError();
- return nullptr;
- }
- }
-
- native_loader_ns = NativeLoaderNamespace(ns);
- }
-
- namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
-
- return &(namespaces_.back().second);
- }
-
- NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
- auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
- [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
- return env->IsSameObject(value.first, class_loader);
- });
- if (it != namespaces_.end()) {
- return &it->second;
- }
-
- return nullptr;
- }
-
- void Initialize() {
- // Once public namespace is initialized there is no
- // point in running this code - it will have no effect
- // on the current list of public libraries.
- if (initialized_) {
- return;
- }
-
- std::vector<std::string> sonames;
- const char* android_root_env = getenv("ANDROID_ROOT");
- std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
- std::string public_native_libraries_system_config =
- root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
- std::string runtime_public_libraries = base::Join(kRuntimePublicLibraries, ":");
- std::string llndk_native_libraries_system_config =
- root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot;
- std::string vndksp_native_libraries_system_config =
- root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot;
-
- std::string product_public_native_libraries_dir = "/product/etc";
-
- std::string error_msg;
- LOG_ALWAYS_FATAL_IF(
- !ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg),
- "Error reading public native library list from \"%s\": %s",
- public_native_libraries_system_config.c_str(), error_msg.c_str());
-
- // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
- // variable to add libraries to the list. This is intended for platform tests only.
- if (is_debuggable()) {
- const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
- if (additional_libs != nullptr && additional_libs[0] != '\0') {
- std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
- std::copy(additional_libs_vector.begin(), additional_libs_vector.end(),
- std::back_inserter(sonames));
- // Apply the same list to the runtime namespace, since some libraries
- // might reside there.
- CHECK(sizeof(kRuntimePublicLibraries) > 0);
- runtime_public_libraries = runtime_public_libraries + ':' + additional_libs;
- }
- }
-
- // Remove the public libs in the runtime namespace.
- // These libs are listed in public.android.txt, but we don't want the rest of android
- // in default namespace to dlopen the libs.
- // For example, libicuuc.so is exposed to classloader namespace from runtime namespace.
- // Unfortunately, it does not have stable C symbols, and default namespace should only use
- // stable symbols in libandroidicu.so. http://b/120786417
- removePublicLibsIfExistsInRuntimeApex(sonames);
-
- // android_init_namespaces() expects all the public libraries
- // to be loaded so that they can be found by soname alone.
- //
- // TODO(dimitry): this is a bit misleading since we do not know
- // if the vendor public library is going to be opened from /vendor/lib
- // we might as well end up loading them from /system/lib or /product/lib
- // For now we rely on CTS test to catch things like this but
- // it should probably be addressed in the future.
- for (const auto& soname : sonames) {
- LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
- "Error preloading public library %s: %s", soname.c_str(), dlerror());
- }
-
- system_public_libraries_ = base::Join(sonames, ':');
- runtime_public_libraries_ = runtime_public_libraries;
-
- // read /system/etc/public.libraries-<companyname>.txt which contain partner defined
- // system libs that are exposed to apps. The libs in the txt files must be
- // named as lib<name>.<companyname>.so.
- sonames.clear();
- ReadExtensionLibraries(base::Dirname(public_native_libraries_system_config).c_str(), &sonames);
- oem_public_libraries_ = base::Join(sonames, ':');
-
- // read /product/etc/public.libraries-<companyname>.txt which contain partner defined
- // product libs that are exposed to apps.
- sonames.clear();
- ReadExtensionLibraries(product_public_native_libraries_dir.c_str(), &sonames);
- product_public_libraries_ = base::Join(sonames, ':');
-
- // Insert VNDK version to llndk and vndksp config file names.
- insert_vndk_version_str(&llndk_native_libraries_system_config);
- insert_vndk_version_str(&vndksp_native_libraries_system_config);
-
- sonames.clear();
- ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
- system_llndk_libraries_ = base::Join(sonames, ':');
-
- sonames.clear();
- ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true);
- system_vndksp_libraries_ = base::Join(sonames, ':');
-
- sonames.clear();
- // This file is optional, quietly ignore if the file does not exist.
- ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr);
-
- vendor_public_libraries_ = base::Join(sonames, ':');
- }
-
- void Reset() { namespaces_.clear(); }
-
- private:
- void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
- if (dir != nullptr) {
- // Failing to opening the dir is not an error, which can happen in
- // webview_zygote.
- while (struct dirent* ent = readdir(dir.get())) {
- if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
- continue;
- }
- const std::string filename(ent->d_name);
- if (android::base::StartsWith(filename, kPublicNativeLibrariesExtensionConfigPrefix) &&
- android::base::EndsWith(filename, kPublicNativeLibrariesExtensionConfigSuffix)) {
- const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen;
- const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen;
- const std::string company_name = filename.substr(start, end - start);
- const std::string config_file_path = dirname + "/"s + filename;
- LOG_ALWAYS_FATAL_IF(
- company_name.empty(),
- "Error extracting company name from public native library list file path \"%s\"",
- config_file_path.c_str());
-
- std::string error_msg;
-
- LOG_ALWAYS_FATAL_IF(
- !ReadConfig(
- config_file_path, sonames,
- [&company_name](const std::string& soname, std::string* error_msg) {
- if (android::base::StartsWith(soname, "lib") &&
- android::base::EndsWith(soname, "." + company_name + ".so")) {
- return true;
- } else {
- *error_msg = "Library name \"" + soname +
- "\" does not end with the company name: " + company_name + ".";
- return false;
- }
- },
- &error_msg),
- "Error reading public native library list from \"%s\": %s", config_file_path.c_str(),
- error_msg.c_str());
- }
- }
- }
- }
-
- /**
- * Remove the public libs in runtime namespace
- */
- void removePublicLibsIfExistsInRuntimeApex(std::vector<std::string>& sonames) {
- for (const std::string& lib_name : kRuntimePublicLibraries) {
- std::string path(kRuntimeApexLibPath);
- path.append("/").append(lib_name);
-
- struct stat s;
- // Do nothing if the path in /apex does not exist.
- // Runtime APEX must be mounted since libnativeloader is in the same APEX
- if (stat(path.c_str(), &s) != 0) {
- continue;
- }
-
- auto it = std::find(sonames.begin(), sonames.end(), lib_name);
- if (it != sonames.end()) {
- sonames.erase(it);
- }
- }
- }
-
- bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
- const std::function<bool(const std::string& /* soname */,
- std::string* /* error_msg */)>& check_soname,
- std::string* error_msg = nullptr) {
- // Read list of public native libraries from the config file.
- std::string file_content;
- if(!base::ReadFileToString(configFile, &file_content)) {
- if (error_msg) *error_msg = strerror(errno);
- return false;
- }
-
- std::vector<std::string> lines = base::Split(file_content, "\n");
-
- for (auto& line : lines) {
- auto trimmed_line = base::Trim(line);
- if (trimmed_line[0] == '#' || trimmed_line.empty()) {
- continue;
- }
- size_t space_pos = trimmed_line.rfind(' ');
- if (space_pos != std::string::npos) {
- std::string type = trimmed_line.substr(space_pos + 1);
- if (type != "32" && type != "64") {
- if (error_msg) *error_msg = "Malformed line: " + line;
- return false;
- }
-#if defined(__LP64__)
- // Skip 32 bit public library.
- if (type == "32") {
- continue;
- }
-#else
- // Skip 64 bit public library.
- if (type == "64") {
- continue;
- }
-#endif
- trimmed_line.resize(space_pos);
- }
-
- if (check_soname(trimmed_line, error_msg)) {
- sonames->push_back(trimmed_line);
- } else {
- return false;
- }
- }
-
- return true;
- }
-
- bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
- // 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(system_public_libraries_.c_str(),
- is_native_bridge ? nullptr : library_path);
- if (!initialized_) {
- *error_msg = dlerror();
- return false;
- }
-
- // and now initialize native bridge namespaces if necessary.
- if (NativeBridgeInitialized()) {
- initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries_.c_str(),
- is_native_bridge ? library_path : nullptr);
- if (!initialized_) {
- *error_msg = NativeBridgeGetError();
- }
- }
-
- return initialized_;
- }
-
- jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
- jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
- jmethodID get_parent = env->GetMethodID(class_loader_class,
- "getParent",
- "()Ljava/lang/ClassLoader;");
-
- return env->CallObjectMethod(class_loader, get_parent);
- }
-
- NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
- jobject parent_class_loader = GetParentClassLoader(env, class_loader);
-
- while (parent_class_loader != nullptr) {
- NativeLoaderNamespace* ns;
- if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
- return ns;
- }
-
- parent_class_loader = GetParentClassLoader(env, parent_class_loader);
- }
-
- return nullptr;
- }
-
- ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
- ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
-
- if (dex_path != nullptr) {
- ScopedUtfChars dex_path_utf_chars(env, dex_path);
-
- if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
- apk_origin = APK_ORIGIN_VENDOR;
- }
-
- if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
- LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
- "Dex path contains both vendor and product partition : %s",
- dex_path_utf_chars.c_str());
-
- apk_origin = APK_ORIGIN_PRODUCT;
- }
- }
-
- return apk_origin;
- }
-
- bool initialized_;
- std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
- std::string system_public_libraries_;
- std::string runtime_public_libraries_;
- std::string vendor_public_libraries_;
- std::string oem_public_libraries_;
- std::string product_public_libraries_;
- std::string system_llndk_libraries_;
- std::string system_vndksp_libraries_;
-
- DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
-};
-
-static std::mutex g_namespaces_mutex;
-static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
-#endif
+#endif // #if defined(__ANDROID__)
+} // namespace
void InitializeNativeLoader() {
#if defined(__ANDROID__)
@@ -784,30 +101,6 @@
return nullptr;
}
-#if defined(__ANDROID__)
-static android_namespace_t* FindExportedNamespace(const char* caller_location) {
- std::string location = caller_location;
- // Lots of implicit assumptions here: we expect `caller_location` to be of the form:
- // /apex/com.android...modulename/...
- //
- // And we extract from it 'modulename', which is the name of the linker namespace.
- if (android::base::StartsWith(location, kApexPath)) {
- size_t slash_index = location.find_first_of('/', strlen(kApexPath));
- LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
- "Error finding namespace of apex: no slash in path %s", caller_location);
- size_t dot_index = location.find_last_of('.', slash_index);
- LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
- "Error finding namespace of apex: no dot in apex name %s", caller_location);
- std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
- android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
- LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
- "Error finding namespace of apex: no namespace called %s", name.c_str());
- return boot_namespace;
- }
- return nullptr;
-}
-#endif
-
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
jobject class_loader, const char* caller_location, jstring library_path,
bool* needs_native_bridge, char** error_msg) {
@@ -958,10 +251,11 @@
return nullptr;
}
+
NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
}
#endif
-}; // android namespace
+}; // namespace android
diff --git a/libnativeloader/native_loader_namespace.h b/libnativeloader/native_loader_namespace.h
new file mode 100644
index 0000000..71b60d8
--- /dev/null
+++ b/libnativeloader/native_loader_namespace.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+#if defined(__ANDROID__)
+
+#include <dlfcn.h>
+
+#include "android-base/logging.h"
+#include "android/dlext.h"
+#include "log/log.h"
+#include "nativebridge/native_bridge.h"
+
+namespace android {
+
+// NativeLoaderNamespace abstracts a linker namespace for the native
+// architecture (ex: arm on arm) or the translated architecture (ex: arm on
+// x86). Instances of this class are managed by LibraryNamespaces object.
+struct NativeLoaderNamespace {
+ public:
+ NativeLoaderNamespace() : android_ns_(nullptr), native_bridge_ns_(nullptr) {}
+
+ explicit NativeLoaderNamespace(android_namespace_t* ns)
+ : android_ns_(ns), native_bridge_ns_(nullptr) {}
+
+ explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
+ : android_ns_(nullptr), native_bridge_ns_(ns) {}
+
+ NativeLoaderNamespace(NativeLoaderNamespace&&) = default;
+ NativeLoaderNamespace(const NativeLoaderNamespace&) = default;
+ NativeLoaderNamespace& operator=(const NativeLoaderNamespace&) = default;
+
+ android_namespace_t* get_android_ns() const {
+ CHECK(native_bridge_ns_ == nullptr);
+ return android_ns_;
+ }
+
+ native_bridge_namespace_t* get_native_bridge_ns() const {
+ CHECK(android_ns_ == nullptr);
+ return native_bridge_ns_;
+ }
+
+ bool is_android_namespace() const { return native_bridge_ns_ == nullptr; }
+
+ private:
+ // Only one of them can be not null
+ android_namespace_t* android_ns_;
+ native_bridge_namespace_t* native_bridge_ns_;
+};
+
+} // namespace android
+#endif // #if defined(__ANDROID__)
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index cb288c5..24c6379 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -188,7 +188,7 @@
int (*write)(void* priv, const void* data, size_t len,
unsigned int block, unsigned int nr_blocks),
void* priv) {
- int ret;
+ int ret = 0;
int chunks;
struct chunk_data chk;
struct output_file* out;
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 26626b5..37323dc 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -25,6 +25,7 @@
#include <algorithm>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <demangle.h>
@@ -168,7 +169,7 @@
// If this elf is memory backed, and there is a valid file, then set
// an indicator that we couldn't open the file.
if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
- map_info->name[0] != '[') {
+ map_info->name[0] != '[' && !android::base::StartsWith(map_info->name, "/memfd:")) {
elf_from_memory_not_file_ = true;
}
step_pc = regs_->pc();
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index f635021..30e57a1 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -126,6 +126,12 @@
const auto& info5 = *--maps_->end();
info5->memory_backed_elf = true;
+ elf = new ElfFake(new MemoryFake);
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/memfd:/jit-cache", elf);
+ const auto& info6 = *--maps_->end();
+ info6->memory_backed_elf = true;
+
process_memory_.reset(new MemoryFake);
}
@@ -1234,6 +1240,36 @@
EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
+TEST_F(UnwinderTest, elf_from_memory_but_from_memfd) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.set_pc(0xc3050);
+ regs_.set_sp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+ ASSERT_EQ(1U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x50U, frame->rel_pc);
+ EXPECT_EQ(0xc3050U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/memfd:/jit-cache", frame->map_name);
+ EXPECT_EQ(0U, frame->map_elf_start_offset);
+ EXPECT_EQ(0U, frame->map_exact_offset);
+ EXPECT_EQ(0xc3000U, frame->map_start);
+ EXPECT_EQ(0xc4000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
// Verify format frame code.
TEST_F(UnwinderTest, format_frame) {
RegsFake regs_arm(10);