blob: 8a8193ed7d77a36a6a9c33350741603bad2ce3f5 [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
17#include <dlfcn.h>
18#include <memory>
19#include <unordered_map>
20
21#include <android-base/strings.h>
22#include <gmock/gmock.h>
23#include <gtest/gtest.h>
24#include <jni.h>
25
26#include "native_loader_namespace.h"
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +010027#include "nativehelper/scoped_utf_chars.h"
Orion Hodson9b16e342019-10-09 13:29:16 +010028#include "nativeloader/dlext_namespaces.h"
29#include "nativeloader/native_loader.h"
30#include "public_libraries.h"
31
Orion Hodson9b16e342019-10-09 13:29:16 +010032namespace android {
33namespace nativeloader {
34
Martin Stjernholm48297332019-11-12 21:21:32 +000035using ::testing::Eq;
36using ::testing::Return;
37using ::testing::StrEq;
38using ::testing::_;
39using internal::ConfigEntry;
40using internal::ParseConfig;
41
Martin Stjernholmbe08b202019-11-12 20:11:00 +000042#if defined(__LP64__)
43#define LIB_DIR "lib64"
44#else
45#define LIB_DIR "lib"
46#endif
47
Orion Hodson9b16e342019-10-09 13:29:16 +010048// gmock interface that represents interested platform APIs on libdl and libnativebridge
49class Platform {
50 public:
51 virtual ~Platform() {}
52
53 // libdl APIs
54 virtual void* dlopen(const char* filename, int flags) = 0;
55 virtual int dlclose(void* handle) = 0;
56 virtual char* dlerror(void) = 0;
57
58 // These mock_* are the APIs semantically the same across libdl and libnativebridge.
59 // Instead of having two set of mock APIs for the two, define only one set with an additional
60 // argument 'bool bridged' to identify the context (i.e., called for libdl or libnativebridge).
61 typedef char* mock_namespace_handle;
62 virtual bool mock_init_anonymous_namespace(bool bridged, const char* sonames,
63 const char* search_paths) = 0;
64 virtual mock_namespace_handle mock_create_namespace(
65 bool bridged, const char* name, const char* ld_library_path, const char* default_library_path,
66 uint64_t type, const char* permitted_when_isolated_path, mock_namespace_handle parent) = 0;
67 virtual bool mock_link_namespaces(bool bridged, mock_namespace_handle from,
68 mock_namespace_handle to, const char* sonames) = 0;
69 virtual mock_namespace_handle mock_get_exported_namespace(bool bridged, const char* name) = 0;
70 virtual void* mock_dlopen_ext(bool bridged, const char* filename, int flags,
71 mock_namespace_handle ns) = 0;
72
73 // libnativebridge APIs for which libdl has no corresponding APIs
74 virtual bool NativeBridgeInitialized() = 0;
75 virtual const char* NativeBridgeGetError() = 0;
76 virtual bool NativeBridgeIsPathSupported(const char*) = 0;
77 virtual bool NativeBridgeIsSupported(const char*) = 0;
78
79 // To mock "ClassLoader Object.getParent()"
80 virtual const char* JniObject_getParent(const char*) = 0;
81};
82
83// The mock does not actually create a namespace object. But simply casts the pointer to the
84// string for the namespace name as the handle to the namespace object.
85#define TO_ANDROID_NAMESPACE(str) \
86 reinterpret_cast<struct android_namespace_t*>(const_cast<char*>(str))
87
88#define TO_BRIDGED_NAMESPACE(str) \
89 reinterpret_cast<struct native_bridge_namespace_t*>(const_cast<char*>(str))
90
91#define TO_MOCK_NAMESPACE(ns) reinterpret_cast<Platform::mock_namespace_handle>(ns)
92
93// These represents built-in namespaces created by the linker according to ld.config.txt
94static std::unordered_map<std::string, Platform::mock_namespace_handle> namespaces = {
95 {"platform", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("platform"))},
96 {"default", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("default"))},
97 {"art", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("art"))},
98 {"sphal", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("sphal"))},
99 {"vndk", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk"))},
100 {"neuralnetworks", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("neuralnetworks"))},
101};
102
103// The actual gmock object
104class MockPlatform : public Platform {
105 public:
106 explicit MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
107 ON_CALL(*this, NativeBridgeIsSupported(_)).WillByDefault(Return(is_bridged_));
108 ON_CALL(*this, NativeBridgeIsPathSupported(_)).WillByDefault(Return(is_bridged_));
109 ON_CALL(*this, mock_get_exported_namespace(_, _))
Martin Stjernholm48297332019-11-12 21:21:32 +0000110 .WillByDefault(testing::Invoke([](bool, const char* name) -> mock_namespace_handle {
Orion Hodson9b16e342019-10-09 13:29:16 +0100111 if (namespaces.find(name) != namespaces.end()) {
112 return namespaces[name];
113 }
114 return TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("(namespace not found"));
115 }));
116 }
117
118 // Mocking libdl APIs
119 MOCK_METHOD2(dlopen, void*(const char*, int));
120 MOCK_METHOD1(dlclose, int(void*));
121 MOCK_METHOD0(dlerror, char*());
122
123 // Mocking the common APIs
124 MOCK_METHOD3(mock_init_anonymous_namespace, bool(bool, const char*, const char*));
125 MOCK_METHOD7(mock_create_namespace,
126 mock_namespace_handle(bool, const char*, const char*, const char*, uint64_t,
127 const char*, mock_namespace_handle));
128 MOCK_METHOD4(mock_link_namespaces,
129 bool(bool, mock_namespace_handle, mock_namespace_handle, const char*));
130 MOCK_METHOD2(mock_get_exported_namespace, mock_namespace_handle(bool, const char*));
131 MOCK_METHOD4(mock_dlopen_ext, void*(bool, const char*, int, mock_namespace_handle));
132
133 // Mocking libnativebridge APIs
134 MOCK_METHOD0(NativeBridgeInitialized, bool());
135 MOCK_METHOD0(NativeBridgeGetError, const char*());
136 MOCK_METHOD1(NativeBridgeIsPathSupported, bool(const char*));
137 MOCK_METHOD1(NativeBridgeIsSupported, bool(const char*));
138
139 // Mocking "ClassLoader Object.getParent()"
140 MOCK_METHOD1(JniObject_getParent, const char*(const char*));
141
142 private:
143 bool is_bridged_;
144};
145
146static std::unique_ptr<MockPlatform> mock;
147
148// Provide C wrappers for the mock object.
149extern "C" {
150void* dlopen(const char* file, int flag) {
151 return mock->dlopen(file, flag);
152}
153
154int dlclose(void* handle) {
155 return mock->dlclose(handle);
156}
157
158char* dlerror(void) {
159 return mock->dlerror();
160}
161
162bool android_init_anonymous_namespace(const char* sonames, const char* search_path) {
163 return mock->mock_init_anonymous_namespace(false, sonames, search_path);
164}
165
166struct android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
167 const char* default_library_path,
168 uint64_t type,
169 const char* permitted_when_isolated_path,
170 struct android_namespace_t* parent) {
171 return TO_ANDROID_NAMESPACE(
172 mock->mock_create_namespace(false, name, ld_library_path, default_library_path, type,
173 permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
174}
175
176bool android_link_namespaces(struct android_namespace_t* from, struct android_namespace_t* to,
177 const char* sonames) {
178 return mock->mock_link_namespaces(false, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
179}
180
181struct android_namespace_t* android_get_exported_namespace(const char* name) {
182 return TO_ANDROID_NAMESPACE(mock->mock_get_exported_namespace(false, name));
183}
184
185void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* info) {
186 return mock->mock_dlopen_ext(false, filename, flags, TO_MOCK_NAMESPACE(info->library_namespace));
187}
188
189// libnativebridge APIs
190bool NativeBridgeIsSupported(const char* libpath) {
191 return mock->NativeBridgeIsSupported(libpath);
192}
193
194struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
195 return TO_BRIDGED_NAMESPACE(mock->mock_get_exported_namespace(true, name));
196}
197
198struct native_bridge_namespace_t* NativeBridgeCreateNamespace(
199 const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
200 const char* permitted_when_isolated_path, struct native_bridge_namespace_t* parent) {
201 return TO_BRIDGED_NAMESPACE(
202 mock->mock_create_namespace(true, name, ld_library_path, default_library_path, type,
203 permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
204}
205
206bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
207 struct native_bridge_namespace_t* to, const char* sonames) {
208 return mock->mock_link_namespaces(true, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
209}
210
211void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
212 struct native_bridge_namespace_t* ns) {
213 return mock->mock_dlopen_ext(true, libpath, flag, TO_MOCK_NAMESPACE(ns));
214}
215
216bool NativeBridgeInitialized() {
217 return mock->NativeBridgeInitialized();
218}
219
220bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
221 const char* anon_ns_library_path) {
222 return mock->mock_init_anonymous_namespace(true, public_ns_sonames, anon_ns_library_path);
223}
224
225const char* NativeBridgeGetError() {
226 return mock->NativeBridgeGetError();
227}
228
229bool NativeBridgeIsPathSupported(const char* path) {
230 return mock->NativeBridgeIsPathSupported(path);
231}
232
233} // extern "C"
234
235// A very simple JNI mock.
236// jstring is a pointer to utf8 char array. We don't need utf16 char here.
237// jobject, jclass, and jmethodID are also a pointer to utf8 char array
238// Only a few JNI methods that are actually used in libnativeloader are mocked.
239JNINativeInterface* CreateJNINativeInterface() {
240 JNINativeInterface* inf = new JNINativeInterface();
241 memset(inf, 0, sizeof(JNINativeInterface));
242
243 inf->GetStringUTFChars = [](JNIEnv*, jstring s, jboolean*) -> const char* {
244 return reinterpret_cast<const char*>(s);
245 };
246
247 inf->ReleaseStringUTFChars = [](JNIEnv*, jstring, const char*) -> void { return; };
248
249 inf->NewStringUTF = [](JNIEnv*, const char* bytes) -> jstring {
250 return reinterpret_cast<jstring>(const_cast<char*>(bytes));
251 };
252
253 inf->FindClass = [](JNIEnv*, const char* name) -> jclass {
254 return reinterpret_cast<jclass>(const_cast<char*>(name));
255 };
256
257 inf->CallObjectMethodV = [](JNIEnv*, jobject obj, jmethodID mid, va_list) -> jobject {
258 if (strcmp("getParent", reinterpret_cast<const char*>(mid)) == 0) {
259 // JniObject_getParent can be a valid jobject or nullptr if there is
260 // no parent classloader.
261 const char* ret = mock->JniObject_getParent(reinterpret_cast<const char*>(obj));
262 return reinterpret_cast<jobject>(const_cast<char*>(ret));
263 }
264 return nullptr;
265 };
266
267 inf->GetMethodID = [](JNIEnv*, jclass, const char* name, const char*) -> jmethodID {
268 return reinterpret_cast<jmethodID>(const_cast<char*>(name));
269 };
270
271 inf->NewWeakGlobalRef = [](JNIEnv*, jobject obj) -> jobject { return obj; };
272
273 inf->IsSameObject = [](JNIEnv*, jobject a, jobject b) -> jboolean {
274 return strcmp(reinterpret_cast<const char*>(a), reinterpret_cast<const char*>(b)) == 0;
275 };
276
277 return inf;
278}
279
280static void* const any_nonnull = reinterpret_cast<void*>(0x12345678);
281
282// Custom matcher for comparing namespace handles
283MATCHER_P(NsEq, other, "") {
284 *result_listener << "comparing " << reinterpret_cast<const char*>(arg) << " and " << other;
285 return strcmp(reinterpret_cast<const char*>(arg), reinterpret_cast<const char*>(other)) == 0;
286}
287
288/////////////////////////////////////////////////////////////////
289
290// Test fixture
291class NativeLoaderTest : public ::testing::TestWithParam<bool> {
292 protected:
293 bool IsBridged() { return GetParam(); }
294
295 void SetUp() override {
Martin Stjernholm48297332019-11-12 21:21:32 +0000296 mock = std::make_unique<testing::NiceMock<MockPlatform>>(IsBridged());
Orion Hodson9b16e342019-10-09 13:29:16 +0100297
298 env = std::make_unique<JNIEnv>();
299 env->functions = CreateJNINativeInterface();
300 }
301
302 void SetExpectations() {
303 std::vector<std::string> default_public_libs =
304 android::base::Split(preloadable_public_libraries(), ":");
305 for (auto l : default_public_libs) {
306 EXPECT_CALL(*mock, dlopen(StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE))
307 .WillOnce(Return(any_nonnull));
308 }
309 }
310
311 void RunTest() { InitializeNativeLoader(); }
312
313 void TearDown() override {
314 ResetNativeLoader();
315 delete env->functions;
316 mock.reset();
317 }
318
319 std::unique_ptr<JNIEnv> env;
320};
321
322/////////////////////////////////////////////////////////////////
323
324TEST_P(NativeLoaderTest, InitializeLoadsDefaultPublicLibraries) {
325 SetExpectations();
326 RunTest();
327}
328
329INSTANTIATE_TEST_SUITE_P(NativeLoaderTests, NativeLoaderTest, testing::Bool());
330
331/////////////////////////////////////////////////////////////////
332
333class NativeLoaderTest_Create : public NativeLoaderTest {
334 protected:
335 // Test inputs (initialized to the default values). Overriding these
336 // must be done before calling SetExpectations() and RunTest().
337 uint32_t target_sdk_version = 29;
338 std::string class_loader = "my_classloader";
339 bool is_shared = false;
340 std::string dex_path = "/data/app/foo/classes.dex";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000341 std::string library_path = "/data/app/foo/" LIB_DIR "/arm";
342 std::string permitted_path = "/data/app/foo/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100343
344 // expected output (.. for the default test inputs)
345 std::string expected_namespace_name = "classloader-namespace";
346 uint64_t expected_namespace_flags =
347 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
348 std::string expected_library_path = library_path;
349 std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
350 std::string expected_parent_namespace = "platform";
351 bool expected_link_with_platform_ns = true;
352 bool expected_link_with_art_ns = true;
353 bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
354 bool expected_link_with_vndk_ns = false;
355 bool expected_link_with_default_ns = false;
356 bool expected_link_with_neuralnetworks_ns = true;
357 std::string expected_shared_libs_to_platform_ns = default_public_libraries();
358 std::string expected_shared_libs_to_art_ns = art_public_libraries();
359 std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
360 std::string expected_shared_libs_to_vndk_ns = vndksp_libraries();
361 std::string expected_shared_libs_to_default_ns = default_public_libraries();
362 std::string expected_shared_libs_to_neuralnetworks_ns = neuralnetworks_public_libraries();
363
364 void SetExpectations() {
365 NativeLoaderTest::SetExpectations();
366
367 ON_CALL(*mock, JniObject_getParent(StrEq(class_loader))).WillByDefault(Return(nullptr));
368
Martin Stjernholm48297332019-11-12 21:21:32 +0000369 EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(testing::AnyNumber());
370 EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(testing::AnyNumber());
Orion Hodson9b16e342019-10-09 13:29:16 +0100371
372 EXPECT_CALL(*mock, mock_create_namespace(
373 Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
374 StrEq(expected_library_path), expected_namespace_flags,
375 StrEq(expected_permitted_path), NsEq(expected_parent_namespace.c_str())))
376 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(dex_path.c_str()))));
377 if (expected_link_with_platform_ns) {
378 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("platform"),
379 StrEq(expected_shared_libs_to_platform_ns)))
380 .WillOnce(Return(true));
381 }
382 if (expected_link_with_art_ns) {
383 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("art"),
384 StrEq(expected_shared_libs_to_art_ns)))
385 .WillOnce(Return(true));
386 }
387 if (expected_link_with_sphal_ns) {
388 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("sphal"),
389 StrEq(expected_shared_libs_to_sphal_ns)))
390 .WillOnce(Return(true));
391 }
392 if (expected_link_with_vndk_ns) {
393 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk"),
394 StrEq(expected_shared_libs_to_vndk_ns)))
395 .WillOnce(Return(true));
396 }
397 if (expected_link_with_default_ns) {
398 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("default"),
399 StrEq(expected_shared_libs_to_default_ns)))
400 .WillOnce(Return(true));
401 }
402 if (expected_link_with_neuralnetworks_ns) {
403 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("neuralnetworks"),
404 StrEq(expected_shared_libs_to_neuralnetworks_ns)))
405 .WillOnce(Return(true));
406 }
407 }
408
409 void RunTest() {
410 NativeLoaderTest::RunTest();
411
412 jstring err = CreateClassLoaderNamespace(
413 env(), target_sdk_version, env()->NewStringUTF(class_loader.c_str()), is_shared,
414 env()->NewStringUTF(dex_path.c_str()), env()->NewStringUTF(library_path.c_str()),
415 env()->NewStringUTF(permitted_path.c_str()));
416
417 // no error
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100418 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100419
420 if (!IsBridged()) {
421 struct android_namespace_t* ns =
422 FindNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
423
424 // The created namespace is for this apk
425 EXPECT_EQ(dex_path.c_str(), reinterpret_cast<const char*>(ns));
426 } else {
427 struct NativeLoaderNamespace* ns =
428 FindNativeLoaderNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
429
430 // The created namespace is for the this apk
431 EXPECT_STREQ(dex_path.c_str(),
432 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
433 }
434 }
435
436 JNIEnv* env() { return NativeLoaderTest::env.get(); }
437};
438
439TEST_P(NativeLoaderTest_Create, DownloadedApp) {
440 SetExpectations();
441 RunTest();
442}
443
444TEST_P(NativeLoaderTest_Create, BundledSystemApp) {
445 dex_path = "/system/app/foo/foo.apk";
446 is_shared = true;
447
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100448 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100449 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
450 SetExpectations();
451 RunTest();
452}
453
454TEST_P(NativeLoaderTest_Create, BundledVendorApp) {
455 dex_path = "/vendor/app/foo/foo.apk";
456 is_shared = true;
457
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100458 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100459 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
460 SetExpectations();
461 RunTest();
462}
463
464TEST_P(NativeLoaderTest_Create, UnbundledVendorApp) {
465 dex_path = "/vendor/app/foo/foo.apk";
466 is_shared = false;
467
468 expected_namespace_name = "vendor-classloader-namespace";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000469 expected_library_path = expected_library_path + ":/vendor/" LIB_DIR;
470 expected_permitted_path = expected_permitted_path + ":/vendor/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100471 expected_shared_libs_to_platform_ns =
472 expected_shared_libs_to_platform_ns + ":" + llndk_libraries();
473 expected_link_with_vndk_ns = true;
474 SetExpectations();
475 RunTest();
476}
477
478TEST_P(NativeLoaderTest_Create, BundledProductApp_pre30) {
479 dex_path = "/product/app/foo/foo.apk";
480 is_shared = true;
481
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100482 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100483 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
484 SetExpectations();
485 RunTest();
486}
487
488TEST_P(NativeLoaderTest_Create, BundledProductApp_post30) {
489 dex_path = "/product/app/foo/foo.apk";
490 is_shared = true;
491 target_sdk_version = 30;
492
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100493 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100494 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
495 SetExpectations();
496 RunTest();
497}
498
499TEST_P(NativeLoaderTest_Create, UnbundledProductApp_pre30) {
500 dex_path = "/product/app/foo/foo.apk";
501 is_shared = false;
502 SetExpectations();
503 RunTest();
504}
505
506TEST_P(NativeLoaderTest_Create, UnbundledProductApp_post30) {
507 dex_path = "/product/app/foo/foo.apk";
508 is_shared = false;
509 target_sdk_version = 30;
510
511 expected_namespace_name = "vendor-classloader-namespace";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000512 expected_library_path = expected_library_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
513 expected_permitted_path =
514 expected_permitted_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100515 expected_shared_libs_to_platform_ns =
516 expected_shared_libs_to_platform_ns + ":" + llndk_libraries();
517 expected_link_with_vndk_ns = true;
518 SetExpectations();
519 RunTest();
520}
521
522TEST_P(NativeLoaderTest_Create, NamespaceForSharedLibIsNotUsedAsAnonymousNamespace) {
523 if (IsBridged()) {
524 // There is no shared lib in translated arch
525 // TODO(jiyong): revisit this
526 return;
527 }
528 // compared to apks, for java shared libs, library_path is empty; java shared
529 // libs don't have their own native libs. They use platform's.
530 library_path = "";
531 expected_library_path = library_path;
532 // no ALSO_USED_AS_ANONYMOUS
533 expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
534 SetExpectations();
535 RunTest();
536}
537
538TEST_P(NativeLoaderTest_Create, TwoApks) {
539 SetExpectations();
540 const uint32_t second_app_target_sdk_version = 29;
541 const std::string second_app_class_loader = "second_app_classloader";
542 const bool second_app_is_shared = false;
543 const std::string second_app_dex_path = "/data/app/bar/classes.dex";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000544 const std::string second_app_library_path = "/data/app/bar/" LIB_DIR "/arm";
545 const std::string second_app_permitted_path = "/data/app/bar/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100546 const std::string expected_second_app_permitted_path =
547 std::string("/data:/mnt/expand:") + second_app_permitted_path;
548 const std::string expected_second_app_parent_namespace = "classloader-namespace";
549 // no ALSO_USED_AS_ANONYMOUS
550 const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
551
552 // The scenario is that second app is loaded by the first app.
553 // So the first app's classloader (`classloader`) is parent of the second
554 // app's classloader.
555 ON_CALL(*mock, JniObject_getParent(StrEq(second_app_class_loader)))
556 .WillByDefault(Return(class_loader.c_str()));
557
558 // namespace for the second app is created. Its parent is set to the namespace
559 // of the first app.
560 EXPECT_CALL(*mock, mock_create_namespace(
561 Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
562 StrEq(second_app_library_path), expected_second_namespace_flags,
563 StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str())))
564 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
565 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
566 .WillRepeatedly(Return(true));
567
568 RunTest();
569 jstring err = CreateClassLoaderNamespace(
570 env(), second_app_target_sdk_version, env()->NewStringUTF(second_app_class_loader.c_str()),
571 second_app_is_shared, env()->NewStringUTF(second_app_dex_path.c_str()),
572 env()->NewStringUTF(second_app_library_path.c_str()),
573 env()->NewStringUTF(second_app_permitted_path.c_str()));
574
575 // success
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100576 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100577
578 if (!IsBridged()) {
579 struct android_namespace_t* ns =
580 FindNamespaceByClassLoader(env(), env()->NewStringUTF(second_app_class_loader.c_str()));
581
582 // The created namespace is for the second apk
583 EXPECT_EQ(second_app_dex_path.c_str(), reinterpret_cast<const char*>(ns));
584 } else {
585 struct NativeLoaderNamespace* ns = FindNativeLoaderNamespaceByClassLoader(
586 env(), env()->NewStringUTF(second_app_class_loader.c_str()));
587
588 // The created namespace is for the second apk
589 EXPECT_STREQ(second_app_dex_path.c_str(),
590 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
591 }
592}
593
594INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
595
596const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
597 [](const struct ConfigEntry&) -> Result<bool> { return true; };
598
599TEST(NativeLoaderConfigParser, NamesAndComments) {
600 const char file_content[] = R"(
601######
602
603libA.so
604#libB.so
605
606
607 libC.so
608libD.so
609 #### libE.so
610)";
611 const std::vector<std::string> expected_result = {"libA.so", "libC.so", "libD.so"};
612 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
613 ASSERT_TRUE(result) << result.error().message();
614 ASSERT_EQ(expected_result, *result);
615}
616
617TEST(NativeLoaderConfigParser, WithBitness) {
618 const char file_content[] = R"(
619libA.so 32
620libB.so 64
621libC.so
622)";
623#if defined(__LP64__)
624 const std::vector<std::string> expected_result = {"libB.so", "libC.so"};
625#else
626 const std::vector<std::string> expected_result = {"libA.so", "libC.so"};
627#endif
628 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
629 ASSERT_TRUE(result) << result.error().message();
630 ASSERT_EQ(expected_result, *result);
631}
632
633TEST(NativeLoaderConfigParser, WithNoPreload) {
634 const char file_content[] = R"(
635libA.so nopreload
636libB.so nopreload
637libC.so
638)";
639
640 const std::vector<std::string> expected_result = {"libC.so"};
641 Result<std::vector<std::string>> result =
642 ParseConfig(file_content,
643 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
644 ASSERT_TRUE(result) << result.error().message();
645 ASSERT_EQ(expected_result, *result);
646}
647
648TEST(NativeLoaderConfigParser, WithNoPreloadAndBitness) {
649 const char file_content[] = R"(
650libA.so nopreload 32
651libB.so 64 nopreload
652libC.so 32
653libD.so 64
654libE.so nopreload
655)";
656
657#if defined(__LP64__)
658 const std::vector<std::string> expected_result = {"libD.so"};
659#else
660 const std::vector<std::string> expected_result = {"libC.so"};
661#endif
662 Result<std::vector<std::string>> result =
663 ParseConfig(file_content,
664 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
665 ASSERT_TRUE(result) << result.error().message();
666 ASSERT_EQ(expected_result, *result);
667}
668
669TEST(NativeLoaderConfigParser, RejectMalformed) {
670 ASSERT_FALSE(ParseConfig("libA.so 32 64", always_true));
671 ASSERT_FALSE(ParseConfig("libA.so 32 32", always_true));
672 ASSERT_FALSE(ParseConfig("libA.so 32 nopreload 64", always_true));
673 ASSERT_FALSE(ParseConfig("32 libA.so nopreload", always_true));
674 ASSERT_FALSE(ParseConfig("nopreload libA.so 32", always_true));
675 ASSERT_FALSE(ParseConfig("libA.so nopreload # comment", always_true));
676}
677
678} // namespace nativeloader
679} // namespace android