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