Move to C API of libnativeloader.

Test: m
Bug: 119840313
Bug: 122710865

(cherry picked from commit e1d970df09)

Merged-In: Id5b08ef5de0d38cb678a50e45d38dfb8107c4a1c
Change-Id: Ic82baa885caa5125dd3c8b5de854128c75f48caf

Exempt-From-Owner-Approval: Cherry-pick of approved CL in master.
This commit is contained in:
Nicolas Geoffray 2019-01-12 15:01:20 +00:00
parent 6410fd2434
commit c3a73dcd27
7 changed files with 144 additions and 66 deletions

View file

@ -23,4 +23,20 @@ cc_library {
"llndk.libraries.txt",
"vndksp.libraries.txt",
],
target: {
android: {
version_script: "libnativeloader.map.txt",
},
},
stubs: {
symbol_file: "libnativeloader.map.txt",
versions: ["1"],
},
}
cc_library_headers {
name: "libnativeloader-dummy-headers",
host_supported: true,
export_include_dirs: ["include"],
}

View file

@ -18,6 +18,7 @@
#define __ANDROID_DLEXT_NAMESPACES_H__
#include <android/dlext.h>
#include <stdbool.h>
__BEGIN_DECLS
@ -84,12 +85,9 @@ enum {
* If a library or any of its dependencies are outside of the permitted_when_isolated_path
* and search_path, and it is not part of the public namespace dlopen will fail.
*/
extern struct android_namespace_t* 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,
android_namespace_t* parent);
extern struct android_namespace_t* 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);
/*
* Creates a link between namespaces. Every link has list of sonames of
@ -107,8 +105,8 @@ extern struct android_namespace_t* android_create_namespace(const char* name,
* step will not go deeper into linked namespaces for this library but
* will do so for DT_NEEDED libraries.
*/
extern bool android_link_namespaces(android_namespace_t* from,
android_namespace_t* to,
extern bool android_link_namespaces(struct android_namespace_t* from,
struct android_namespace_t* to,
const char* shared_libs_sonames);
/*
@ -124,7 +122,7 @@ extern bool android_link_namespaces(android_namespace_t* from,
*/
extern void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size);
extern android_namespace_t* android_get_exported_namespace(const char* name);
extern struct android_namespace_t* android_get_exported_namespace(const char* name);
__END_DECLS

View file

@ -17,14 +17,21 @@
#ifndef NATIVE_LOADER_H_
#define NATIVE_LOADER_H_
#include "jni.h"
#include <stdbool.h>
#include <stdint.h>
#include <string>
#include "jni.h"
#if defined(__ANDROID__)
#include <android/dlext.h>
#endif
#ifdef __cplusplus
namespace android {
extern "C" {
#endif // __cplusplus
// README: the char** error message parameter being passed
// to the methods below need to be freed through calling NativeLoaderFreeErrorMessage.
// It's the caller's responsibility to call that method.
__attribute__((visibility("default")))
void InitializeNativeLoader();
@ -38,42 +45,39 @@ jstring CreateClassLoaderNamespace(JNIEnv* env,
jstring library_path,
jstring permitted_path);
__attribute__((visibility("default")))
void* OpenNativeLibrary(JNIEnv* env,
int32_t target_sdk_version,
const char* path,
jobject class_loader,
jstring library_path,
bool* needs_native_bridge,
std::string* error_msg);
__attribute__((visibility("default"))) void* OpenNativeLibrary(
JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader,
jstring library_path, bool* needs_native_bridge, char** error_msg);
__attribute__((visibility("default"))) bool CloseNativeLibrary(void* handle,
const bool needs_native_bridge,
std::string* error_msg);
char** error_msg);
__attribute__((visibility("default"))) void NativeLoaderFreeErrorMessage(char* msg);
#if defined(__ANDROID__)
// Look up linker namespace by class_loader. Returns nullptr if
// there is no namespace associated with the class_loader.
// TODO(b/79940628): move users to FindNativeLoaderNamespaceByClassLoader and remove this function.
__attribute__((visibility("default")))
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
class NativeLoaderNamespace;
__attribute__((visibility("default")))
NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(
__attribute__((visibility("default"))) struct android_namespace_t* FindNamespaceByClassLoader(
JNIEnv* env, jobject class_loader);
// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
struct NativeLoaderNamespace;
__attribute__((visibility("default"))) struct NativeLoaderNamespace*
FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
// Load library. Unlinke OpenNativeLibrary above couldn't create namespace on demand, but does
// not require access to JNIEnv either.
__attribute__((visibility("default")))
void* OpenNativeLibrary(NativeLoaderNamespace* ns,
const char* path,
bool* needs_native_bridge,
std::string* error_msg);
__attribute__((visibility("default"))) void* OpenNativeLibraryInNamespace(
struct NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
char** error_msg);
#endif
__attribute__((visibility("default")))
void ResetNativeLoader();
}; // namespace android
#ifdef __cplusplus
} // extern "C"
} // namespace android
#endif // __cplusplus
#endif // NATIVE_BRIDGE_H_

View file

@ -0,0 +1,31 @@
#
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# TODO(b/122710865): Prune these uses once the runtime APEX is complete.
LIBNATIVELOADER_1 {
global:
OpenNativeLibrary;
InitializeNativeLoader;
ResetNativeLoader;
CloseNativeLibrary;
OpenNativeLibraryInNamespace;
FindNamespaceByClassLoader;
FindNativeLoaderNamespaceByClassLoader;
CreateClassLoaderNamespace;
NativeLoaderFreeErrorMessage;
local:
*;
};

View file

@ -52,7 +52,7 @@ using namespace std::string_literals;
namespace android {
#if defined(__ANDROID__)
class NativeLoaderNamespace {
struct NativeLoaderNamespace {
public:
NativeLoaderNamespace()
: android_ns_(nullptr), native_bridge_ns_(nullptr) { }
@ -151,14 +151,9 @@ class LibraryNamespaces {
public:
LibraryNamespaces() : initialized_(false) { }
NativeLoaderNamespace* Create(JNIEnv* env,
uint32_t target_sdk_version,
jobject class_loader,
bool is_shared,
bool is_for_vendor,
jstring java_library_path,
jstring java_permitted_path,
std::string* error_msg) {
NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
bool is_shared, bool is_for_vendor, jstring java_library_path,
jstring java_permitted_path, std::string* error_msg) {
std::string library_path; // empty string by default.
if (java_library_path != nullptr) {
@ -628,13 +623,9 @@ jstring CreateClassLoaderNamespace(JNIEnv* env,
return nullptr;
}
void* OpenNativeLibrary(JNIEnv* env,
int32_t target_sdk_version,
const char* path,
jobject class_loader,
jstring library_path,
bool* needs_native_bridge,
std::string* error_msg) {
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
jobject class_loader, jstring library_path, bool* needs_native_bridge,
char** error_msg) {
#if defined(__ANDROID__)
UNUSED(target_sdk_version);
if (class_loader == nullptr) {
@ -652,19 +643,16 @@ void* OpenNativeLibrary(JNIEnv* env,
if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
if ((ns = g_namespaces->Create(env,
target_sdk_version,
class_loader,
false /* is_shared */,
false /* is_for_vendor */,
library_path,
nullptr,
error_msg)) == nullptr) {
std::string create_error_msg;
if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */,
false /* is_for_vendor */, library_path, nullptr,
&create_error_msg)) == nullptr) {
*error_msg = strdup(create_error_msg.c_str());
return nullptr;
}
}
return OpenNativeLibrary(ns, path, needs_native_bridge, error_msg);
return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);
#else
UNUSED(env, target_sdk_version, class_loader);
@ -705,35 +693,40 @@ void* OpenNativeLibrary(JNIEnv* env,
if (handle != nullptr) {
return handle;
}
*error_msg = NativeBridgeGetError();
*error_msg = strdup(NativeBridgeGetError());
} else {
*error_msg = dlerror();
*error_msg = strdup(dlerror());
}
}
return nullptr;
#endif
}
bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, std::string* error_msg) {
bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
bool success;
if (needs_native_bridge) {
success = (NativeBridgeUnloadLibrary(handle) == 0);
if (!success) {
*error_msg = NativeBridgeGetError();
*error_msg = strdup(NativeBridgeGetError());
}
} else {
success = (dlclose(handle) == 0);
if (!success) {
*error_msg = dlerror();
*error_msg = strdup(dlerror());
}
}
return success;
}
void NativeLoaderFreeErrorMessage(char* msg) {
// The error messages get allocated through strdup, so we must call free on them.
free(msg);
}
#if defined(__ANDROID__)
void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
std::string* error_msg) {
void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
bool* needs_native_bridge, char** error_msg) {
if (ns->is_android_namespace()) {
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
@ -741,14 +734,14 @@ void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs
void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
if (handle == nullptr) {
*error_msg = dlerror();
*error_msg = strdup(dlerror());
}
*needs_native_bridge = false;
return handle;
} else {
void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns());
if (handle == nullptr) {
*error_msg = NativeBridgeGetError();
*error_msg = strdup(NativeBridgeGetError());
}
*needs_native_bridge = true;
return handle;

View file

@ -69,3 +69,14 @@ cc_library {
"libbase",
],
}
// Build the test for the C API.
cc_test {
name: "libnativeloader-api-tests",
host_supported: true,
test_per_src: true,
srcs: [
"api_test.c",
],
header_libs: ["libnativeloader-dummy-headers"],
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* The main purpose of this test is to ensure this C header compiles in C, so
* that no C++ features inadvertently leak into the C ABI. */
#include "nativeloader/native_loader.h"
int main(int argc, char** argv) {
(void)argc;
(void)argv;
return 0;
}