blob: e36a7e6de2d9e8296c9f295306aa31040ab9753e [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;
Jooyung Han538f99a2020-03-03 00:46:50 +090041using internal::ParseJniConfig;
Martin Stjernholm48297332019-11-12 21:21:32 +000042
Martin Stjernholmbe08b202019-11-12 20:11:00 +000043#if defined(__LP64__)
44#define LIB_DIR "lib64"
45#else
46#define LIB_DIR "lib"
47#endif
48
Orion Hodson9b16e342019-10-09 13:29:16 +010049// gmock interface that represents interested platform APIs on libdl and libnativebridge
50class Platform {
51 public:
52 virtual ~Platform() {}
53
54 // libdl APIs
55 virtual void* dlopen(const char* filename, int flags) = 0;
56 virtual int dlclose(void* handle) = 0;
57 virtual char* dlerror(void) = 0;
58
59 // These mock_* are the APIs semantically the same across libdl and libnativebridge.
60 // Instead of having two set of mock APIs for the two, define only one set with an additional
61 // argument 'bool bridged' to identify the context (i.e., called for libdl or libnativebridge).
62 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
74 // libnativebridge APIs for which libdl has no corresponding APIs
75 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 = {
Kiyoung Kim99c19ca2020-01-29 16:09:38 +090096 {"system", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("system"))},
Orion Hodson9b16e342019-10-09 13:29:16 +010097 {"default", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("default"))},
Kiyoung Kim272b36d2020-02-19 16:08:47 +090098 {"com_android_art", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("com_android_art"))},
Orion Hodson9b16e342019-10-09 13:29:16 +010099 {"sphal", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("sphal"))},
100 {"vndk", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk"))},
Justin Yuneb4f08c2020-02-18 11:29:07 +0900101 {"vndk_product", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk_product"))},
Kiyoung Kim272b36d2020-02-19 16:08:47 +0900102 {"com_android_neuralnetworks", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("com_android_neuralnetworks"))},
103 {"com_android_cronet", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("com_android_cronet"))},
104 {"com_android_os_statsd", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("com_android_os_statsd"))},
Orion Hodson9b16e342019-10-09 13:29:16 +0100105};
106
107// The actual gmock object
108class MockPlatform : public Platform {
109 public:
110 explicit MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
111 ON_CALL(*this, NativeBridgeIsSupported(_)).WillByDefault(Return(is_bridged_));
112 ON_CALL(*this, NativeBridgeIsPathSupported(_)).WillByDefault(Return(is_bridged_));
113 ON_CALL(*this, mock_get_exported_namespace(_, _))
Martin Stjernholm48297332019-11-12 21:21:32 +0000114 .WillByDefault(testing::Invoke([](bool, const char* name) -> mock_namespace_handle {
Orion Hodson9b16e342019-10-09 13:29:16 +0100115 if (namespaces.find(name) != namespaces.end()) {
116 return namespaces[name];
117 }
118 return TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("(namespace not found"));
119 }));
120 }
121
122 // Mocking libdl APIs
123 MOCK_METHOD2(dlopen, void*(const char*, int));
124 MOCK_METHOD1(dlclose, int(void*));
125 MOCK_METHOD0(dlerror, char*());
126
127 // Mocking the common APIs
128 MOCK_METHOD3(mock_init_anonymous_namespace, bool(bool, const char*, const char*));
129 MOCK_METHOD7(mock_create_namespace,
130 mock_namespace_handle(bool, const char*, const char*, const char*, uint64_t,
131 const char*, mock_namespace_handle));
132 MOCK_METHOD4(mock_link_namespaces,
133 bool(bool, mock_namespace_handle, mock_namespace_handle, const char*));
134 MOCK_METHOD2(mock_get_exported_namespace, mock_namespace_handle(bool, const char*));
135 MOCK_METHOD4(mock_dlopen_ext, void*(bool, const char*, int, mock_namespace_handle));
136
137 // Mocking libnativebridge APIs
138 MOCK_METHOD0(NativeBridgeInitialized, bool());
139 MOCK_METHOD0(NativeBridgeGetError, const char*());
140 MOCK_METHOD1(NativeBridgeIsPathSupported, bool(const char*));
141 MOCK_METHOD1(NativeBridgeIsSupported, bool(const char*));
142
143 // Mocking "ClassLoader Object.getParent()"
144 MOCK_METHOD1(JniObject_getParent, const char*(const char*));
145
146 private:
147 bool is_bridged_;
148};
149
150static std::unique_ptr<MockPlatform> mock;
151
152// Provide C wrappers for the mock object.
153extern "C" {
154void* dlopen(const char* file, int flag) {
155 return mock->dlopen(file, flag);
156}
157
158int dlclose(void* handle) {
159 return mock->dlclose(handle);
160}
161
162char* dlerror(void) {
163 return mock->dlerror();
164}
165
166bool android_init_anonymous_namespace(const char* sonames, const char* search_path) {
167 return mock->mock_init_anonymous_namespace(false, sonames, search_path);
168}
169
170struct android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
171 const char* default_library_path,
172 uint64_t type,
173 const char* permitted_when_isolated_path,
174 struct android_namespace_t* parent) {
175 return TO_ANDROID_NAMESPACE(
176 mock->mock_create_namespace(false, name, ld_library_path, default_library_path, type,
177 permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
178}
179
180bool android_link_namespaces(struct android_namespace_t* from, struct android_namespace_t* to,
181 const char* sonames) {
182 return mock->mock_link_namespaces(false, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
183}
184
185struct android_namespace_t* android_get_exported_namespace(const char* name) {
186 return TO_ANDROID_NAMESPACE(mock->mock_get_exported_namespace(false, name));
187}
188
189void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* info) {
190 return mock->mock_dlopen_ext(false, filename, flags, TO_MOCK_NAMESPACE(info->library_namespace));
191}
192
193// libnativebridge APIs
194bool NativeBridgeIsSupported(const char* libpath) {
195 return mock->NativeBridgeIsSupported(libpath);
196}
197
198struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
199 return TO_BRIDGED_NAMESPACE(mock->mock_get_exported_namespace(true, name));
200}
201
202struct native_bridge_namespace_t* NativeBridgeCreateNamespace(
203 const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
204 const char* permitted_when_isolated_path, struct native_bridge_namespace_t* parent) {
205 return TO_BRIDGED_NAMESPACE(
206 mock->mock_create_namespace(true, name, ld_library_path, default_library_path, type,
207 permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
208}
209
210bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
211 struct native_bridge_namespace_t* to, const char* sonames) {
212 return mock->mock_link_namespaces(true, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
213}
214
215void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
216 struct native_bridge_namespace_t* ns) {
217 return mock->mock_dlopen_ext(true, libpath, flag, TO_MOCK_NAMESPACE(ns));
218}
219
220bool NativeBridgeInitialized() {
221 return mock->NativeBridgeInitialized();
222}
223
224bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
225 const char* anon_ns_library_path) {
226 return mock->mock_init_anonymous_namespace(true, public_ns_sonames, anon_ns_library_path);
227}
228
229const char* NativeBridgeGetError() {
230 return mock->NativeBridgeGetError();
231}
232
233bool NativeBridgeIsPathSupported(const char* path) {
234 return mock->NativeBridgeIsPathSupported(path);
235}
236
237} // extern "C"
238
239// A very simple JNI mock.
240// jstring is a pointer to utf8 char array. We don't need utf16 char here.
241// jobject, jclass, and jmethodID are also a pointer to utf8 char array
242// Only a few JNI methods that are actually used in libnativeloader are mocked.
243JNINativeInterface* CreateJNINativeInterface() {
244 JNINativeInterface* inf = new JNINativeInterface();
245 memset(inf, 0, sizeof(JNINativeInterface));
246
247 inf->GetStringUTFChars = [](JNIEnv*, jstring s, jboolean*) -> const char* {
248 return reinterpret_cast<const char*>(s);
249 };
250
251 inf->ReleaseStringUTFChars = [](JNIEnv*, jstring, const char*) -> void { return; };
252
253 inf->NewStringUTF = [](JNIEnv*, const char* bytes) -> jstring {
254 return reinterpret_cast<jstring>(const_cast<char*>(bytes));
255 };
256
257 inf->FindClass = [](JNIEnv*, const char* name) -> jclass {
258 return reinterpret_cast<jclass>(const_cast<char*>(name));
259 };
260
261 inf->CallObjectMethodV = [](JNIEnv*, jobject obj, jmethodID mid, va_list) -> jobject {
262 if (strcmp("getParent", reinterpret_cast<const char*>(mid)) == 0) {
263 // JniObject_getParent can be a valid jobject or nullptr if there is
264 // no parent classloader.
265 const char* ret = mock->JniObject_getParent(reinterpret_cast<const char*>(obj));
266 return reinterpret_cast<jobject>(const_cast<char*>(ret));
267 }
268 return nullptr;
269 };
270
271 inf->GetMethodID = [](JNIEnv*, jclass, const char* name, const char*) -> jmethodID {
272 return reinterpret_cast<jmethodID>(const_cast<char*>(name));
273 };
274
275 inf->NewWeakGlobalRef = [](JNIEnv*, jobject obj) -> jobject { return obj; };
276
277 inf->IsSameObject = [](JNIEnv*, jobject a, jobject b) -> jboolean {
278 return strcmp(reinterpret_cast<const char*>(a), reinterpret_cast<const char*>(b)) == 0;
279 };
280
281 return inf;
282}
283
284static void* const any_nonnull = reinterpret_cast<void*>(0x12345678);
285
286// Custom matcher for comparing namespace handles
287MATCHER_P(NsEq, other, "") {
288 *result_listener << "comparing " << reinterpret_cast<const char*>(arg) << " and " << other;
289 return strcmp(reinterpret_cast<const char*>(arg), reinterpret_cast<const char*>(other)) == 0;
290}
291
292/////////////////////////////////////////////////////////////////
293
294// Test fixture
295class NativeLoaderTest : public ::testing::TestWithParam<bool> {
296 protected:
297 bool IsBridged() { return GetParam(); }
298
299 void SetUp() override {
Martin Stjernholm48297332019-11-12 21:21:32 +0000300 mock = std::make_unique<testing::NiceMock<MockPlatform>>(IsBridged());
Orion Hodson9b16e342019-10-09 13:29:16 +0100301
302 env = std::make_unique<JNIEnv>();
303 env->functions = CreateJNINativeInterface();
304 }
305
306 void SetExpectations() {
307 std::vector<std::string> default_public_libs =
308 android::base::Split(preloadable_public_libraries(), ":");
309 for (auto l : default_public_libs) {
310 EXPECT_CALL(*mock, dlopen(StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE))
311 .WillOnce(Return(any_nonnull));
312 }
313 }
314
315 void RunTest() { InitializeNativeLoader(); }
316
317 void TearDown() override {
318 ResetNativeLoader();
319 delete env->functions;
320 mock.reset();
321 }
322
323 std::unique_ptr<JNIEnv> env;
324};
325
326/////////////////////////////////////////////////////////////////
327
328TEST_P(NativeLoaderTest, InitializeLoadsDefaultPublicLibraries) {
329 SetExpectations();
330 RunTest();
331}
332
333INSTANTIATE_TEST_SUITE_P(NativeLoaderTests, NativeLoaderTest, testing::Bool());
334
335/////////////////////////////////////////////////////////////////
336
337class NativeLoaderTest_Create : public NativeLoaderTest {
338 protected:
339 // Test inputs (initialized to the default values). Overriding these
340 // must be done before calling SetExpectations() and RunTest().
341 uint32_t target_sdk_version = 29;
342 std::string class_loader = "my_classloader";
343 bool is_shared = false;
344 std::string dex_path = "/data/app/foo/classes.dex";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000345 std::string library_path = "/data/app/foo/" LIB_DIR "/arm";
346 std::string permitted_path = "/data/app/foo/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100347
348 // expected output (.. for the default test inputs)
349 std::string expected_namespace_name = "classloader-namespace";
350 uint64_t expected_namespace_flags =
351 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
352 std::string expected_library_path = library_path;
353 std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
Kiyoung Kim99c19ca2020-01-29 16:09:38 +0900354 std::string expected_parent_namespace = "system";
Orion Hodson9b16e342019-10-09 13:29:16 +0100355 bool expected_link_with_platform_ns = true;
356 bool expected_link_with_art_ns = true;
357 bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
358 bool expected_link_with_vndk_ns = false;
Justin Yuneb4f08c2020-02-18 11:29:07 +0900359 bool expected_link_with_vndk_product_ns = false;
Orion Hodson9b16e342019-10-09 13:29:16 +0100360 bool expected_link_with_default_ns = false;
361 bool expected_link_with_neuralnetworks_ns = true;
Luke Huang5c017722019-12-17 10:54:26 +0800362 bool expected_link_with_cronet_ns = true;
Jeffrey Huang52575032020-02-11 17:33:45 -0800363 bool expected_link_with_statsd_ns = true;
Orion Hodson9b16e342019-10-09 13:29:16 +0100364 std::string expected_shared_libs_to_platform_ns = default_public_libraries();
365 std::string expected_shared_libs_to_art_ns = art_public_libraries();
366 std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
Justin Yuneb4f08c2020-02-18 11:29:07 +0900367 std::string expected_shared_libs_to_vndk_ns = vndksp_libraries_vendor();
368 std::string expected_shared_libs_to_vndk_product_ns = vndksp_libraries_product();
Orion Hodson9b16e342019-10-09 13:29:16 +0100369 std::string expected_shared_libs_to_default_ns = default_public_libraries();
370 std::string expected_shared_libs_to_neuralnetworks_ns = neuralnetworks_public_libraries();
Luke Huang5c017722019-12-17 10:54:26 +0800371 std::string expected_shared_libs_to_cronet_ns = cronet_public_libraries();
Jeffrey Huang52575032020-02-11 17:33:45 -0800372 std::string expected_shared_libs_to_statsd_ns = statsd_public_libraries();
Orion Hodson9b16e342019-10-09 13:29:16 +0100373
374 void SetExpectations() {
375 NativeLoaderTest::SetExpectations();
376
377 ON_CALL(*mock, JniObject_getParent(StrEq(class_loader))).WillByDefault(Return(nullptr));
378
Martin Stjernholm48297332019-11-12 21:21:32 +0000379 EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(testing::AnyNumber());
380 EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(testing::AnyNumber());
Orion Hodson9b16e342019-10-09 13:29:16 +0100381
382 EXPECT_CALL(*mock, mock_create_namespace(
383 Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
384 StrEq(expected_library_path), expected_namespace_flags,
385 StrEq(expected_permitted_path), NsEq(expected_parent_namespace.c_str())))
386 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(dex_path.c_str()))));
387 if (expected_link_with_platform_ns) {
Kiyoung Kim99c19ca2020-01-29 16:09:38 +0900388 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("system"),
Orion Hodson9b16e342019-10-09 13:29:16 +0100389 StrEq(expected_shared_libs_to_platform_ns)))
390 .WillOnce(Return(true));
391 }
392 if (expected_link_with_art_ns) {
Kiyoung Kim272b36d2020-02-19 16:08:47 +0900393 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_art"),
Orion Hodson9b16e342019-10-09 13:29:16 +0100394 StrEq(expected_shared_libs_to_art_ns)))
395 .WillOnce(Return(true));
396 }
397 if (expected_link_with_sphal_ns) {
398 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("sphal"),
399 StrEq(expected_shared_libs_to_sphal_ns)))
400 .WillOnce(Return(true));
401 }
402 if (expected_link_with_vndk_ns) {
403 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk"),
404 StrEq(expected_shared_libs_to_vndk_ns)))
405 .WillOnce(Return(true));
406 }
Justin Yuneb4f08c2020-02-18 11:29:07 +0900407 if (expected_link_with_vndk_product_ns) {
408 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk_product"),
409 StrEq(expected_shared_libs_to_vndk_product_ns)))
410 .WillOnce(Return(true));
411 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100412 if (expected_link_with_default_ns) {
413 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("default"),
414 StrEq(expected_shared_libs_to_default_ns)))
415 .WillOnce(Return(true));
416 }
417 if (expected_link_with_neuralnetworks_ns) {
Kiyoung Kim272b36d2020-02-19 16:08:47 +0900418 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_neuralnetworks"),
Orion Hodson9b16e342019-10-09 13:29:16 +0100419 StrEq(expected_shared_libs_to_neuralnetworks_ns)))
420 .WillOnce(Return(true));
421 }
Luke Huang5c017722019-12-17 10:54:26 +0800422 if (expected_link_with_cronet_ns) {
Kiyoung Kim272b36d2020-02-19 16:08:47 +0900423 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_cronet"),
Luke Huang5c017722019-12-17 10:54:26 +0800424 StrEq(expected_shared_libs_to_cronet_ns)))
425 .WillOnce(Return(true));
426 }
Jeffrey Huang52575032020-02-11 17:33:45 -0800427 if (expected_link_with_statsd_ns) {
Kiyoung Kim272b36d2020-02-19 16:08:47 +0900428 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_os_statsd"),
Jeffrey Huang52575032020-02-11 17:33:45 -0800429 StrEq(expected_shared_libs_to_statsd_ns)))
430 .WillOnce(Return(true));
431 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100432 }
433
434 void RunTest() {
435 NativeLoaderTest::RunTest();
436
437 jstring err = CreateClassLoaderNamespace(
438 env(), target_sdk_version, env()->NewStringUTF(class_loader.c_str()), is_shared,
439 env()->NewStringUTF(dex_path.c_str()), env()->NewStringUTF(library_path.c_str()),
440 env()->NewStringUTF(permitted_path.c_str()));
441
442 // no error
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100443 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100444
445 if (!IsBridged()) {
446 struct android_namespace_t* ns =
447 FindNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
448
449 // The created namespace is for this apk
450 EXPECT_EQ(dex_path.c_str(), reinterpret_cast<const char*>(ns));
451 } else {
452 struct NativeLoaderNamespace* ns =
453 FindNativeLoaderNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
454
455 // The created namespace is for the this apk
456 EXPECT_STREQ(dex_path.c_str(),
457 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
458 }
459 }
460
461 JNIEnv* env() { return NativeLoaderTest::env.get(); }
462};
463
464TEST_P(NativeLoaderTest_Create, DownloadedApp) {
465 SetExpectations();
466 RunTest();
467}
468
469TEST_P(NativeLoaderTest_Create, BundledSystemApp) {
470 dex_path = "/system/app/foo/foo.apk";
471 is_shared = true;
472
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100473 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100474 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
475 SetExpectations();
476 RunTest();
477}
478
479TEST_P(NativeLoaderTest_Create, BundledVendorApp) {
480 dex_path = "/vendor/app/foo/foo.apk";
481 is_shared = true;
482
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100483 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100484 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
485 SetExpectations();
486 RunTest();
487}
488
489TEST_P(NativeLoaderTest_Create, UnbundledVendorApp) {
490 dex_path = "/vendor/app/foo/foo.apk";
491 is_shared = false;
492
493 expected_namespace_name = "vendor-classloader-namespace";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000494 expected_library_path = expected_library_path + ":/vendor/" LIB_DIR;
495 expected_permitted_path = expected_permitted_path + ":/vendor/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100496 expected_shared_libs_to_platform_ns =
Justin Yun089c1352020-02-06 16:53:08 +0900497 expected_shared_libs_to_platform_ns + ":" + llndk_libraries_vendor();
Orion Hodson9b16e342019-10-09 13:29:16 +0100498 expected_link_with_vndk_ns = true;
499 SetExpectations();
500 RunTest();
501}
502
Justin Yun3db26d52019-12-16 14:09:39 +0900503TEST_P(NativeLoaderTest_Create, BundledProductApp) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100504 dex_path = "/product/app/foo/foo.apk";
505 is_shared = true;
506
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100507 expected_namespace_name = "classloader-namespace-shared";
Orion Hodson9b16e342019-10-09 13:29:16 +0100508 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
509 SetExpectations();
510 RunTest();
511}
512
Justin Yun3db26d52019-12-16 14:09:39 +0900513TEST_P(NativeLoaderTest_Create, UnbundledProductApp) {
Orion Hodson9b16e342019-10-09 13:29:16 +0100514 dex_path = "/product/app/foo/foo.apk";
515 is_shared = false;
Orion Hodson9b16e342019-10-09 13:29:16 +0100516
Justin Yun3db26d52019-12-16 14:09:39 +0900517 if (is_product_vndk_version_defined()) {
518 expected_namespace_name = "vendor-classloader-namespace";
519 expected_library_path = expected_library_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
520 expected_permitted_path =
521 expected_permitted_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
522 expected_shared_libs_to_platform_ns =
Justin Yun089c1352020-02-06 16:53:08 +0900523 expected_shared_libs_to_platform_ns + ":" + llndk_libraries_product();
Justin Yuneb4f08c2020-02-18 11:29:07 +0900524 expected_link_with_vndk_product_ns = true;
Justin Yun3db26d52019-12-16 14:09:39 +0900525 }
Orion Hodson9b16e342019-10-09 13:29:16 +0100526 SetExpectations();
527 RunTest();
528}
529
530TEST_P(NativeLoaderTest_Create, NamespaceForSharedLibIsNotUsedAsAnonymousNamespace) {
531 if (IsBridged()) {
532 // There is no shared lib in translated arch
533 // TODO(jiyong): revisit this
534 return;
535 }
536 // compared to apks, for java shared libs, library_path is empty; java shared
537 // libs don't have their own native libs. They use platform's.
538 library_path = "";
539 expected_library_path = library_path;
540 // no ALSO_USED_AS_ANONYMOUS
541 expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
542 SetExpectations();
543 RunTest();
544}
545
546TEST_P(NativeLoaderTest_Create, TwoApks) {
547 SetExpectations();
548 const uint32_t second_app_target_sdk_version = 29;
549 const std::string second_app_class_loader = "second_app_classloader";
550 const bool second_app_is_shared = false;
551 const std::string second_app_dex_path = "/data/app/bar/classes.dex";
Martin Stjernholmbe08b202019-11-12 20:11:00 +0000552 const std::string second_app_library_path = "/data/app/bar/" LIB_DIR "/arm";
553 const std::string second_app_permitted_path = "/data/app/bar/" LIB_DIR;
Orion Hodson9b16e342019-10-09 13:29:16 +0100554 const std::string expected_second_app_permitted_path =
555 std::string("/data:/mnt/expand:") + second_app_permitted_path;
556 const std::string expected_second_app_parent_namespace = "classloader-namespace";
557 // no ALSO_USED_AS_ANONYMOUS
558 const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
559
560 // The scenario is that second app is loaded by the first app.
561 // So the first app's classloader (`classloader`) is parent of the second
562 // app's classloader.
563 ON_CALL(*mock, JniObject_getParent(StrEq(second_app_class_loader)))
564 .WillByDefault(Return(class_loader.c_str()));
565
566 // namespace for the second app is created. Its parent is set to the namespace
567 // of the first app.
568 EXPECT_CALL(*mock, mock_create_namespace(
569 Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
570 StrEq(second_app_library_path), expected_second_namespace_flags,
571 StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str())))
572 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
573 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
574 .WillRepeatedly(Return(true));
575
576 RunTest();
577 jstring err = CreateClassLoaderNamespace(
578 env(), second_app_target_sdk_version, env()->NewStringUTF(second_app_class_loader.c_str()),
579 second_app_is_shared, env()->NewStringUTF(second_app_dex_path.c_str()),
580 env()->NewStringUTF(second_app_library_path.c_str()),
581 env()->NewStringUTF(second_app_permitted_path.c_str()));
582
583 // success
Martin Stjernholm94fd9ea2019-10-24 16:57:34 +0100584 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
Orion Hodson9b16e342019-10-09 13:29:16 +0100585
586 if (!IsBridged()) {
587 struct android_namespace_t* ns =
588 FindNamespaceByClassLoader(env(), env()->NewStringUTF(second_app_class_loader.c_str()));
589
590 // The created namespace is for the second apk
591 EXPECT_EQ(second_app_dex_path.c_str(), reinterpret_cast<const char*>(ns));
592 } else {
593 struct NativeLoaderNamespace* ns = FindNativeLoaderNamespaceByClassLoader(
594 env(), env()->NewStringUTF(second_app_class_loader.c_str()));
595
596 // The created namespace is for the second apk
597 EXPECT_STREQ(second_app_dex_path.c_str(),
598 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
599 }
600}
601
602INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
603
604const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
605 [](const struct ConfigEntry&) -> Result<bool> { return true; };
606
607TEST(NativeLoaderConfigParser, NamesAndComments) {
608 const char file_content[] = R"(
609######
610
611libA.so
612#libB.so
613
614
615 libC.so
616libD.so
617 #### libE.so
618)";
619 const std::vector<std::string> expected_result = {"libA.so", "libC.so", "libD.so"};
620 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900621 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100622 ASSERT_EQ(expected_result, *result);
623}
624
625TEST(NativeLoaderConfigParser, WithBitness) {
626 const char file_content[] = R"(
627libA.so 32
628libB.so 64
629libC.so
630)";
631#if defined(__LP64__)
632 const std::vector<std::string> expected_result = {"libB.so", "libC.so"};
633#else
634 const std::vector<std::string> expected_result = {"libA.so", "libC.so"};
635#endif
636 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900637 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100638 ASSERT_EQ(expected_result, *result);
639}
640
641TEST(NativeLoaderConfigParser, WithNoPreload) {
642 const char file_content[] = R"(
643libA.so nopreload
644libB.so nopreload
645libC.so
646)";
647
648 const std::vector<std::string> expected_result = {"libC.so"};
649 Result<std::vector<std::string>> result =
650 ParseConfig(file_content,
651 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900652 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100653 ASSERT_EQ(expected_result, *result);
654}
655
656TEST(NativeLoaderConfigParser, WithNoPreloadAndBitness) {
657 const char file_content[] = R"(
658libA.so nopreload 32
659libB.so 64 nopreload
660libC.so 32
661libD.so 64
662libE.so nopreload
663)";
664
665#if defined(__LP64__)
666 const std::vector<std::string> expected_result = {"libD.so"};
667#else
668 const std::vector<std::string> expected_result = {"libC.so"};
669#endif
670 Result<std::vector<std::string>> result =
671 ParseConfig(file_content,
672 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900673 ASSERT_RESULT_OK(result);
Orion Hodson9b16e342019-10-09 13:29:16 +0100674 ASSERT_EQ(expected_result, *result);
675}
676
677TEST(NativeLoaderConfigParser, RejectMalformed) {
Bernie Innocentiac5ae3c2020-02-12 10:43:42 +0900678 ASSERT_FALSE(ParseConfig("libA.so 32 64", always_true).ok());
679 ASSERT_FALSE(ParseConfig("libA.so 32 32", always_true).ok());
680 ASSERT_FALSE(ParseConfig("libA.so 32 nopreload 64", always_true).ok());
681 ASSERT_FALSE(ParseConfig("32 libA.so nopreload", always_true).ok());
682 ASSERT_FALSE(ParseConfig("nopreload libA.so 32", always_true).ok());
683 ASSERT_FALSE(ParseConfig("libA.so nopreload # comment", always_true).ok());
Orion Hodson9b16e342019-10-09 13:29:16 +0100684}
685
Jooyung Han538f99a2020-03-03 00:46:50 +0900686TEST(NativeLoaderJniConfigParser, BasicLoading) {
687 const char file_content[] = R"(
688# comment
689com_android_foo libfoo.so
690# Empty line is ignored
691
692com_android_bar libbar.so:libbar2.so
693)";
694
695 std::map<std::string, std::string> expected_result{
696 {"com_android_foo", "libfoo.so"},
697 {"com_android_bar", "libbar.so:libbar2.so"},
698 };
699
700 Result<std::map<std::string, std::string>> result = ParseJniConfig(file_content);
701 ASSERT_RESULT_OK(result);
702 ASSERT_EQ(expected_result, *result);
703}
704
705TEST(NativeLoaderJniConfigParser, RejectMalformed) {
706 ASSERT_FALSE(ParseJniConfig("com_android_foo").ok());
707}
708
Orion Hodson9b16e342019-10-09 13:29:16 +0100709} // namespace nativeloader
710} // namespace android