1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/android/bundle_utils.h"
7 #include <android/dlext.h>
10 #include "base/android/jni_android.h"
11 #include "base/android/jni_string.h"
12 #include "base/base_jni/BundleUtils_jni.h"
13 #include "base/check.h"
14 #include "base/files/file_path.h"
15 #include "base/notreached.h"
17 // These symbols are added by the lld linker when creating a partitioned shared
18 // library. The symbols live in the base library, and are used to properly load
19 // the other partitions (feature libraries) when needed.
20 struct PartitionIndexEntry {
25 static_assert(sizeof(PartitionIndexEntry) == 12U,
26 "Unexpected PartitionIndexEntry size");
28 // Marked as weak_import because these symbols are lld-specific. The method that
29 // uses them will only be invoked in builds that have lld-generated partitions.
30 extern PartitionIndexEntry __part_index_begin[] __attribute__((weak_import));
31 extern PartitionIndexEntry __part_index_end[] __attribute__((weak_import));
38 const void* ReadRelPtr(const int32_t* relptr) {
39 return reinterpret_cast<const char*>(relptr) + *relptr;
45 std::string BundleUtils::ResolveLibraryPath(const std::string& library_name,
46 const std::string& split_name) {
47 JNIEnv* env = AttachCurrentThread();
48 ScopedJavaLocalRef<jstring> java_path = Java_BundleUtils_getNativeLibraryPath(
49 env, ConvertUTF8ToJavaString(env, library_name),
50 ConvertUTF8ToJavaString(env, split_name));
51 // TODO(https://crbug.com/1019853): Remove this tolerance.
55 return ConvertJavaStringToUTF8(env, java_path);
59 bool BundleUtils::IsBundle() {
60 return Java_BundleUtils_isBundleForNative(AttachCurrentThread());
64 void* BundleUtils::DlOpenModuleLibraryPartition(const std::string& library_name,
65 const std::string& partition,
66 const std::string& split_name) {
67 // TODO(https://crbug.com/1019853): Remove this tolerance.
68 std::string library_path = ResolveLibraryPath(library_name, split_name);
69 if (library_path.empty()) {
73 // Linear search is required here because the partition descriptors are not
74 // ordered. If a large number of partitions come into existence, lld could be
75 // modified to sort the partitions.
76 DCHECK(__part_index_begin != nullptr);
77 DCHECK(__part_index_end != nullptr);
78 for (const PartitionIndexEntry* part = __part_index_begin;
79 part != __part_index_end; ++part) {
81 reinterpret_cast<const char*>(ReadRelPtr(&part->name_relptr)));
82 if (name == partition) {
83 android_dlextinfo info = {};
84 info.flags = ANDROID_DLEXT_RESERVED_ADDRESS;
85 info.reserved_addr = const_cast<void*>(ReadRelPtr(&part->addr_relptr));
86 info.reserved_size = part->size;
88 #if __ANDROID_API__ >= 24
89 return android_dlopen_ext(library_path.c_str(), RTLD_LOCAL, &info);
91 // When targeting pre-N, such as for Cronet, android_dlopen_ext() might
92 // not be available on the system.
93 CHECK(0) << "android_dlopen_ext not available";
102 } // namespace android