blob: e754414f46fe298d93440ab4ddecdf45242722e5 [file] [log] [blame]
Orion Hodson9b16e342019-10-09 13:29:16 +01001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Nicolas Geoffray7ca8b672020-04-24 15:43:48 +010017#if defined(ART_TARGET_ANDROID)
18
Orion Hodson9b16e342019-10-09 13:29:16 +010019#include <dlfcn.h>
20#include <memory>
21#include <unordered_map>
22
Martin Stjernholmb3092402020-09-04 00:49:44 +010023#include <android-base/stringprintf.h>
Orion Hodson9b16e342019-10-09 13:29:16 +010024#include <android-base/strings.h>
25#include <gmock/gmock.h>
26#include <gtest/gtest.h>
27#include <jni.h>
28
29#include "native_loader_namespace.h"
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +010030#include "nativehelper/scoped_utf_chars.h"
Orion Hodson9b16e342019-10-09 13:29:16 +010031#include "nativeloader/dlext_namespaces.h"
32#include "nativeloader/native_loader.h"
33#include "public_libraries.h"
34
Orion Hodson9b16e342019-10-09 13:29:16 +010035namespace android {
36namespace nativeloader {
37
Martin Stjernholm48297332019-11-12 21:21:32 +000038using ::testing::Eq;
Martin Stjernholm26659432021-04-16 19:55:03 +010039using ::testing::NotNull;
Martin Stjernholm48297332019-11-12 21:21:32 +000040using ::testing::Return;
41using ::testing::StrEq;
42using ::testing::_;
43using internal::ConfigEntry;
Calin Juravle91d2c5c2021-05-07 22:44:29 +000044using internal::ParseApexLibrariesConfig;
Martin Stjernholm26659432021-04-16 19:55:03 +010045using internal::ParseConfig;
Martin Stjernholm48297332019-11-12 21:21:32 +000046
Martin Stjernholmbe08b202019-11-12 20:11:00 +000047#if defined(__LP64__)
48#define LIB_DIR "lib64"
49#else
50#define LIB_DIR "lib"
51#endif
52
Martin Stjernholm26659432021-04-16 19:55:03 +010053// gmock interface that represents interested platform APIs on libdl_android and libnativebridge
Orion Hodson9b16e342019-10-09 13:29:16 +010054class Platform {
55 public:
56 virtual ~Platform() {}
57
Martin Stjernholm26659432021-04-16 19:55:03 +010058 // These mock_* are the APIs semantically the same across libdl_android and libnativebridge.
Orion Hodson9b16e342019-10-09 13:29:16 +010059 // Instead of having two set of mock APIs for the two, define only one set with an additional
Martin Stjernholm26659432021-04-16 19:55:03 +010060 // argument 'bool bridged' to identify the context (i.e., called for libdl_android or
61 // libnativebridge).
Orion Hodson9b16e342019-10-09 13:29:16 +010062 typedef char* mock_namespace_handle;
63 virtual bool mock_init_anonymous_namespace(bool bridged, const char* sonames,
64 const char* search_paths) = 0;
65 virtual mock_namespace_handle mock_create_namespace(
66 bool bridged, const char* name, const char* ld_library_path, const char* default_library_path,
67 uint64_t type, const char* permitted_when_isolated_path, mock_namespace_handle parent) = 0;
68 virtual bool mock_link_namespaces(bool bridged, mock_namespace_handle from,
69 mock_namespace_handle to, const char* sonames) = 0;
70 virtual mock_namespace_handle mock_get_exported_namespace(bool bridged, const char* name) = 0;
71 virtual void* mock_dlopen_ext(bool bridged, const char* filename, int flags,
72 mock_namespace_handle ns) = 0;
73
Martin Stjernholm26659432021-04-16 19:55:03 +010074 // libnativebridge APIs for which libdl_android has no corresponding APIs
Orion Hodson9b16e342019-10-09 13:29:16 +010075 virtual bool NativeBridgeInitialized() = 0;
76 virtual const char* NativeBridgeGetError() = 0;
77 virtual bool NativeBridgeIsPathSupported(const char*) = 0;
78 virtual bool NativeBridgeIsSupported(const char*) = 0;
79
80 // To mock "ClassLoader Object.getParent()"
81 virtual const char* JniObject_getParent(const char*) = 0;
82};
83
84// The mock does not actually create a namespace object. But simply casts the pointer to the
85// string for the namespace name as the handle to the namespace object.
86#define TO_ANDROID_NAMESPACE(str) \
87 reinterpret_cast<struct android_namespace_t*>(const_cast<char*>(str))
88
89#define TO_BRIDGED_NAMESPACE(str) \
90 reinterpret_cast<struct native_bridge_namespace_t*>(const_cast<char*>(str))
91
92#define TO_MOCK_NAMESPACE(ns) reinterpret_cast<Platform::mock_namespace_handle>(ns)
93
94// These represents built-in namespaces created by the linker according to ld.config.txt
95static std::unordered_map<std::string, Platform::mock_namespace_handle> namespaces = {
Martin Stjernholmb3092402020-09-04 00:49:44 +010096#define NAMESPACE_ENTRY(ns) {ns, TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(ns))}
97 NAMESPACE_ENTRY("com_android_i18n"),
98 NAMESPACE_ENTRY("com_android_neuralnetworks"),
Martin Stjernholmb3092402020-09-04 00:49:44 +010099 NAMESPACE_ENTRY("com_android_art"),
100 NAMESPACE_ENTRY("default"),
101 NAMESPACE_ENTRY("sphal"),
102 NAMESPACE_ENTRY("system"),
103 NAMESPACE_ENTRY("vndk"),
104 NAMESPACE_ENTRY("vndk_product"),
105#undef NAMESPACE_ENTRY
Orion Hodson9b16e342019-10-09 13:29:16 +0100106};
107
108// The actual gmock object
109class MockPlatform : public Platform {
110 public:
111 explicit MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
112 ON_CALL(*this, NativeBridgeIsSupported(_)).WillByDefault(Return(is_bridged_));
113 ON_CALL(*this, NativeBridgeIsPathSupported(_)).WillByDefault(Return(is_bridged_));
114 ON_CALL(*this, mock_get_exported_namespace(_, _))
Martin Stjernholm48297332019-11-12 21:21:32 +0000115 .WillByDefault(testing::Invoke([](bool, const char* name) -> mock_namespace_handle {
Orion Hodson9b16e342019-10-09 13:29:16 +0100116 if (namespaces.find(name) != namespaces.end()) {
117 return namespaces[name];
118 }
Martin Stjernholmb3092402020-09-04 00:49:44 +0100119 std::string msg = android::base::StringPrintf("(namespace %s not found)", name);
120 // The strdup'ed string will leak, but the test is already failing if we get here.
121 return TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(strdup(msg.c_str())));
Orion Hodson9b16e342019-10-09 13:29:16 +0100122 }));
123 }
124
Orion Hodson9b16e342019-10-09 13:29:16 +0100125 // Mocking the common APIs
126 MOCK_METHOD3(mock_init_anonymous_namespace, bool(bool, const char*, const char*));
127 MOCK_METHOD7(mock_create_namespace,
128 mock_namespace_handle(bool, const char*, const char*, const char*, uint64_t,
129 const char*, mock_namespace_handle));
130 MOCK_METHOD4(mock_link_namespaces,
131 bool(bool, mock_namespace_handle, mock_namespace_handle, const char*));
132 MOCK_METHOD2(mock_get_exported_namespace, mock_namespace_handle(bool, const char*));
133 MOCK_METHOD4(mock_dlopen_ext, void*(bool, const char*, int, mock_namespace_handle));
134
135 // Mocking libnativebridge APIs
136 MOCK_METHOD0(NativeBridgeInitialized, bool());
137 MOCK_METHOD0(NativeBridgeGetError, const char*());
138 MOCK_METHOD1(NativeBridgeIsPathSupported, bool(const char*));
139 MOCK_METHOD1(NativeBridgeIsSupported, bool(const char*));
140
141 // Mocking "ClassLoader Object.getParent()"
142 MOCK_METHOD1(JniObject_getParent, const char*(const char*));
143
144 private:
145 bool is_bridged_;
146};
147
148static std::unique_ptr<MockPlatform> mock;
149
Martin Stjernholm26659432021-04-16 19:55:03 +0100150// Provide C wrappers for the mock object. These symbols must be exported by ld
151// to be able to override the real symbols in the shared libs.
Orion Hodson9b16e342019-10-09 13:29:16 +0100152extern "C" {
Orion Hodson9b16e342019-10-09 13:29:16 +0100153
Martin Stjernholm26659432021-04-16 19:55:03 +0100154// libdl_android APIs
Orion Hodson9b16e342019-10-09 13:29:16 +0100155
156bool android_init_anonymous_namespace(const char* sonames, const char* search_path) {
157 return mock->mock_init_anonymous_namespace(false, sonames, search_path);
158}
159
160struct android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
161 const char* default_library_path,
162 uint64_t type,
163 const char* permitted_when_isolated_path,
164 struct android_namespace_t* parent) {
165 return TO_ANDROID_NAMESPACE(
166 mock->mock_create_namespace(false, name, ld_library_path, default_library_path, type,
167 permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
168}
169
170bool android_link_namespaces(struct android_namespace_t* from, struct android_namespace_t* to,
171 const char* sonames) {
172 return mock->mock_link_namespaces(false, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
173}
174
175struct android_namespace_t* android_get_exported_namespace(const char* name) {
176 return TO_ANDROID_NAMESPACE(mock->mock_get_exported_namespace(false, name));
177}
178
179void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* info) {
180 return mock->mock_dlopen_ext(false, filename, flags, TO_MOCK_NAMESPACE(info->library_namespace));
181}
182
183// libnativebridge APIs
Martin Stjernholm26659432021-04-16 19:55:03 +0100184
Orion Hodson9b16e342019-10-09 13:29:16 +0100185bool NativeBridgeIsSupported(const char* libpath) {
186 return mock->NativeBridgeIsSupported(libpath);
187}
188
189struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
190 return TO_BRIDGED_NAMESPACE(mock->mock_get_exported_namespace(true, name));
191}
192
193struct native_bridge_namespace_t* NativeBridgeCreateNamespace(
194 const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
195 const char* permitted_when_isolated_path, struct native_bridge_namespace_t* parent) {
196 return TO_BRIDGED_NAMESPACE(
197 mock->mock_create_namespace(true, name, ld_library_path, default_library_path, type,
198 permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
199}
200
201bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
202 struct native_bridge_namespace_t* to, const char* sonames) {
203 return mock->mock_link_namespaces(true, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
204}
205
206void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
207 struct native_bridge_namespace_t* ns) {
208 return mock->mock_dlopen_ext(true, libpath, flag, TO_MOCK_NAMESPACE(ns));
209}
210
211bool NativeBridgeInitialized() {
212 return mock->NativeBridgeInitialized();
213}
214
215bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
216 const char* anon_ns_library_path) {
217 return mock->mock_init_anonymous_namespace(true, public_ns_sonames, anon_ns_library_path);
218}
219
220const char* NativeBridgeGetError() {
221 return mock->NativeBridgeGetError();
222}
223
224bool NativeBridgeIsPathSupported(const char* path) {
225 return mock->NativeBridgeIsPathSupported(path);
226}
227
228} // extern "C"
229
230// A very simple JNI mock.
231// jstring is a pointer to utf8 char array. We don't need utf16 char here.
232// jobject, jclass, and jmethodID are also a pointer to utf8 char array
233// Only a few JNI methods that are actually used in libnativeloader are mocked.
234JNINativeInterface* CreateJNINativeInterface() {
235 JNINativeInterface* inf = new JNINativeInterface();
236 memset(inf, 0, sizeof(JNINativeInterface));
237
238 inf->GetStringUTFChars = [](JNIEnv*, jstring s, jboolean*) -> const char* {
239 return reinterpret_cast<const char*>(s);
240 };
241
242 inf->ReleaseStringUTFChars = [](JNIEnv*, jstring, const char*) -> void { return; };
243
244 inf->NewStringUTF = [](JNIEnv*, const char* bytes) -> jstring {
245 return reinterpret_cast<jstring>(const_cast<char*>(bytes));
246 };
247
248 inf->FindClass = [](JNIEnv*, const char* name) -> jclass {
249 return reinterpret_cast<jclass>(const_cast<char*>(name));
250 };
251
252 inf->CallObjectMethodV = [](JNIEnv*, jobject obj, jmethodID mid, va_list) -> jobject {
253 if (strcmp("getParent", reinterpret_cast<const char*>(mid)) == 0) {
254 // JniObject_getParent can be a valid jobject or nullptr if there is
255 // no parent classloader.
256 const char* ret = mock->JniObject_getParent(reinterpret_cast<const char*>(obj));
257 return reinterpret_cast<jobject>(const_cast<char*>(ret));
258 }
259 return nullptr;
260 };
261
262 inf->GetMethodID = [](JNIEnv*, jclass, const char* name, const char*) -> jmethodID {
263 return reinterpret_cast<jmethodID>(const_cast<char*>(name));
264 };
265
266 inf->NewWeakGlobalRef = [](JNIEnv*, jobject obj) -> jobject { return obj; };
267
268 inf->IsSameObject = [](JNIEnv*, jobject a, jobject b) -> jboolean {
269 return strcmp(reinterpret_cast<const char*>(a), reinterpret_cast<const char*>(b)) == 0;
270 };
271
272 return inf;
273}
274
275static void* const any_nonnull = reinterpret_cast<void*>(0x12345678);
276
277// Custom matcher for comparing namespace handles
278MATCHER_P(NsEq, other, "") {
279 *result_listener << "comparing " << reinterpret_cast<const char*>(arg) << " and " << other;
280 return strcmp(reinterpret_cast<const char*>(arg), reinterpret_cast<const char*>(other)) == 0;
281}
282
283/////////////////////////////////////////////////////////////////
284
285// Test fixture
286class NativeLoaderTest : public ::testing::TestWithParam<bool> {
287 protected:
288 bool IsBridged() { return GetParam(); }
289
290 void SetUp() override {
Martin Stjernholm48297332019-11-12 21:21:32 +0000291 mock = std::make_unique<testing::NiceMock<MockPlatform>>(IsBridged());
Orion Hodson9b16e342019-10-09 13:29:16 +0100292
293 env = std::make_unique<JNIEnv>();
294 env->functions = CreateJNINativeInterface();
295 }
296
297 void SetExpectations() {
298 std::vector<std::string> default_public_libs =
299 android::base::Split(preloadable_public_libraries(), ":");
300 for (auto l : default_public_libs) {
Martin Stjernholm26659432021-04-16 19:55:03 +0100301 EXPECT_CALL(*mock,
302 mock_dlopen_ext(false, StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE, NotNull()))
Orion Hodson9b16e342019-10-09 13:29:16 +0100303 .WillOnce(Return(any_nonnull));
304 }
305 }
306
307 void RunTest() { InitializeNativeLoader(); }
308
309 void TearDown() override {
310 ResetNativeLoader();
311 delete env->functions;
312 mock.reset();
313 }
314
315 std::unique_ptr<JNIEnv> env;
316};
317
318/////////////////////////////////////////////////////////////////
319
320TEST_P(NativeLoaderTest, InitializeLoadsDefaultPublicLibraries) {
321 SetExpectations();
322 RunTest();
323}
324
Martin Stjernholm26659432021-04-16 19:55:03 +0100325TEST_P(NativeLoaderTest, OpenNativeLibraryWithoutClassloaderInApex) {
326 const char* test_lib_path = "libfoo.so";
327 void* fake_handle = &fake_handle; // Arbitrary non-null value
328 EXPECT_CALL(*mock,
329 mock_dlopen_ext(false, StrEq(test_lib_path), RTLD_NOW, NsEq("com_android_art")))
330 .WillOnce(Return(fake_handle));
331
332 bool needs_native_bridge = false;
333 char* errmsg = nullptr;
334 EXPECT_EQ(fake_handle,
335 OpenNativeLibrary(env.get(),
336 /*target_sdk_version=*/17,
337 test_lib_path,
338 /*class_loader=*/nullptr,
339 /*caller_location=*/"/apex/com.android.art/javalib/myloadinglib.jar",
340 /*library_path=*/nullptr,
341 &needs_native_bridge,
342 &errmsg));
343 // OpenNativeLibrary never uses nativebridge when there's no classloader. That
344 // should maybe change.
345 EXPECT_EQ(needs_native_bridge, false);
346 EXPECT_EQ(errmsg, nullptr);
347}
348
349TEST_P(NativeLoaderTest, OpenNativeLibraryWithoutClassloaderInFramework) {
350 const char* test_lib_path = "libfoo.so";
351 void* fake_handle = &fake_handle; // Arbitrary non-null value
352 EXPECT_CALL(*mock, mock_dlopen_ext(false, StrEq(test_lib_path), RTLD_NOW, NsEq("system")))
353 .WillOnce(Return(fake_handle));
354
355 bool needs_native_bridge = false;
356 char* errmsg = nullptr;
357 EXPECT_EQ(fake_handle,
358 OpenNativeLibrary(env.get(),
359 /*target_sdk_version=*/17,
360 test_lib_path,
361 /*class_loader=*/nullptr,
362 /*caller_location=*/"/system/framework/framework.jar!classes1.dex",
363 /*library_path=*/nullptr,
364 &needs_native_bridge,
365 &errmsg));
366 // OpenNativeLibrary never uses nativebridge when there's no classloader. That
367 // should maybe change.
368 EXPECT_EQ(needs_native_bridge, false);
369 EXPECT_EQ(errmsg, nullptr);
370}
371
372TEST_P(NativeLoaderTest, OpenNativeLibraryWithoutClassloaderAndCallerLocation) {
373 const char* test_lib_path = "libfoo.so";
374 void* fake_handle = &fake_handle; // Arbitrary non-null value
375 EXPECT_CALL(*mock, mock_dlopen_ext(false, StrEq(test_lib_path), RTLD_NOW, NsEq("system")))
376 .WillOnce(Return(fake_handle));
377
378 bool needs_native_bridge = false;
379 char* errmsg = nullptr;
380 EXPECT_EQ(fake_handle,
381 OpenNativeLibrary(env.get(),
382 /*target_sdk_version=*/17,
383 test_lib_path,
384 /*class_loader=*/nullptr,
385 /*caller_location=*/nullptr,
386 /*library_path=*/nullptr,
387 &needs_native_bridge,
388 &errmsg));
389 // OpenNativeLibrary never uses nativebridge when there's no classloader. That
390 // should maybe change.
391 EXPECT_EQ(needs_native_bridge, false);
392 EXPECT_EQ(errmsg, nullptr);
393}
394
Orion Hodson9b16e342019-10-09 13:29:16 +0100395INSTANTIATE_TEST_SUITE_P(NativeLoaderTests, NativeLoaderTest, testing::Bool());
396
397/////////////////////////////////////////////////////////////////
398
399class NativeLoaderTest_Create : public NativeLoaderTest {
400 protected:
401 // Test inputs (initialized to the default values). Overriding these
402 // must be done before calling SetExpectations() and RunTest().
403 uint32_t target_sdk_version = 29;
404 std::string class_loader = "my_classloader";
405 bool is_shared = false;
406 std::string dex_path = "/data/app/foo/classes.dex";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000407 std::string library_path = "/data/app/foo/" LIB_DIR "/arm";
408 std::string permitted_path = "/data/app/foo/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100409
410 // expected output (.. for the default test inputs)
411 std::string expected_namespace_name = "classloader-namespace";
412 uint64_t expected_namespace_flags =
413 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
414 std::string expected_library_path = library_path;
415 std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
Kiyoung Kim99c19ca2020-01-29 16:09:38 +0900416 std::string expected_parent_namespace = "system";
Orion Hodson9b16e342019-10-09 13:29:16 +0100417 bool expected_link_with_platform_ns = true;
418 bool expected_link_with_art_ns = true;
Victor Changd20e51d2020-05-05 16:01:19 +0100419 bool expected_link_with_i18n_ns = true;
Orion Hodson9b16e342019-10-09 13:29:16 +0100420 bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
421 bool expected_link_with_vndk_ns = false;
Justin Yuneb4f08c2020-02-18 11:29:07 +0900422 bool expected_link_with_vndk_product_ns = false;
Orion Hodson9b16e342019-10-09 13:29:16 +0100423 bool expected_link_with_default_ns = false;
424 bool expected_link_with_neuralnetworks_ns = true;
425 std::string expected_shared_libs_to_platform_ns = default_public_libraries();
Jooyung Hancd616d02020-09-01 14:53:23 +0900426 std::string expected_shared_libs_to_art_ns = apex_public_libraries().at("com_android_art");
427 std::string expected_shared_libs_to_i18n_ns = apex_public_libraries().at("com_android_i18n");
Orion Hodson9b16e342019-10-09 13:29:16 +0100428 std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
Justin Yuneb4f08c2020-02-18 11:29:07 +0900429 std::string expected_shared_libs_to_vndk_ns = vndksp_libraries_vendor();
430 std::string expected_shared_libs_to_vndk_product_ns = vndksp_libraries_product();
Orion Hodson9b16e342019-10-09 13:29:16 +0100431 std::string expected_shared_libs_to_default_ns = default_public_libraries();
Jooyung Hancd616d02020-09-01 14:53:23 +0900432 std::string expected_shared_libs_to_neuralnetworks_ns = apex_public_libraries().at("com_android_neuralnetworks");
Orion Hodson9b16e342019-10-09 13:29:16 +0100433
434 void SetExpectations() {
435 NativeLoaderTest::SetExpectations();
436
437 ON_CALL(*mock, JniObject_getParent(StrEq(class_loader))).WillByDefault(Return(nullptr));
438
Martin Stjernholm48297332019-11-12 21:21:32 +0000439 EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(testing::AnyNumber());
440 EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(testing::AnyNumber());
Orion Hodson9b16e342019-10-09 13:29:16 +0100441
442 EXPECT_CALL(*mock, mock_create_namespace(
443 Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
444 StrEq(expected_library_path), expected_namespace_flags,
445 StrEq(expected_permitted_path), NsEq(expected_parent_namespace.c_str())))
446 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(dex_path.c_str()))));
447 if (expected_link_with_platform_ns) {
Kiyoung Kim99c19ca2020-01-29 16:09:38 +0900448 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("system"),
Orion Hodson9b16e342019-10-09 13:29:16 +0100449 StrEq(expected_shared_libs_to_platform_ns)))
450 .WillOnce(Return(true));
451 }
452 if (expected_link_with_art_ns) {
Kiyoung Kim272b36d2020-02-19 16:08:47 +0900453 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_art"),
Orion Hodson9b16e342019-10-09 13:29:16 +0100454 StrEq(expected_shared_libs_to_art_ns)))
455 .WillOnce(Return(true));
456 }
Victor Changd20e51d2020-05-05 16:01:19 +0100457 if (expected_link_with_i18n_ns) {
458 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_i18n"),
459 StrEq(expected_shared_libs_to_i18n_ns)))
460 .WillOnce(Return(true));
461 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100462 if (expected_link_with_sphal_ns) {
463 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("sphal"),
464 StrEq(expected_shared_libs_to_sphal_ns)))
465 .WillOnce(Return(true));
466 }
467 if (expected_link_with_vndk_ns) {
468 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk"),
469 StrEq(expected_shared_libs_to_vndk_ns)))
470 .WillOnce(Return(true));
471 }
Justin Yuneb4f08c2020-02-18 11:29:07 +0900472 if (expected_link_with_vndk_product_ns) {
473 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk_product"),
474 StrEq(expected_shared_libs_to_vndk_product_ns)))
475 .WillOnce(Return(true));
476 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100477 if (expected_link_with_default_ns) {
478 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("default"),
479 StrEq(expected_shared_libs_to_default_ns)))
480 .WillOnce(Return(true));
481 }
482 if (expected_link_with_neuralnetworks_ns) {
Kiyoung Kim272b36d2020-02-19 16:08:47 +0900483 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_neuralnetworks"),
Orion Hodson9b16e342019-10-09 13:29:16 +0100484 StrEq(expected_shared_libs_to_neuralnetworks_ns)))
485 .WillOnce(Return(true));
486 }
487 }
488
489 void RunTest() {
490 NativeLoaderTest::RunTest();
491
492 jstring err = CreateClassLoaderNamespace(
493 env(), target_sdk_version, env()->NewStringUTF(class_loader.c_str()), is_shared,
494 env()->NewStringUTF(dex_path.c_str()), env()->NewStringUTF(library_path.c_str()),
Martin Stjernholmb3092402020-09-04 00:49:44 +0100495 env()->NewStringUTF(permitted_path.c_str()), /*uses_library_list=*/ nullptr);
Orion Hodson9b16e342019-10-09 13:29:16 +0100496
497 // no error
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100498 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100499
500 if (!IsBridged()) {
501 struct android_namespace_t* ns =
502 FindNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
503
504 // The created namespace is for this apk
505 EXPECT_EQ(dex_path.c_str(), reinterpret_cast<const char*>(ns));
506 } else {
507 struct NativeLoaderNamespace* ns =
508 FindNativeLoaderNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
509
510 // The created namespace is for the this apk
511 EXPECT_STREQ(dex_path.c_str(),
512 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
513 }
514 }
515
516 JNIEnv* env() { return NativeLoaderTest::env.get(); }
517};
518
519TEST_P(NativeLoaderTest_Create, DownloadedApp) {
520 SetExpectations();
521 RunTest();
522}
523
524TEST_P(NativeLoaderTest_Create, BundledSystemApp) {
525 dex_path = "/system/app/foo/foo.apk";
526 is_shared = true;
527
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100528 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100529 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
530 SetExpectations();
531 RunTest();
532}
533
534TEST_P(NativeLoaderTest_Create, BundledVendorApp) {
535 dex_path = "/vendor/app/foo/foo.apk";
536 is_shared = true;
537
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100538 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100539 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
540 SetExpectations();
541 RunTest();
542}
543
544TEST_P(NativeLoaderTest_Create, UnbundledVendorApp) {
545 dex_path = "/vendor/app/foo/foo.apk";
546 is_shared = false;
547
548 expected_namespace_name = "vendor-classloader-namespace";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000549 expected_library_path = expected_library_path + ":/vendor/" LIB_DIR;
550 expected_permitted_path = expected_permitted_path + ":/vendor/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100551 expected_shared_libs_to_platform_ns =
Justin Yun089c1352020-02-06 16:53:08 +0900552 expected_shared_libs_to_platform_ns + ":" + llndk_libraries_vendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100553 expected_link_with_vndk_ns = true;
554 SetExpectations();
555 RunTest();
556}
557
Justin Yun3db26d52019-12-16 14:09:39 +0900558TEST_P(NativeLoaderTest_Create, BundledProductApp) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100559 dex_path = "/product/app/foo/foo.apk";
560 is_shared = true;
561
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100562 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100563 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
564 SetExpectations();
565 RunTest();
566}
567
Justin Yun3db26d52019-12-16 14:09:39 +0900568TEST_P(NativeLoaderTest_Create, UnbundledProductApp) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100569 dex_path = "/product/app/foo/foo.apk";
570 is_shared = false;
Orion Hodson9b16e342019-10-09 13:29:16 +0100571
Justin Yun3db26d52019-12-16 14:09:39 +0900572 if (is_product_vndk_version_defined()) {
573 expected_namespace_name = "vendor-classloader-namespace";
574 expected_library_path = expected_library_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
575 expected_permitted_path =
576 expected_permitted_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
577 expected_shared_libs_to_platform_ns =
Justin Yun089c1352020-02-06 16:53:08 +0900578 expected_shared_libs_to_platform_ns + ":" + llndk_libraries_product();
Justin Yuneb4f08c2020-02-18 11:29:07 +0900579 expected_link_with_vndk_product_ns = true;
Justin Yun3db26d52019-12-16 14:09:39 +0900580 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100581 SetExpectations();
582 RunTest();
583}
584
585TEST_P(NativeLoaderTest_Create, NamespaceForSharedLibIsNotUsedAsAnonymousNamespace) {
586 if (IsBridged()) {
587 // There is no shared lib in translated arch
588 // TODO(jiyong): revisit this
589 return;
590 }
591 // compared to apks, for java shared libs, library_path is empty; java shared
592 // libs don't have their own native libs. They use platform's.
593 library_path = "";
594 expected_library_path = library_path;
595 // no ALSO_USED_AS_ANONYMOUS
596 expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
597 SetExpectations();
598 RunTest();
599}
600
601TEST_P(NativeLoaderTest_Create, TwoApks) {
602 SetExpectations();
603 const uint32_t second_app_target_sdk_version = 29;
604 const std::string second_app_class_loader = "second_app_classloader";
605 const bool second_app_is_shared = false;
606 const std::string second_app_dex_path = "/data/app/bar/classes.dex";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000607 const std::string second_app_library_path = "/data/app/bar/" LIB_DIR "/arm";
608 const std::string second_app_permitted_path = "/data/app/bar/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100609 const std::string expected_second_app_permitted_path =
610 std::string("/data:/mnt/expand:") + second_app_permitted_path;
611 const std::string expected_second_app_parent_namespace = "classloader-namespace";
612 // no ALSO_USED_AS_ANONYMOUS
613 const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
614
615 // The scenario is that second app is loaded by the first app.
616 // So the first app's classloader (`classloader`) is parent of the second
617 // app's classloader.
618 ON_CALL(*mock, JniObject_getParent(StrEq(second_app_class_loader)))
619 .WillByDefault(Return(class_loader.c_str()));
620
621 // namespace for the second app is created. Its parent is set to the namespace
622 // of the first app.
623 EXPECT_CALL(*mock, mock_create_namespace(
624 Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
625 StrEq(second_app_library_path), expected_second_namespace_flags,
626 StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str())))
627 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
628 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
629 .WillRepeatedly(Return(true));
630
631 RunTest();
632 jstring err = CreateClassLoaderNamespace(
633 env(), second_app_target_sdk_version, env()->NewStringUTF(second_app_class_loader.c_str()),
634 second_app_is_shared, env()->NewStringUTF(second_app_dex_path.c_str()),
635 env()->NewStringUTF(second_app_library_path.c_str()),
Martin Stjernholmb3092402020-09-04 00:49:44 +0100636 env()->NewStringUTF(second_app_permitted_path.c_str()), /*uses_library_list=*/ nullptr);
Orion Hodson9b16e342019-10-09 13:29:16 +0100637
638 // success
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100639 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100640
641 if (!IsBridged()) {
642 struct android_namespace_t* ns =
643 FindNamespaceByClassLoader(env(), env()->NewStringUTF(second_app_class_loader.c_str()));
644
645 // The created namespace is for the second apk
646 EXPECT_EQ(second_app_dex_path.c_str(), reinterpret_cast<const char*>(ns));
647 } else {
648 struct NativeLoaderNamespace* ns = FindNativeLoaderNamespaceByClassLoader(
649 env(), env()->NewStringUTF(second_app_class_loader.c_str()));
650
651 // The created namespace is for the second apk
652 EXPECT_STREQ(second_app_dex_path.c_str(),
653 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
654 }
655}
656
657INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
658
659const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
660 [](const struct ConfigEntry&) -> Result<bool> { return true; };
661
662TEST(NativeLoaderConfigParser, NamesAndComments) {
663 const char file_content[] = R"(
664######
665
666libA.so
667#libB.so
668
669
670 libC.so
671libD.so
672 #### libE.so
673)";
674 const std::vector<std::string> expected_result = {"libA.so", "libC.so", "libD.so"};
675 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900676 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100677 ASSERT_EQ(expected_result, *result);
678}
679
680TEST(NativeLoaderConfigParser, WithBitness) {
681 const char file_content[] = R"(
682libA.so 32
683libB.so 64
684libC.so
685)";
686#if defined(__LP64__)
687 const std::vector<std::string> expected_result = {"libB.so", "libC.so"};
688#else
689 const std::vector<std::string> expected_result = {"libA.so", "libC.so"};
690#endif
691 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900692 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100693 ASSERT_EQ(expected_result, *result);
694}
695
696TEST(NativeLoaderConfigParser, WithNoPreload) {
697 const char file_content[] = R"(
698libA.so nopreload
699libB.so nopreload
700libC.so
701)";
702
703 const std::vector<std::string> expected_result = {"libC.so"};
704 Result<std::vector<std::string>> result =
705 ParseConfig(file_content,
706 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900707 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100708 ASSERT_EQ(expected_result, *result);
709}
710
711TEST(NativeLoaderConfigParser, WithNoPreloadAndBitness) {
712 const char file_content[] = R"(
713libA.so nopreload 32
714libB.so 64 nopreload
715libC.so 32
716libD.so 64
717libE.so nopreload
718)";
719
720#if defined(__LP64__)
721 const std::vector<std::string> expected_result = {"libD.so"};
722#else
723 const std::vector<std::string> expected_result = {"libC.so"};
724#endif
725 Result<std::vector<std::string>> result =
726 ParseConfig(file_content,
727 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900728 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100729 ASSERT_EQ(expected_result, *result);
730}
731
732TEST(NativeLoaderConfigParser, RejectMalformed) {
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900733 ASSERT_FALSE(ParseConfig("libA.so 32 64", always_true).ok());
734 ASSERT_FALSE(ParseConfig("libA.so 32 32", always_true).ok());
735 ASSERT_FALSE(ParseConfig("libA.so 32 nopreload 64", always_true).ok());
736 ASSERT_FALSE(ParseConfig("32 libA.so nopreload", always_true).ok());
737 ASSERT_FALSE(ParseConfig("nopreload libA.so 32", always_true).ok());
738 ASSERT_FALSE(ParseConfig("libA.so nopreload # comment", always_true).ok());
Orion Hodson9b16e342019-10-09 13:29:16 +0100739}
740
Jooyung Hancd616d02020-09-01 14:53:23 +0900741TEST(NativeLoaderApexLibrariesConfigParser, BasicLoading) {
Jooyung Han538f99a2020-03-03 00:46:50 +0900742 const char file_content[] = R"(
743# comment
Jooyung Hancd616d02020-09-01 14:53:23 +0900744jni com_android_foo libfoo.so
Jooyung Han538f99a2020-03-03 00:46:50 +0900745# Empty line is ignored
746
Jooyung Hancd616d02020-09-01 14:53:23 +0900747jni com_android_bar libbar.so:libbar2.so
748
749 public com_android_bar libpublic.so
Jooyung Han538f99a2020-03-03 00:46:50 +0900750)";
751
Jooyung Hancd616d02020-09-01 14:53:23 +0900752 auto jni_libs = ParseApexLibrariesConfig(file_content, "jni");
753 ASSERT_RESULT_OK(jni_libs);
754 std::map<std::string, std::string> expected_jni_libs {
Jooyung Han538f99a2020-03-03 00:46:50 +0900755 {"com_android_foo", "libfoo.so"},
756 {"com_android_bar", "libbar.so:libbar2.so"},
757 };
Jooyung Hancd616d02020-09-01 14:53:23 +0900758 ASSERT_EQ(expected_jni_libs, *jni_libs);
Jooyung Han538f99a2020-03-03 00:46:50 +0900759
Jooyung Hancd616d02020-09-01 14:53:23 +0900760 auto public_libs = ParseApexLibrariesConfig(file_content, "public");
761 ASSERT_RESULT_OK(public_libs);
762 std::map<std::string, std::string> expected_public_libs {
763 {"com_android_bar", "libpublic.so"},
764 };
765 ASSERT_EQ(expected_public_libs, *public_libs);
Jooyung Han538f99a2020-03-03 00:46:50 +0900766}
767
Jooyung Hancd616d02020-09-01 14:53:23 +0900768TEST(NativeLoaderApexLibrariesConfigParser, RejectMalformedLine) {
769 const char file_content[] = R"(
770jni com_android_foo libfoo
771# missing <library list>
772jni com_android_bar
773)";
774 auto result = ParseApexLibrariesConfig(file_content, "jni");
775 ASSERT_FALSE(result.ok());
776 ASSERT_EQ("Malformed line \"jni com_android_bar\"", result.error().message());
Jooyung Han538f99a2020-03-03 00:46:50 +0900777}
778
Jooyung Hancd616d02020-09-01 14:53:23 +0900779TEST(NativeLoaderApexLibrariesConfigParser, RejectInvalidTag) {
780 const char file_content[] = R"(
781jni apex1 lib
782public apex2 lib
783# unknown tag
784unknown com_android_foo libfoo
785)";
786 auto result = ParseApexLibrariesConfig(file_content, "jni");
787 ASSERT_FALSE(result.ok());
788 ASSERT_EQ("Invalid tag \"unknown com_android_foo libfoo\"", result.error().message());
789}
790
791TEST(NativeLoaderApexLibrariesConfigParser, RejectInvalidApexNamespace) {
792 const char file_content[] = R"(
793# apex linker namespace should be mangled ('.' -> '_')
794jni com.android.foo lib
795)";
796 auto result = ParseApexLibrariesConfig(file_content, "jni");
797 ASSERT_FALSE(result.ok());
798 ASSERT_EQ("Invalid apex_namespace \"jni com.android.foo lib\"", result.error().message());
799}
800
801TEST(NativeLoaderApexLibrariesConfigParser, RejectInvalidLibraryList) {
802 const char file_content[] = R"(
803# library list is ":" separated list of filenames
804jni com_android_foo lib64/libfoo.so
805)";
806 auto result = ParseApexLibrariesConfig(file_content, "jni");
807 ASSERT_FALSE(result.ok());
808 ASSERT_EQ("Invalid library_list \"jni com_android_foo lib64/libfoo.so\"", result.error().message());
809}
810
811
Orion Hodson9b16e342019-10-09 13:29:16 +0100812} // namespace nativeloader
813} // namespace android
Nicolas Geoffray7ca8b672020-04-24 15:43:48 +0100814
815#endif // defined(ART_TARGET_ANDROID)