1 /*
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 "native_loader_test.h"
18
19 #include <functional>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <unordered_map>
24 #include <vector>
25
26 #include "android-base/properties.h"
27 #include "android-base/result.h"
28 #include "android-base/stringprintf.h"
29 #include "android-base/strings.h"
30 #include "dlfcn.h"
31 #include "gmock/gmock.h"
32 #include "gtest/gtest.h"
33 #include "jni.h"
34 #include "native_loader_namespace.h"
35 #include "nativehelper/scoped_utf_chars.h"
36 #include "nativeloader/dlext_namespaces.h"
37 #include "nativeloader/native_loader.h"
38 #include "public_libraries.h"
39
40 namespace android {
41 namespace nativeloader {
42
43 using internal::ConfigEntry; // NOLINT - ConfigEntry is actually used
44 using internal::ParseApexLibrariesConfig;
45 using internal::ParseConfig;
46 using ::testing::_;
47 using ::testing::Eq;
48 using ::testing::NotNull;
49 using ::testing::Return;
50 using ::testing::StartsWith;
51 using ::testing::StrEq;
52
53 #if defined(__LP64__)
54 #define LIB_DIR "lib64"
55 #else
56 #define LIB_DIR "lib"
57 #endif
58
59 // gmock interface that represents interesting platform APIs in libdl_android and libnativebridge
60 class Platform {
61 public:
~Platform()62 virtual ~Platform() {}
63
64 // These mock_* are the APIs semantically the same across libdl_android and libnativebridge.
65 // Instead of having two set of mock APIs for the two, define only one set with an additional
66 // argument 'bool bridged' to identify the context (i.e., called for libdl_android or
67 // libnativebridge).
68 using mock_namespace_handle = char*;
69 virtual bool mock_init_anonymous_namespace(bool bridged,
70 const char* sonames,
71 const char* search_paths) = 0;
72 virtual mock_namespace_handle mock_create_namespace(bool bridged,
73 const char* name,
74 const char* ld_library_path,
75 const char* default_library_path,
76 uint64_t type,
77 const char* permitted_when_isolated_path,
78 mock_namespace_handle parent) = 0;
79 virtual bool mock_link_namespaces(bool bridged,
80 mock_namespace_handle from,
81 mock_namespace_handle to,
82 const char* sonames) = 0;
83 virtual mock_namespace_handle mock_get_exported_namespace(bool bridged, const char* name) = 0;
84 virtual void* mock_dlopen_ext(bool bridged,
85 const char* filename,
86 int flags,
87 mock_namespace_handle ns) = 0;
88
89 // libnativebridge APIs for which libdl_android has no corresponding APIs
90 virtual bool NativeBridgeInitialized() = 0;
91 virtual const char* NativeBridgeGetError() = 0;
92 virtual bool NativeBridgeIsPathSupported(const char*) = 0;
93 virtual bool NativeBridgeIsSupported(const char*) = 0;
94 };
95
96 // The mock does not actually create a namespace object. But simply casts the pointer to the
97 // string for the namespace name as the handle to the namespace object.
98 #define TO_ANDROID_NAMESPACE(str) \
99 reinterpret_cast<struct android_namespace_t*>(const_cast<char*>(str))
100
101 #define TO_BRIDGED_NAMESPACE(str) \
102 reinterpret_cast<struct native_bridge_namespace_t*>(const_cast<char*>(str))
103
104 #define TO_MOCK_NAMESPACE(ns) reinterpret_cast<Platform::mock_namespace_handle>(ns)
105
106 // These represents built-in namespaces created by the linker according to ld.config.txt
107 static std::unordered_map<std::string, Platform::mock_namespace_handle> namespaces = {
108 #define NAMESPACE_ENTRY(ns) \
109 { ns, TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(ns)) }
110 NAMESPACE_ENTRY("com_android_i18n"),
111 NAMESPACE_ENTRY("com_android_neuralnetworks"),
112 NAMESPACE_ENTRY("com_android_art"),
113
114 // TODO(b/191644631) This can be removed when the test becomes more test-friendly.
115 // This is added so that the test can exercise the JNI lib related behavior.
116 NAMESPACE_ENTRY("com_android_conscrypt"),
117
118 NAMESPACE_ENTRY("default"),
119 NAMESPACE_ENTRY("sphal"),
120 NAMESPACE_ENTRY("product"),
121 NAMESPACE_ENTRY("system"),
122 NAMESPACE_ENTRY("vndk"),
123 NAMESPACE_ENTRY("vndk_product"),
124 #undef NAMESPACE_ENTRY
125 };
126
127 // The actual gmock object
128 class MockPlatform : public Platform {
129 public:
MockPlatform(bool is_bridged)130 explicit MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
131 ON_CALL(*this, NativeBridgeIsSupported(_)).WillByDefault(Return(is_bridged_));
132 ON_CALL(*this, NativeBridgeIsPathSupported(_)).WillByDefault(Return(is_bridged_));
133 ON_CALL(*this, mock_get_exported_namespace(_, _))
134 .WillByDefault(testing::Invoke([](bool, const char* name) -> mock_namespace_handle {
135 if (namespaces.find(name) != namespaces.end()) {
136 return namespaces[name];
137 }
138 std::string msg = android::base::StringPrintf("(namespace %s not found)", name);
139 // The strdup'ed string will leak, but the test is already failing if we get here.
140 return TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(strdup(msg.c_str())));
141 }));
142 }
143
144 // Mocking the common APIs
145 MOCK_METHOD3(mock_init_anonymous_namespace, bool(bool, const char*, const char*));
146 MOCK_METHOD7(mock_create_namespace,
147 mock_namespace_handle(bool,
148 const char*,
149 const char*,
150 const char*,
151 uint64_t,
152 const char*,
153 mock_namespace_handle));
154 MOCK_METHOD4(mock_link_namespaces,
155 bool(bool, mock_namespace_handle, mock_namespace_handle, const char*));
156 MOCK_METHOD2(mock_get_exported_namespace, mock_namespace_handle(bool, const char*));
157 MOCK_METHOD4(mock_dlopen_ext, void*(bool, const char*, int, mock_namespace_handle));
158
159 // Mocking libnativebridge APIs
160 MOCK_METHOD0(NativeBridgeInitialized, bool());
161 MOCK_METHOD0(NativeBridgeGetError, const char*());
162 MOCK_METHOD1(NativeBridgeIsPathSupported, bool(const char*));
163 MOCK_METHOD1(NativeBridgeIsSupported, bool(const char*));
164
165 private:
166 bool is_bridged_;
167 };
168
169 static std::unique_ptr<MockPlatform> mock;
170
171 // Provide C wrappers for the mock object. These symbols must be exported by ld
172 // to be able to override the real symbols in the shared libs.
173 extern "C" {
174
175 // libdl_android APIs
176
android_init_anonymous_namespace(const char * sonames,const char * search_path)177 bool android_init_anonymous_namespace(const char* sonames, const char* search_path) {
178 return mock->mock_init_anonymous_namespace(false, sonames, search_path);
179 }
180
android_create_namespace(const char * name,const char * ld_library_path,const char * default_library_path,uint64_t type,const char * permitted_when_isolated_path,struct android_namespace_t * parent)181 struct android_namespace_t* android_create_namespace(const char* name,
182 const char* ld_library_path,
183 const char* default_library_path,
184 uint64_t type,
185 const char* permitted_when_isolated_path,
186 struct android_namespace_t* parent) {
187 return TO_ANDROID_NAMESPACE(mock->mock_create_namespace(false,
188 name,
189 ld_library_path,
190 default_library_path,
191 type,
192 permitted_when_isolated_path,
193 TO_MOCK_NAMESPACE(parent)));
194 }
195
android_link_namespaces(struct android_namespace_t * from,struct android_namespace_t * to,const char * sonames)196 bool android_link_namespaces(struct android_namespace_t* from,
197 struct android_namespace_t* to,
198 const char* sonames) {
199 return mock->mock_link_namespaces(false, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
200 }
201
android_get_exported_namespace(const char * name)202 struct android_namespace_t* android_get_exported_namespace(const char* name) {
203 return TO_ANDROID_NAMESPACE(mock->mock_get_exported_namespace(false, name));
204 }
205
android_dlopen_ext(const char * filename,int flags,const android_dlextinfo * info)206 void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* info) {
207 return mock->mock_dlopen_ext(false, filename, flags, TO_MOCK_NAMESPACE(info->library_namespace));
208 }
209
210 // libnativebridge APIs
211
NativeBridgeIsSupported(const char * libpath)212 bool NativeBridgeIsSupported(const char* libpath) { return mock->NativeBridgeIsSupported(libpath); }
213
NativeBridgeGetExportedNamespace(const char * name)214 struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
215 return TO_BRIDGED_NAMESPACE(mock->mock_get_exported_namespace(true, name));
216 }
217
NativeBridgeCreateNamespace(const char * name,const char * ld_library_path,const char * default_library_path,uint64_t type,const char * permitted_when_isolated_path,struct native_bridge_namespace_t * parent)218 struct native_bridge_namespace_t* NativeBridgeCreateNamespace(
219 const char* name,
220 const char* ld_library_path,
221 const char* default_library_path,
222 uint64_t type,
223 const char* permitted_when_isolated_path,
224 struct native_bridge_namespace_t* parent) {
225 return TO_BRIDGED_NAMESPACE(mock->mock_create_namespace(true,
226 name,
227 ld_library_path,
228 default_library_path,
229 type,
230 permitted_when_isolated_path,
231 TO_MOCK_NAMESPACE(parent)));
232 }
233
NativeBridgeLinkNamespaces(struct native_bridge_namespace_t * from,struct native_bridge_namespace_t * to,const char * sonames)234 bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
235 struct native_bridge_namespace_t* to,
236 const char* sonames) {
237 return mock->mock_link_namespaces(true, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
238 }
239
NativeBridgeLoadLibraryExt(const char * libpath,int flag,struct native_bridge_namespace_t * ns)240 void* NativeBridgeLoadLibraryExt(const char* libpath,
241 int flag,
242 struct native_bridge_namespace_t* ns) {
243 return mock->mock_dlopen_ext(true, libpath, flag, TO_MOCK_NAMESPACE(ns));
244 }
245
NativeBridgeInitialized()246 bool NativeBridgeInitialized() { return mock->NativeBridgeInitialized(); }
247
NativeBridgeInitAnonymousNamespace(const char * public_ns_sonames,const char * anon_ns_library_path)248 bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
249 const char* anon_ns_library_path) {
250 return mock->mock_init_anonymous_namespace(true, public_ns_sonames, anon_ns_library_path);
251 }
252
NativeBridgeGetError()253 const char* NativeBridgeGetError() { return mock->NativeBridgeGetError(); }
254
NativeBridgeIsPathSupported(const char * path)255 bool NativeBridgeIsPathSupported(const char* path) {
256 return mock->NativeBridgeIsPathSupported(path);
257 }
258
259 } // extern "C"
260
261 static void* const any_nonnull = reinterpret_cast<void*>(0x12345678);
262
263 // Custom matcher for comparing namespace handles
264 MATCHER_P(NsEq, other, "") {
265 *result_listener << "comparing " << reinterpret_cast<const char*>(arg) << " and " << other;
266 return strcmp(reinterpret_cast<const char*>(arg), reinterpret_cast<const char*>(other)) == 0;
267 }
268
269 /////////////////////////////////////////////////////////////////
270
271 // Test fixture
272 class NativeLoaderTest : public ::testing::TestWithParam<bool> {
273 protected:
IsBridged()274 bool IsBridged() { return GetParam(); }
275
SetUp()276 void SetUp() override {
277 mock = std::make_unique<testing::NiceMock<MockPlatform>>(IsBridged());
278 jni_mock = std::make_unique<testing::NiceMock<MockJni>>();
279
280 env = std::make_unique<JNIEnv>();
281 env->functions = CreateJNINativeInterface();
282 }
283
SetExpectations()284 void SetExpectations() {
285 std::vector<std::string> default_public_libs =
286 android::base::Split(preloadable_public_libraries(), ":");
287 for (const std::string& l : default_public_libs) {
288 EXPECT_CALL(*mock,
289 mock_dlopen_ext(false, StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE, NotNull()))
290 .WillOnce(Return(any_nonnull));
291 }
292 }
293
RunTest()294 void RunTest() { InitializeNativeLoader(); }
295
TearDown()296 void TearDown() override {
297 ResetNativeLoader();
298 delete env->functions;
299 mock.reset();
300 }
301
302 std::unique_ptr<JNIEnv> env;
303 };
304
305 /////////////////////////////////////////////////////////////////
306
TEST_P(NativeLoaderTest,InitializeLoadsDefaultPublicLibraries)307 TEST_P(NativeLoaderTest, InitializeLoadsDefaultPublicLibraries) {
308 SetExpectations();
309 RunTest();
310 }
311
TEST_P(NativeLoaderTest,OpenNativeLibraryWithoutClassloaderInApex)312 TEST_P(NativeLoaderTest, OpenNativeLibraryWithoutClassloaderInApex) {
313 const char* test_lib_path = "libfoo.so";
314 void* fake_handle = &fake_handle; // Arbitrary non-null value
315 EXPECT_CALL(*mock,
316 mock_dlopen_ext(false, StrEq(test_lib_path), RTLD_NOW, NsEq("com_android_art")))
317 .WillOnce(Return(fake_handle));
318
319 bool needs_native_bridge = false;
320 char* errmsg = nullptr;
321 EXPECT_EQ(fake_handle,
322 OpenNativeLibrary(env.get(),
323 /*target_sdk_version=*/17,
324 test_lib_path,
325 /*class_loader=*/nullptr,
326 /*caller_location=*/"/apex/com.android.art/javalib/myloadinglib.jar",
327 /*library_path=*/nullptr,
328 &needs_native_bridge,
329 &errmsg));
330 // OpenNativeLibrary never uses nativebridge when there's no classloader. That
331 // should maybe change.
332 EXPECT_EQ(needs_native_bridge, false);
333 EXPECT_EQ(errmsg, nullptr);
334 }
335
TEST_P(NativeLoaderTest,OpenNativeLibraryWithoutClassloaderInFramework)336 TEST_P(NativeLoaderTest, OpenNativeLibraryWithoutClassloaderInFramework) {
337 const char* test_lib_path = "libfoo.so";
338 void* fake_handle = &fake_handle; // Arbitrary non-null value
339 EXPECT_CALL(*mock, mock_dlopen_ext(false, StrEq(test_lib_path), RTLD_NOW, NsEq("system")))
340 .WillOnce(Return(fake_handle));
341
342 bool needs_native_bridge = false;
343 char* errmsg = nullptr;
344 EXPECT_EQ(fake_handle,
345 OpenNativeLibrary(env.get(),
346 /*target_sdk_version=*/17,
347 test_lib_path,
348 /*class_loader=*/nullptr,
349 /*caller_location=*/"/system/framework/framework.jar!classes1.dex",
350 /*library_path=*/nullptr,
351 &needs_native_bridge,
352 &errmsg));
353 // OpenNativeLibrary never uses nativebridge when there's no classloader. That
354 // should maybe change.
355 EXPECT_EQ(needs_native_bridge, false);
356 EXPECT_EQ(errmsg, nullptr);
357 }
358
TEST_P(NativeLoaderTest,OpenNativeLibraryWithoutClassloaderAndCallerLocation)359 TEST_P(NativeLoaderTest, OpenNativeLibraryWithoutClassloaderAndCallerLocation) {
360 const char* test_lib_path = "libfoo.so";
361 void* fake_handle = &fake_handle; // Arbitrary non-null value
362 EXPECT_CALL(*mock, mock_dlopen_ext(false, StrEq(test_lib_path), RTLD_NOW, NsEq("system")))
363 .WillOnce(Return(fake_handle));
364
365 bool needs_native_bridge = false;
366 char* errmsg = nullptr;
367 EXPECT_EQ(fake_handle,
368 OpenNativeLibrary(env.get(),
369 /*target_sdk_version=*/17,
370 test_lib_path,
371 /*class_loader=*/nullptr,
372 /*caller_location=*/nullptr,
373 /*library_path=*/nullptr,
374 &needs_native_bridge,
375 &errmsg));
376 // OpenNativeLibrary never uses nativebridge when there's no classloader. That
377 // should maybe change.
378 EXPECT_EQ(needs_native_bridge, false);
379 EXPECT_EQ(errmsg, nullptr);
380 }
381
382 INSTANTIATE_TEST_SUITE_P(NativeLoaderTests, NativeLoaderTest, testing::Bool());
383
384 /////////////////////////////////////////////////////////////////
385
append_extended_libraries(const std::string & libs)386 std::string append_extended_libraries(const std::string& libs) {
387 const std::string& ext_libs = extended_public_libraries();
388 if (!ext_libs.empty()) {
389 return libs + ":" + ext_libs;
390 }
391 return libs;
392 }
393
default_public_and_extended_libraries()394 std::string default_public_and_extended_libraries() {
395 return append_extended_libraries(default_public_libraries());
396 }
397
398 class NativeLoaderTest_Create : public NativeLoaderTest {
399 protected:
400 // Test inputs (initialized to the default values). Overriding these
401 // must be done before calling SetExpectations() and RunTest().
402 uint32_t target_sdk_version = 29;
403 std::string class_loader = "my_classloader";
404 bool is_shared = false;
405 std::string dex_path = "/data/app/foo/classes.dex";
406 std::string library_path = "/data/app/foo/" LIB_DIR "/arm";
407 std::string permitted_path = "/data/app/foo/" LIB_DIR;
408
409 // expected output (.. for the default test inputs)
410 std::string expected_namespace_prefix = "clns";
411 uint64_t expected_namespace_flags =
412 ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
413 std::string expected_library_path = library_path;
414 std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
415 std::string expected_parent_namespace = "system";
416 bool expected_link_with_platform_ns = true;
417 bool expected_link_with_art_ns = true;
418 bool expected_link_with_i18n_ns = true;
419 bool expected_link_with_conscrypt_ns = false;
420 bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
421 bool expected_link_with_product_ns = !product_public_libraries().empty();
422 bool expected_link_with_vndk_ns = false;
423 bool expected_link_with_vndk_product_ns = false;
424 bool expected_link_with_default_ns = false;
425 bool expected_link_with_neuralnetworks_ns = true;
426 std::string expected_shared_libs_to_platform_ns = default_public_and_extended_libraries();
427 std::string expected_shared_libs_to_art_ns = apex_public_libraries().at("com_android_art");
428 std::string expected_shared_libs_to_i18n_ns = apex_public_libraries().at("com_android_i18n");
429 std::string expected_shared_libs_to_conscrypt_ns = apex_jni_libraries("com_android_conscrypt");
430 std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
431 std::string expected_shared_libs_to_product_ns = product_public_libraries();
432 std::string expected_shared_libs_to_vndk_ns = vndksp_libraries_vendor();
433 std::string expected_shared_libs_to_vndk_product_ns = vndksp_libraries_product();
434 std::string expected_shared_libs_to_default_ns = default_public_and_extended_libraries();
435 std::string expected_shared_libs_to_neuralnetworks_ns = apex_public_libraries().at("com_android_neuralnetworks");
436
SetExpectations()437 void SetExpectations() {
438 NativeLoaderTest::SetExpectations();
439
440 ON_CALL(*jni_mock, JniObject_getParent(StrEq(class_loader))).WillByDefault(Return(nullptr));
441
442 EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(testing::AnyNumber());
443 EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(testing::AnyNumber());
444
445 EXPECT_CALL(*mock, mock_create_namespace(
446 Eq(IsBridged()), StartsWith(expected_namespace_prefix + "-"), nullptr,
447 StrEq(expected_library_path), expected_namespace_flags,
448 StrEq(expected_permitted_path), NsEq(expected_parent_namespace.c_str())))
449 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(dex_path.c_str()))));
450 if (expected_link_with_platform_ns) {
451 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("system"),
452 StrEq(expected_shared_libs_to_platform_ns)))
453 .WillOnce(Return(true));
454 }
455 if (expected_link_with_art_ns) {
456 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_art"),
457 StrEq(expected_shared_libs_to_art_ns)))
458 .WillOnce(Return(true));
459 }
460 if (expected_link_with_i18n_ns) {
461 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_i18n"),
462 StrEq(expected_shared_libs_to_i18n_ns)))
463 .WillOnce(Return(true));
464 }
465 if (expected_link_with_sphal_ns) {
466 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("sphal"),
467 StrEq(expected_shared_libs_to_sphal_ns)))
468 .WillOnce(Return(true));
469 }
470 if (expected_link_with_product_ns) {
471 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("product"),
472 StrEq(expected_shared_libs_to_product_ns)))
473 .WillOnce(Return(true));
474 }
475 if (expected_link_with_vndk_ns) {
476 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk"),
477 StrEq(expected_shared_libs_to_vndk_ns)))
478 .WillOnce(Return(true));
479 }
480 if (expected_link_with_vndk_product_ns) {
481 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk_product"),
482 StrEq(expected_shared_libs_to_vndk_product_ns)))
483 .WillOnce(Return(true));
484 }
485 if (expected_link_with_default_ns) {
486 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("default"),
487 StrEq(expected_shared_libs_to_default_ns)))
488 .WillOnce(Return(true));
489 }
490 if (expected_link_with_neuralnetworks_ns) {
491 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_neuralnetworks"),
492 StrEq(expected_shared_libs_to_neuralnetworks_ns)))
493 .WillOnce(Return(true));
494 }
495 if (expected_link_with_conscrypt_ns) {
496 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("com_android_conscrypt"),
497 StrEq(expected_shared_libs_to_conscrypt_ns)))
498 .WillOnce(Return(true));
499 }
500 }
501
RunTest()502 void RunTest() {
503 NativeLoaderTest::RunTest();
504
505 jstring err = CreateClassLoaderNamespace(
506 env(), target_sdk_version, env()->NewStringUTF(class_loader.c_str()), is_shared,
507 env()->NewStringUTF(dex_path.c_str()), env()->NewStringUTF(library_path.c_str()),
508 env()->NewStringUTF(permitted_path.c_str()), /*uses_library_list=*/ nullptr);
509
510 // no error
511 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
512
513 if (!IsBridged()) {
514 struct android_namespace_t* ns =
515 FindNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
516
517 // The created namespace is for this apk
518 EXPECT_EQ(dex_path.c_str(), reinterpret_cast<const char*>(ns));
519 } else {
520 struct NativeLoaderNamespace* ns =
521 FindNativeLoaderNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
522
523 // The created namespace is for the this apk
524 EXPECT_STREQ(dex_path.c_str(),
525 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
526 }
527 }
528
env()529 JNIEnv* env() { return NativeLoaderTest::env.get(); }
530 };
531
TEST_P(NativeLoaderTest_Create,DownloadedApp)532 TEST_P(NativeLoaderTest_Create, DownloadedApp) {
533 SetExpectations();
534 RunTest();
535 }
536
TEST_P(NativeLoaderTest_Create,BundledSystemApp)537 TEST_P(NativeLoaderTest_Create, BundledSystemApp) {
538 dex_path = "/system/app/foo/foo.apk";
539 is_shared = true;
540
541 expected_namespace_prefix = "clns-shared";
542 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
543 SetExpectations();
544 RunTest();
545 }
546
TEST_P(NativeLoaderTest_Create,BundledVendorApp)547 TEST_P(NativeLoaderTest_Create, BundledVendorApp) {
548 dex_path = "/vendor/app/foo/foo.apk";
549 is_shared = true;
550
551 expected_namespace_prefix = "clns-shared";
552 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
553 SetExpectations();
554 RunTest();
555 }
556
TEST_P(NativeLoaderTest_Create,UnbundledVendorApp)557 TEST_P(NativeLoaderTest_Create, UnbundledVendorApp) {
558 dex_path = "/vendor/app/foo/foo.apk";
559 is_shared = false;
560
561 expected_namespace_prefix = "vendor-clns";
562 expected_library_path = expected_library_path + ":/vendor/" LIB_DIR;
563 expected_permitted_path = expected_permitted_path + ":/vendor/" LIB_DIR;
564 expected_shared_libs_to_platform_ns =
565 default_public_libraries() + ":" + llndk_libraries_vendor();
566 if (android::base::GetProperty("ro.vndk.version", "") != "") {
567 expected_link_with_vndk_ns = true;
568 }
569 SetExpectations();
570 RunTest();
571 }
572
TEST_P(NativeLoaderTest_Create,BundledProductApp)573 TEST_P(NativeLoaderTest_Create, BundledProductApp) {
574 dex_path = "/product/app/foo/foo.apk";
575 is_shared = true;
576
577 expected_namespace_prefix = "clns-shared";
578 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
579 SetExpectations();
580 RunTest();
581 }
582
TEST_P(NativeLoaderTest_Create,SystemServerWithApexJars)583 TEST_P(NativeLoaderTest_Create, SystemServerWithApexJars) {
584 dex_path = "/system/framework/services.jar:/apex/com.android.conscrypt/javalib/service-foo.jar";
585 is_shared = true;
586
587 expected_namespace_prefix = "clns-shared";
588 expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
589 expected_link_with_conscrypt_ns = true;
590 SetExpectations();
591 RunTest();
592 }
593
TEST_P(NativeLoaderTest_Create,UnbundledProductApp)594 TEST_P(NativeLoaderTest_Create, UnbundledProductApp) {
595 dex_path = "/product/app/foo/foo.apk";
596 is_shared = false;
597
598 if (is_product_treblelized()) {
599 expected_namespace_prefix = "product-clns";
600 expected_library_path =
601 expected_library_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
602 expected_permitted_path =
603 expected_permitted_path + ":/product/" LIB_DIR ":/system/product/" LIB_DIR;
604 expected_shared_libs_to_platform_ns =
605 append_extended_libraries(default_public_libraries() + ":" + llndk_libraries_product());
606 if (android::base::GetProperty("ro.product.vndk.version", "") != "") {
607 expected_link_with_vndk_product_ns = true;
608 }
609 }
610
611 SetExpectations();
612 RunTest();
613 }
614
TEST_P(NativeLoaderTest_Create,NamespaceForSharedLibIsNotUsedAsAnonymousNamespace)615 TEST_P(NativeLoaderTest_Create, NamespaceForSharedLibIsNotUsedAsAnonymousNamespace) {
616 if (IsBridged()) {
617 // There is no shared lib in translated arch
618 // TODO(jiyong): revisit this
619 return;
620 }
621 // compared to apks, for java shared libs, library_path is empty; java shared
622 // libs don't have their own native libs. They use platform's.
623 library_path = "";
624 expected_library_path = library_path;
625 // no ALSO_USED_AS_ANONYMOUS
626 expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
627 SetExpectations();
628 RunTest();
629 }
630
TEST_P(NativeLoaderTest_Create,TwoApks)631 TEST_P(NativeLoaderTest_Create, TwoApks) {
632 SetExpectations();
633 const uint32_t second_app_target_sdk_version = 29;
634 const std::string second_app_class_loader = "second_app_classloader";
635 const bool second_app_is_shared = false;
636 const std::string second_app_dex_path = "/data/app/bar/classes.dex";
637 const std::string second_app_library_path = "/data/app/bar/" LIB_DIR "/arm";
638 const std::string second_app_permitted_path = "/data/app/bar/" LIB_DIR;
639 const std::string expected_second_app_permitted_path =
640 std::string("/data:/mnt/expand:") + second_app_permitted_path;
641 const std::string expected_second_app_parent_namespace = "clns";
642 // no ALSO_USED_AS_ANONYMOUS
643 const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
644
645 // The scenario is that second app is loaded by the first app.
646 // So the first app's classloader (`classloader`) is parent of the second
647 // app's classloader.
648 ON_CALL(*jni_mock, JniObject_getParent(StrEq(second_app_class_loader)))
649 .WillByDefault(Return(class_loader.c_str()));
650
651 // namespace for the second app is created. Its parent is set to the namespace
652 // of the first app.
653 EXPECT_CALL(*mock, mock_create_namespace(
654 Eq(IsBridged()), StartsWith(expected_namespace_prefix + "-"), nullptr,
655 StrEq(second_app_library_path), expected_second_namespace_flags,
656 StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str())))
657 .WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
658 EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
659 .WillRepeatedly(Return(true));
660
661 RunTest();
662 jstring err = CreateClassLoaderNamespace(
663 env(), second_app_target_sdk_version, env()->NewStringUTF(second_app_class_loader.c_str()),
664 second_app_is_shared, env()->NewStringUTF(second_app_dex_path.c_str()),
665 env()->NewStringUTF(second_app_library_path.c_str()),
666 env()->NewStringUTF(second_app_permitted_path.c_str()), /*uses_library_list=*/ nullptr);
667
668 // success
669 EXPECT_EQ(err, nullptr) << "Error is: " << std::string(ScopedUtfChars(env(), err).c_str());
670
671 if (!IsBridged()) {
672 struct android_namespace_t* ns =
673 FindNamespaceByClassLoader(env(), env()->NewStringUTF(second_app_class_loader.c_str()));
674
675 // The created namespace is for the second apk
676 EXPECT_EQ(second_app_dex_path.c_str(), reinterpret_cast<const char*>(ns));
677 } else {
678 struct NativeLoaderNamespace* ns = FindNativeLoaderNamespaceByClassLoader(
679 env(), env()->NewStringUTF(second_app_class_loader.c_str()));
680
681 // The created namespace is for the second apk
682 EXPECT_STREQ(second_app_dex_path.c_str(),
683 reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
684 }
685 }
686
687 INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
688
689 const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
__anona7cbf4c60202(const struct ConfigEntry&) 690 [](const struct ConfigEntry&) -> Result<bool> { return true; };
691
TEST(NativeLoaderConfigParser,NamesAndComments)692 TEST(NativeLoaderConfigParser, NamesAndComments) {
693 const char file_content[] = R"(
694 ######
695
696 libA.so
697 #libB.so
698
699
700 libC.so
701 libD.so
702 #### libE.so
703 )";
704 const std::vector<std::string> expected_result = {"libA.so", "libC.so", "libD.so"};
705 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
706 ASSERT_RESULT_OK(result);
707 ASSERT_EQ(expected_result, *result);
708 }
709
TEST(NativeLoaderConfigParser,WithBitness)710 TEST(NativeLoaderConfigParser, WithBitness) {
711 const char file_content[] = R"(
712 libA.so 32
713 libB.so 64
714 libC.so
715 )";
716 #if defined(__LP64__)
717 const std::vector<std::string> expected_result = {"libB.so", "libC.so"};
718 #else
719 const std::vector<std::string> expected_result = {"libA.so", "libC.so"};
720 #endif
721 Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
722 ASSERT_RESULT_OK(result);
723 ASSERT_EQ(expected_result, *result);
724 }
725
TEST(NativeLoaderConfigParser,WithNoPreload)726 TEST(NativeLoaderConfigParser, WithNoPreload) {
727 const char file_content[] = R"(
728 libA.so nopreload
729 libB.so nopreload
730 libC.so
731 )";
732
733 const std::vector<std::string> expected_result = {"libC.so"};
734 Result<std::vector<std::string>> result =
735 ParseConfig(file_content,
736 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
737 ASSERT_RESULT_OK(result);
738 ASSERT_EQ(expected_result, *result);
739 }
740
TEST(NativeLoaderConfigParser,WithNoPreloadAndBitness)741 TEST(NativeLoaderConfigParser, WithNoPreloadAndBitness) {
742 const char file_content[] = R"(
743 libA.so nopreload 32
744 libB.so 64 nopreload
745 libC.so 32
746 libD.so 64
747 libE.so nopreload
748 )";
749
750 #if defined(__LP64__)
751 const std::vector<std::string> expected_result = {"libD.so"};
752 #else
753 const std::vector<std::string> expected_result = {"libC.so"};
754 #endif
755 Result<std::vector<std::string>> result =
756 ParseConfig(file_content,
757 [](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
758 ASSERT_RESULT_OK(result);
759 ASSERT_EQ(expected_result, *result);
760 }
761
TEST(NativeLoaderConfigParser,RejectMalformed)762 TEST(NativeLoaderConfigParser, RejectMalformed) {
763 ASSERT_FALSE(ParseConfig("libA.so 32 64", always_true).ok());
764 ASSERT_FALSE(ParseConfig("libA.so 32 32", always_true).ok());
765 ASSERT_FALSE(ParseConfig("libA.so 32 nopreload 64", always_true).ok());
766 ASSERT_FALSE(ParseConfig("32 libA.so nopreload", always_true).ok());
767 ASSERT_FALSE(ParseConfig("nopreload libA.so 32", always_true).ok());
768 ASSERT_FALSE(ParseConfig("libA.so nopreload # comment", always_true).ok());
769 }
770
TEST(NativeLoaderApexLibrariesConfigParser,BasicLoading)771 TEST(NativeLoaderApexLibrariesConfigParser, BasicLoading) {
772 const char file_content[] = R"(
773 # comment
774 jni com_android_foo libfoo.so
775 # Empty line is ignored
776
777 jni com_android_bar libbar.so:libbar2.so
778
779 public com_android_bar libpublic.so
780 )";
781
782 Result<std::map<std::string, std::string>> jni_libs =
783 ParseApexLibrariesConfig(file_content, "jni");
784 ASSERT_RESULT_OK(jni_libs);
785 std::map<std::string, std::string> expected_jni_libs {
786 {"com_android_foo", "libfoo.so"},
787 {"com_android_bar", "libbar.so:libbar2.so"},
788 };
789 ASSERT_EQ(expected_jni_libs, *jni_libs);
790
791 Result<std::map<std::string, std::string>> public_libs =
792 ParseApexLibrariesConfig(file_content, "public");
793 ASSERT_RESULT_OK(public_libs);
794 std::map<std::string, std::string> expected_public_libs {
795 {"com_android_bar", "libpublic.so"},
796 };
797 ASSERT_EQ(expected_public_libs, *public_libs);
798 }
799
TEST(NativeLoaderApexLibrariesConfigParser,RejectMalformedLine)800 TEST(NativeLoaderApexLibrariesConfigParser, RejectMalformedLine) {
801 const char file_content[] = R"(
802 jni com_android_foo libfoo
803 # missing <library list>
804 jni com_android_bar
805 )";
806 Result<std::map<std::string, std::string>> result = ParseApexLibrariesConfig(file_content, "jni");
807 ASSERT_FALSE(result.ok());
808 ASSERT_EQ("Malformed line \"jni com_android_bar\"", result.error().message());
809 }
810
TEST(NativeLoaderApexLibrariesConfigParser,RejectInvalidTag)811 TEST(NativeLoaderApexLibrariesConfigParser, RejectInvalidTag) {
812 const char file_content[] = R"(
813 jni apex1 lib
814 public apex2 lib
815 # unknown tag
816 unknown com_android_foo libfoo
817 )";
818 Result<std::map<std::string, std::string>> result = ParseApexLibrariesConfig(file_content, "jni");
819 ASSERT_FALSE(result.ok());
820 ASSERT_EQ("Invalid tag \"unknown com_android_foo libfoo\"", result.error().message());
821 }
822
TEST(NativeLoaderApexLibrariesConfigParser,RejectInvalidApexNamespace)823 TEST(NativeLoaderApexLibrariesConfigParser, RejectInvalidApexNamespace) {
824 const char file_content[] = R"(
825 # apex linker namespace should be mangled ('.' -> '_')
826 jni com.android.foo lib
827 )";
828 Result<std::map<std::string, std::string>> result = ParseApexLibrariesConfig(file_content, "jni");
829 ASSERT_FALSE(result.ok());
830 ASSERT_EQ("Invalid apex_namespace \"jni com.android.foo lib\"", result.error().message());
831 }
832
TEST(NativeLoaderApexLibrariesConfigParser,RejectInvalidLibraryList)833 TEST(NativeLoaderApexLibrariesConfigParser, RejectInvalidLibraryList) {
834 const char file_content[] = R"(
835 # library list is ":" separated list of filenames
836 jni com_android_foo lib64/libfoo.so
837 )";
838 Result<std::map<std::string, std::string>> result = ParseApexLibrariesConfig(file_content, "jni");
839 ASSERT_FALSE(result.ok());
840 ASSERT_EQ("Invalid library_list \"jni com_android_foo lib64/libfoo.so\"", result.error().message());
841 }
842
843 } // namespace nativeloader
844 } // namespace android
845