Merge "Move libnative{bridge,loader} to art/"
This commit is contained in:
commit
5a1489ce4e
64 changed files with 0 additions and 5486 deletions
|
@ -1 +0,0 @@
|
|||
../.clang-format-2
|
|
@ -1,65 +0,0 @@
|
|||
cc_defaults {
|
||||
name: "libnativebridge-defaults",
|
||||
cflags: [
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
],
|
||||
cppflags: [
|
||||
"-fvisibility=protected",
|
||||
],
|
||||
header_libs: ["libnativebridge-headers"],
|
||||
export_header_lib_headers: ["libnativebridge-headers"],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libnativebridge-headers",
|
||||
|
||||
host_supported: true,
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libnativebridge",
|
||||
defaults: ["libnativebridge-defaults"],
|
||||
// TODO(oth): remove after moving under art/ (b/137364733)
|
||||
visibility: ["//visibility:public"],
|
||||
|
||||
host_supported: true,
|
||||
srcs: ["native_bridge.cc"],
|
||||
header_libs: [
|
||||
"libbase_headers",
|
||||
],
|
||||
shared_libs: [
|
||||
"liblog",
|
||||
],
|
||||
// TODO(jiyong): remove this line after aosp/885921 lands
|
||||
export_include_dirs: ["include"],
|
||||
|
||||
target: {
|
||||
android: {
|
||||
version_script: "libnativebridge.map.txt",
|
||||
},
|
||||
linux: {
|
||||
version_script: "libnativebridge.map.txt",
|
||||
},
|
||||
},
|
||||
|
||||
stubs: {
|
||||
symbol_file: "libnativebridge.map.txt",
|
||||
versions: ["1"],
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(b/124250621): eliminate the need for this library
|
||||
cc_library {
|
||||
name: "libnativebridge_lazy",
|
||||
defaults: ["libnativebridge-defaults"],
|
||||
// TODO(oth): remove after moving under art/ (b/137364733)
|
||||
visibility: ["//visibility:public"],
|
||||
|
||||
host_supported: false,
|
||||
srcs: ["native_bridge_lazy.cc"],
|
||||
required: ["libnativebridge"],
|
||||
}
|
||||
|
||||
subdirs = ["tests"]
|
|
@ -1,19 +0,0 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
filter=-build/header_guard
|
||||
filter=-whitespace/comments
|
||||
filter=-whitespace/parens
|
|
@ -1,4 +0,0 @@
|
|||
dimitry@google.com
|
||||
eaeltsin@google.com
|
||||
ngeoffray@google.com
|
||||
oth@google.com
|
|
@ -1,418 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#ifndef NATIVE_BRIDGE_H_
|
||||
#define NATIVE_BRIDGE_H_
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace android {
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
struct NativeBridgeRuntimeCallbacks;
|
||||
struct NativeBridgeRuntimeValues;
|
||||
|
||||
// Function pointer type for sigaction. This is mostly the signature of a signal handler, except
|
||||
// for the return type. The runtime needs to know whether the signal was handled or should be given
|
||||
// to the chain.
|
||||
typedef bool (*NativeBridgeSignalHandlerFn)(int, siginfo_t*, void*);
|
||||
|
||||
// Open the native bridge, if any. Should be called by Runtime::Init(). A null library filename
|
||||
// signals that we do not want to load a native bridge.
|
||||
bool LoadNativeBridge(const char* native_bridge_library_filename,
|
||||
const struct NativeBridgeRuntimeCallbacks* runtime_callbacks);
|
||||
|
||||
// Quick check whether a native bridge will be needed. This is based off of the instruction set
|
||||
// of the process.
|
||||
bool NeedsNativeBridge(const char* instruction_set);
|
||||
|
||||
// Do the early initialization part of the native bridge, if necessary. This should be done under
|
||||
// high privileges.
|
||||
bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set);
|
||||
|
||||
// Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv*
|
||||
// will be used to modify the app environment for the bridge.
|
||||
bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set);
|
||||
|
||||
// Unload the native bridge, if any. Should be called by Runtime::DidForkFromZygote.
|
||||
void UnloadNativeBridge();
|
||||
|
||||
// Check whether a native bridge is available (opened or initialized). Requires a prior call to
|
||||
// LoadNativeBridge.
|
||||
bool NativeBridgeAvailable();
|
||||
|
||||
// Check whether a native bridge is available (initialized). Requires a prior call to
|
||||
// LoadNativeBridge & InitializeNativeBridge.
|
||||
bool NativeBridgeInitialized();
|
||||
|
||||
// Load a shared library that is supported by the native bridge.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeLoadLibraryExt() instead in namespace scenario.
|
||||
void* NativeBridgeLoadLibrary(const char* libpath, int flag);
|
||||
|
||||
// Get a native bridge trampoline for specified native method.
|
||||
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
|
||||
|
||||
// True if native library paths are valid and is for an ABI that is supported by native bridge.
|
||||
// The *libpath* must point to a library.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeIsPathSupported() instead in namespace scenario.
|
||||
bool NativeBridgeIsSupported(const char* libpath);
|
||||
|
||||
// Returns the version number of the native bridge. This information is available after a
|
||||
// successful LoadNativeBridge() and before closing it, that is, as long as NativeBridgeAvailable()
|
||||
// returns true. Returns 0 otherwise.
|
||||
uint32_t NativeBridgeGetVersion();
|
||||
|
||||
// Returns a signal handler that the bridge would like to be managed. Only valid for a native
|
||||
// bridge supporting the version 2 interface. Will return null if the bridge does not support
|
||||
// version 2, or if it doesn't have a signal handler it wants to be known.
|
||||
NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal);
|
||||
|
||||
// Returns whether we have seen a native bridge error. This could happen because the library
|
||||
// was not found, rejected, could not be initialized and so on.
|
||||
//
|
||||
// This functionality is mainly for testing.
|
||||
bool NativeBridgeError();
|
||||
|
||||
// Returns whether a given string is acceptable as a native bridge library filename.
|
||||
//
|
||||
// This functionality is exposed mainly for testing.
|
||||
bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
|
||||
|
||||
// Decrements the reference count on the dynamic library handler. If the reference count drops
|
||||
// to zero then the dynamic library is unloaded. Returns 0 on success and non-zero on error.
|
||||
int NativeBridgeUnloadLibrary(void* handle);
|
||||
|
||||
// Get last error message of native bridge when fail to load library or search symbol.
|
||||
// This is reflection of dlerror() for native bridge.
|
||||
const char* NativeBridgeGetError();
|
||||
|
||||
struct native_bridge_namespace_t;
|
||||
|
||||
// True if native library paths are valid and is for an ABI that is supported by native bridge.
|
||||
// Different from NativeBridgeIsSupported(), the *path* here must be a directory containing
|
||||
// libraries of an ABI.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeIsSupported() instead in non-namespace scenario.
|
||||
bool NativeBridgeIsPathSupported(const char* path);
|
||||
|
||||
// Initializes anonymous namespace.
|
||||
// NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
|
||||
//
|
||||
// The anonymous namespace is used in the case when a NativeBridge implementation
|
||||
// cannot identify the caller of dlopen/dlsym which happens for the code not loaded
|
||||
// by dynamic linker; for example calls from the mono-compiled code.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Should not use in non-namespace scenario.
|
||||
bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
|
||||
const char* anon_ns_library_path);
|
||||
|
||||
// Create new namespace in which native libraries will be loaded.
|
||||
// NativeBridge's peer of android_create_namespace() of dynamic linker.
|
||||
//
|
||||
// The libraries in the namespace are searched by folowing order:
|
||||
// 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
|
||||
// 2. In directories specified by DT_RUNPATH of the "needed by" binary.
|
||||
// 3. deault_library_path (This of this as namespace-local default library path)
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Should not use in non-namespace scenario.
|
||||
struct native_bridge_namespace_t* 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_ns);
|
||||
|
||||
// Creates a link which shares some libraries from one namespace to another.
|
||||
// NativeBridge's peer of android_link_namespaces() of dynamic linker.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Should not use in non-namespace scenario.
|
||||
bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
|
||||
struct native_bridge_namespace_t* to,
|
||||
const char* shared_libs_sonames);
|
||||
|
||||
// Load a shared library with namespace key that is supported by the native bridge.
|
||||
// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
|
||||
// extension.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
|
||||
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
|
||||
struct native_bridge_namespace_t* ns);
|
||||
|
||||
// Returns exported namespace by the name. This is a reflection of
|
||||
// android_get_exported_namespace function. Introduced in v5.
|
||||
struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name);
|
||||
|
||||
// Native bridge interfaces to runtime.
|
||||
struct NativeBridgeCallbacks {
|
||||
// Version number of the interface.
|
||||
uint32_t version;
|
||||
|
||||
// Initialize native bridge. Native bridge's internal implementation must ensure MT safety and
|
||||
// that the native bridge is initialized only once. Thus it is OK to call this interface for an
|
||||
// already initialized native bridge.
|
||||
//
|
||||
// Parameters:
|
||||
// runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
|
||||
// Returns:
|
||||
// true if initialization was successful.
|
||||
bool (*initialize)(const struct NativeBridgeRuntimeCallbacks* runtime_cbs,
|
||||
const char* private_dir, const char* instruction_set);
|
||||
|
||||
// Load a shared library that is supported by the native bridge.
|
||||
//
|
||||
// Parameters:
|
||||
// libpath [IN] path to the shared library
|
||||
// flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
|
||||
// Returns:
|
||||
// The opaque handle of the shared library if sucessful, otherwise NULL
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use loadLibraryExt instead in namespace scenario.
|
||||
void* (*loadLibrary)(const char* libpath, int flag);
|
||||
|
||||
// Get a native bridge trampoline for specified native method. The trampoline has same
|
||||
// sigature as the native method.
|
||||
//
|
||||
// Parameters:
|
||||
// handle [IN] the handle returned from loadLibrary
|
||||
// shorty [IN] short descriptor of native method
|
||||
// len [IN] length of shorty
|
||||
// Returns:
|
||||
// address of trampoline if successful, otherwise NULL
|
||||
void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
|
||||
|
||||
// Check whether native library is valid and is for an ABI that is supported by native bridge.
|
||||
//
|
||||
// Parameters:
|
||||
// libpath [IN] path to the shared library
|
||||
// Returns:
|
||||
// TRUE if library is supported by native bridge, FALSE otherwise
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use isPathSupported instead in namespace scenario.
|
||||
bool (*isSupported)(const char* libpath);
|
||||
|
||||
// Provide environment values required by the app running with native bridge according to the
|
||||
// instruction set.
|
||||
//
|
||||
// Parameters:
|
||||
// instruction_set [IN] the instruction set of the app
|
||||
// Returns:
|
||||
// NULL if not supported by native bridge.
|
||||
// Otherwise, return all environment values to be set after fork.
|
||||
const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
|
||||
|
||||
// Added callbacks in version 2.
|
||||
|
||||
// Check whether the bridge is compatible with the given version. A bridge may decide not to be
|
||||
// forwards- or backwards-compatible, and libnativebridge will then stop using it.
|
||||
//
|
||||
// Parameters:
|
||||
// bridge_version [IN] the version of libnativebridge.
|
||||
// Returns:
|
||||
// true if the native bridge supports the given version of libnativebridge.
|
||||
bool (*isCompatibleWith)(uint32_t bridge_version);
|
||||
|
||||
// A callback to retrieve a native bridge's signal handler for the specified signal. The runtime
|
||||
// will ensure that the signal handler is being called after the runtime's own handler, but before
|
||||
// all chained handlers. The native bridge should not try to install the handler by itself, as
|
||||
// that will potentially lead to cycles.
|
||||
//
|
||||
// Parameters:
|
||||
// signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
|
||||
// supported by the runtime.
|
||||
// Returns:
|
||||
// NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
|
||||
// runtime.
|
||||
// Otherwise, a pointer to the signal handler.
|
||||
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
|
||||
|
||||
// Added callbacks in version 3.
|
||||
|
||||
// Decrements the reference count on the dynamic library handler. If the reference count drops
|
||||
// to zero then the dynamic library is unloaded.
|
||||
//
|
||||
// Parameters:
|
||||
// handle [IN] the handler of a dynamic library.
|
||||
//
|
||||
// Returns:
|
||||
// 0 on success, and nonzero on error.
|
||||
int (*unloadLibrary)(void* handle);
|
||||
|
||||
// Dump the last failure message of native bridge when fail to load library or search symbol.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// Returns:
|
||||
// A string describing the most recent error that occurred when load library
|
||||
// or lookup symbol via native bridge.
|
||||
const char* (*getError)();
|
||||
|
||||
// Check whether library paths are supported by native bridge.
|
||||
//
|
||||
// Parameters:
|
||||
// library_path [IN] search paths for native libraries (directories separated by ':')
|
||||
// Returns:
|
||||
// TRUE if libraries within search paths are supported by native bridge, FALSE otherwise
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use isSupported instead in non-namespace scenario.
|
||||
bool (*isPathSupported)(const char* library_path);
|
||||
|
||||
// Initializes anonymous namespace at native bridge side.
|
||||
// NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
|
||||
//
|
||||
// The anonymous namespace is used in the case when a NativeBridge implementation
|
||||
// cannot identify the caller of dlopen/dlsym which happens for the code not loaded
|
||||
// by dynamic linker; for example calls from the mono-compiled code.
|
||||
//
|
||||
// Parameters:
|
||||
// public_ns_sonames [IN] the name of "public" libraries.
|
||||
// anon_ns_library_path [IN] the library search path of (anonymous) namespace.
|
||||
// Returns:
|
||||
// true if the pass is ok.
|
||||
// Otherwise, false.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Should not use in non-namespace scenario.
|
||||
bool (*initAnonymousNamespace)(const char* public_ns_sonames, const char* anon_ns_library_path);
|
||||
|
||||
// Create new namespace in which native libraries will be loaded.
|
||||
// NativeBridge's peer of android_create_namespace() of dynamic linker.
|
||||
//
|
||||
// Parameters:
|
||||
// name [IN] the name of the namespace.
|
||||
// ld_library_path [IN] the first set of library search paths of the namespace.
|
||||
// default_library_path [IN] the second set of library search path of the namespace.
|
||||
// type [IN] the attribute of the namespace.
|
||||
// permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
|
||||
// parent_ns [IN] the pointer of the parent namespace to be inherited from.
|
||||
// Returns:
|
||||
// native_bridge_namespace_t* for created namespace or nullptr in the case of error.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Should not use in non-namespace scenario.
|
||||
struct native_bridge_namespace_t* (*createNamespace)(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_ns);
|
||||
|
||||
// Creates a link which shares some libraries from one namespace to another.
|
||||
// NativeBridge's peer of android_link_namespaces() of dynamic linker.
|
||||
//
|
||||
// Parameters:
|
||||
// from [IN] the namespace where libraries are accessed.
|
||||
// to [IN] the namespace where libraries are loaded.
|
||||
// shared_libs_sonames [IN] the libraries to be shared.
|
||||
//
|
||||
// Returns:
|
||||
// Whether successed or not.
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Should not use in non-namespace scenario.
|
||||
bool (*linkNamespaces)(struct native_bridge_namespace_t* from,
|
||||
struct native_bridge_namespace_t* to, const char* shared_libs_sonames);
|
||||
|
||||
// Load a shared library within a namespace.
|
||||
// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
|
||||
// extension.
|
||||
//
|
||||
// Parameters:
|
||||
// libpath [IN] path to the shared library
|
||||
// flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
|
||||
// ns [IN] the pointer of the namespace in which the library should be loaded.
|
||||
// Returns:
|
||||
// The opaque handle of the shared library if sucessful, otherwise NULL
|
||||
//
|
||||
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
|
||||
// Use loadLibrary instead in non-namespace scenario.
|
||||
void* (*loadLibraryExt)(const char* libpath, int flag, struct native_bridge_namespace_t* ns);
|
||||
|
||||
// Get native bridge version of vendor namespace.
|
||||
// The vendor namespace is the namespace used to load vendor public libraries.
|
||||
// With O release this namespace can be different from the default namespace.
|
||||
// For the devices without enable vendor namespaces this function should return null
|
||||
//
|
||||
// Returns:
|
||||
// vendor namespace or null if it was not set up for the device
|
||||
//
|
||||
// Starting with v5 (Android Q) this function is no longer used.
|
||||
// Use getExportedNamespace() below.
|
||||
struct native_bridge_namespace_t* (*getVendorNamespace)();
|
||||
|
||||
// Get native bridge version of exported namespace. Peer of
|
||||
// android_get_exported_namespace(const char*) function.
|
||||
//
|
||||
// Returns:
|
||||
// exported namespace or null if it was not set up for the device
|
||||
struct native_bridge_namespace_t* (*getExportedNamespace)(const char* name);
|
||||
};
|
||||
|
||||
// Runtime interfaces to native bridge.
|
||||
struct NativeBridgeRuntimeCallbacks {
|
||||
// Get shorty of a Java method. The shorty is supposed to be persistent in memory.
|
||||
//
|
||||
// Parameters:
|
||||
// env [IN] pointer to JNIenv.
|
||||
// mid [IN] Java methodID.
|
||||
// Returns:
|
||||
// short descriptor for method.
|
||||
const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
|
||||
|
||||
// Get number of native methods for specified class.
|
||||
//
|
||||
// Parameters:
|
||||
// env [IN] pointer to JNIenv.
|
||||
// clazz [IN] Java class object.
|
||||
// Returns:
|
||||
// number of native methods.
|
||||
uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
|
||||
|
||||
// Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
|
||||
// via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
|
||||
//
|
||||
// Parameters:
|
||||
// env [IN] pointer to JNIenv.
|
||||
// clazz [IN] Java class object.
|
||||
// methods [OUT] array of method with the name, shorty, and fnPtr.
|
||||
// method_count [IN] max number of elements in methods.
|
||||
// Returns:
|
||||
// number of method it actually wrote to methods.
|
||||
uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
|
||||
uint32_t method_count);
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
} // namespace android
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // NATIVE_BRIDGE_H_
|
|
@ -1,45 +0,0 @@
|
|||
#
|
||||
# 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): Most of these uses come from libnativeloader, which should be bundled
|
||||
# together with libnativebridge in the APEX. Once this happens, prune this list.
|
||||
LIBNATIVEBRIDGE_1 {
|
||||
global:
|
||||
NativeBridgeIsSupported;
|
||||
NativeBridgeLoadLibrary;
|
||||
NativeBridgeUnloadLibrary;
|
||||
NativeBridgeGetError;
|
||||
NativeBridgeIsPathSupported;
|
||||
NativeBridgeCreateNamespace;
|
||||
NativeBridgeGetExportedNamespace;
|
||||
NativeBridgeLinkNamespaces;
|
||||
NativeBridgeLoadLibraryExt;
|
||||
NativeBridgeInitAnonymousNamespace;
|
||||
NativeBridgeInitialized;
|
||||
NativeBridgeGetTrampoline;
|
||||
LoadNativeBridge;
|
||||
PreInitializeNativeBridge;
|
||||
InitializeNativeBridge;
|
||||
NativeBridgeGetVersion;
|
||||
NativeBridgeGetSignalHandler;
|
||||
UnloadNativeBridge;
|
||||
NativeBridgeAvailable;
|
||||
NeedsNativeBridge;
|
||||
NativeBridgeError;
|
||||
NativeBridgeNameAcceptable;
|
||||
local:
|
||||
*;
|
||||
};
|
|
@ -1,646 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "nativebridge"
|
||||
|
||||
#include "nativebridge/native_bridge.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <android-base/macros.h>
|
||||
#include <log/log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
#ifdef __APPLE__
|
||||
template <typename T>
|
||||
void UNUSED(const T&) {}
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Environment values required by the apps running with native bridge.
|
||||
struct NativeBridgeRuntimeValues {
|
||||
const char* os_arch;
|
||||
const char* cpu_abi;
|
||||
const char* cpu_abi2;
|
||||
const char* *supported_abis;
|
||||
int32_t abi_count;
|
||||
};
|
||||
|
||||
// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
|
||||
static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
|
||||
|
||||
enum class NativeBridgeState {
|
||||
kNotSetup, // Initial state.
|
||||
kOpened, // After successful dlopen.
|
||||
kPreInitialized, // After successful pre-initialization.
|
||||
kInitialized, // After successful initialization.
|
||||
kClosed // Closed or errors.
|
||||
};
|
||||
|
||||
static constexpr const char* kNotSetupString = "kNotSetup";
|
||||
static constexpr const char* kOpenedString = "kOpened";
|
||||
static constexpr const char* kPreInitializedString = "kPreInitialized";
|
||||
static constexpr const char* kInitializedString = "kInitialized";
|
||||
static constexpr const char* kClosedString = "kClosed";
|
||||
|
||||
static const char* GetNativeBridgeStateString(NativeBridgeState state) {
|
||||
switch (state) {
|
||||
case NativeBridgeState::kNotSetup:
|
||||
return kNotSetupString;
|
||||
|
||||
case NativeBridgeState::kOpened:
|
||||
return kOpenedString;
|
||||
|
||||
case NativeBridgeState::kPreInitialized:
|
||||
return kPreInitializedString;
|
||||
|
||||
case NativeBridgeState::kInitialized:
|
||||
return kInitializedString;
|
||||
|
||||
case NativeBridgeState::kClosed:
|
||||
return kClosedString;
|
||||
}
|
||||
}
|
||||
|
||||
// Current state of the native bridge.
|
||||
static NativeBridgeState state = NativeBridgeState::kNotSetup;
|
||||
|
||||
// The version of NativeBridge implementation.
|
||||
// Different Nativebridge interface needs the service of different version of
|
||||
// Nativebridge implementation.
|
||||
// Used by isCompatibleWith() which is introduced in v2.
|
||||
enum NativeBridgeImplementationVersion {
|
||||
// first version, not used.
|
||||
DEFAULT_VERSION = 1,
|
||||
// The version which signal semantic is introduced.
|
||||
SIGNAL_VERSION = 2,
|
||||
// The version which namespace semantic is introduced.
|
||||
NAMESPACE_VERSION = 3,
|
||||
// The version with vendor namespaces
|
||||
VENDOR_NAMESPACE_VERSION = 4,
|
||||
// The version with runtime namespaces
|
||||
RUNTIME_NAMESPACE_VERSION = 5,
|
||||
};
|
||||
|
||||
// Whether we had an error at some point.
|
||||
static bool had_error = false;
|
||||
|
||||
// Handle of the loaded library.
|
||||
static void* native_bridge_handle = nullptr;
|
||||
// Pointer to the callbacks. Available as soon as LoadNativeBridge succeeds, but only initialized
|
||||
// later.
|
||||
static const NativeBridgeCallbacks* callbacks = nullptr;
|
||||
// Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
|
||||
static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
|
||||
|
||||
// The app's code cache directory.
|
||||
static char* app_code_cache_dir = nullptr;
|
||||
|
||||
// Code cache directory (relative to the application private directory)
|
||||
// Ideally we'd like to call into framework to retrieve this name. However that's considered an
|
||||
// implementation detail and will require either hacks or consistent refactorings. We compromise
|
||||
// and hard code the directory name again here.
|
||||
static constexpr const char* kCodeCacheDir = "code_cache";
|
||||
|
||||
// Characters allowed in a native bridge filename. The first character must
|
||||
// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
|
||||
static bool CharacterAllowed(char c, bool first) {
|
||||
if (first) {
|
||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
||||
} else {
|
||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
|
||||
(c == '.') || (c == '_') || (c == '-');
|
||||
}
|
||||
}
|
||||
|
||||
static void ReleaseAppCodeCacheDir() {
|
||||
if (app_code_cache_dir != nullptr) {
|
||||
delete[] app_code_cache_dir;
|
||||
app_code_cache_dir = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// We only allow simple names for the library. It is supposed to be a file in
|
||||
// /system/lib or /vendor/lib. Only allow a small range of characters, that is
|
||||
// names consisting of [a-zA-Z0-9._-] and starting with [a-zA-Z].
|
||||
bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
|
||||
const char* ptr = nb_library_filename;
|
||||
if (*ptr == 0) {
|
||||
// Emptry string. Allowed, means no native bridge.
|
||||
return true;
|
||||
} else {
|
||||
// First character must be [a-zA-Z].
|
||||
if (!CharacterAllowed(*ptr, true)) {
|
||||
// Found an invalid fist character, don't accept.
|
||||
ALOGE("Native bridge library %s has been rejected for first character %c",
|
||||
nb_library_filename,
|
||||
*ptr);
|
||||
return false;
|
||||
} else {
|
||||
// For the rest, be more liberal.
|
||||
ptr++;
|
||||
while (*ptr != 0) {
|
||||
if (!CharacterAllowed(*ptr, false)) {
|
||||
// Found an invalid character, don't accept.
|
||||
ALOGE("Native bridge library %s has been rejected for %c", nb_library_filename, *ptr);
|
||||
return false;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// The policy of invoking Nativebridge changed in v3 with/without namespace.
|
||||
// Suggest Nativebridge implementation not maintain backward-compatible.
|
||||
static bool isCompatibleWith(const uint32_t version) {
|
||||
// Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
|
||||
// version.
|
||||
if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
|
||||
if (callbacks->version >= SIGNAL_VERSION) {
|
||||
return callbacks->isCompatibleWith(version);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CloseNativeBridge(bool with_error) {
|
||||
state = NativeBridgeState::kClosed;
|
||||
had_error |= with_error;
|
||||
ReleaseAppCodeCacheDir();
|
||||
}
|
||||
|
||||
bool LoadNativeBridge(const char* nb_library_filename,
|
||||
const NativeBridgeRuntimeCallbacks* runtime_cbs) {
|
||||
// We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not
|
||||
// multi-threaded, so we do not need locking here.
|
||||
|
||||
if (state != NativeBridgeState::kNotSetup) {
|
||||
// Setup has been called before. Ignore this call.
|
||||
if (nb_library_filename != nullptr) { // Avoids some log-spam for dalvikvm.
|
||||
ALOGW("Called LoadNativeBridge for an already set up native bridge. State is %s.",
|
||||
GetNativeBridgeStateString(state));
|
||||
}
|
||||
// Note: counts as an error, even though the bridge may be functional.
|
||||
had_error = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nb_library_filename == nullptr || *nb_library_filename == 0) {
|
||||
CloseNativeBridge(false);
|
||||
return false;
|
||||
} else {
|
||||
if (!NativeBridgeNameAcceptable(nb_library_filename)) {
|
||||
CloseNativeBridge(true);
|
||||
} else {
|
||||
// Try to open the library.
|
||||
void* handle = dlopen(nb_library_filename, RTLD_LAZY);
|
||||
if (handle != nullptr) {
|
||||
callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
|
||||
kNativeBridgeInterfaceSymbol));
|
||||
if (callbacks != nullptr) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
// Store the handle for later.
|
||||
native_bridge_handle = handle;
|
||||
} else {
|
||||
callbacks = nullptr;
|
||||
dlclose(handle);
|
||||
ALOGW("Unsupported native bridge interface.");
|
||||
}
|
||||
} else {
|
||||
dlclose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
// Two failure conditions: could not find library (dlopen failed), or could not find native
|
||||
// bridge interface (dlsym failed). Both are an error and close the native bridge.
|
||||
if (callbacks == nullptr) {
|
||||
CloseNativeBridge(true);
|
||||
} else {
|
||||
runtime_callbacks = runtime_cbs;
|
||||
state = NativeBridgeState::kOpened;
|
||||
}
|
||||
}
|
||||
return state == NativeBridgeState::kOpened;
|
||||
}
|
||||
}
|
||||
|
||||
bool NeedsNativeBridge(const char* instruction_set) {
|
||||
if (instruction_set == nullptr) {
|
||||
ALOGE("Null instruction set in NeedsNativeBridge.");
|
||||
return false;
|
||||
}
|
||||
return strncmp(instruction_set, ABI_STRING, strlen(ABI_STRING) + 1) != 0;
|
||||
}
|
||||
|
||||
bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) {
|
||||
if (state != NativeBridgeState::kOpened) {
|
||||
ALOGE("Invalid state: native bridge is expected to be opened.");
|
||||
CloseNativeBridge(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (app_data_dir_in == nullptr) {
|
||||
ALOGE("Application private directory cannot be null.");
|
||||
CloseNativeBridge(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the path to the application code cache directory.
|
||||
// The memory will be release after Initialization or when the native bridge is closed.
|
||||
const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2; // '\0' + '/'
|
||||
app_code_cache_dir = new char[len];
|
||||
snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir);
|
||||
|
||||
// Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo.
|
||||
// Failure is not fatal and will keep the native bridge in kPreInitialized.
|
||||
state = NativeBridgeState::kPreInitialized;
|
||||
|
||||
#ifndef __APPLE__
|
||||
if (instruction_set == nullptr) {
|
||||
return true;
|
||||
}
|
||||
size_t isa_len = strlen(instruction_set);
|
||||
if (isa_len > 10) {
|
||||
// 10 is a loose upper bound on the currently known instruction sets (a tight bound is 7 for
|
||||
// x86_64 [including the trailing \0]). This is so we don't have to change here if there will
|
||||
// be another instruction set in the future.
|
||||
ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.",
|
||||
instruction_set);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the file does not exist, the mount command will fail,
|
||||
// so we save the extra file existence check.
|
||||
char cpuinfo_path[1024];
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib"
|
||||
#ifdef __LP64__
|
||||
"64"
|
||||
#endif // __LP64__
|
||||
"/%s/cpuinfo", instruction_set);
|
||||
#else // !__ANDROID__
|
||||
// To be able to test on the host, we hardwire a relative path.
|
||||
snprintf(cpuinfo_path, sizeof(cpuinfo_path), "./cpuinfo");
|
||||
#endif
|
||||
|
||||
// Bind-mount.
|
||||
if (TEMP_FAILURE_RETRY(mount(cpuinfo_path, // Source.
|
||||
"/proc/cpuinfo", // Target.
|
||||
nullptr, // FS type.
|
||||
MS_BIND, // Mount flags: bind mount.
|
||||
nullptr)) == -1) { // "Data."
|
||||
ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno));
|
||||
}
|
||||
#else // __APPLE__
|
||||
UNUSED(instruction_set);
|
||||
ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible.");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) {
|
||||
if (value != nullptr) {
|
||||
jfieldID field_id = env->GetStaticFieldID(build_class, field, "Ljava/lang/String;");
|
||||
if (field_id == nullptr) {
|
||||
env->ExceptionClear();
|
||||
ALOGW("Could not find %s field.", field);
|
||||
return;
|
||||
}
|
||||
|
||||
jstring str = env->NewStringUTF(value);
|
||||
if (str == nullptr) {
|
||||
env->ExceptionClear();
|
||||
ALOGW("Could not create string %s.", value);
|
||||
return;
|
||||
}
|
||||
|
||||
env->SetStaticObjectField(build_class, field_id, str);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the environment for the bridged app.
|
||||
static void SetupEnvironment(const NativeBridgeCallbacks* callbacks, JNIEnv* env, const char* isa) {
|
||||
// Need a JNIEnv* to do anything.
|
||||
if (env == nullptr) {
|
||||
ALOGW("No JNIEnv* to set up app environment.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Query the bridge for environment values.
|
||||
const struct NativeBridgeRuntimeValues* env_values = callbacks->getAppEnv(isa);
|
||||
if (env_values == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep the JNIEnv clean.
|
||||
jint success = env->PushLocalFrame(16); // That should be small and large enough.
|
||||
if (success < 0) {
|
||||
// Out of memory, really borked.
|
||||
ALOGW("Out of memory while setting up app environment.");
|
||||
env->ExceptionClear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset CPU_ABI & CPU_ABI2 to values required by the apps running with native bridge.
|
||||
if (env_values->cpu_abi != nullptr || env_values->cpu_abi2 != nullptr ||
|
||||
env_values->abi_count >= 0) {
|
||||
jclass bclass_id = env->FindClass("android/os/Build");
|
||||
if (bclass_id != nullptr) {
|
||||
SetCpuAbi(env, bclass_id, "CPU_ABI", env_values->cpu_abi);
|
||||
SetCpuAbi(env, bclass_id, "CPU_ABI2", env_values->cpu_abi2);
|
||||
} else {
|
||||
// For example in a host test environment.
|
||||
env->ExceptionClear();
|
||||
ALOGW("Could not find Build class.");
|
||||
}
|
||||
}
|
||||
|
||||
if (env_values->os_arch != nullptr) {
|
||||
jclass sclass_id = env->FindClass("java/lang/System");
|
||||
if (sclass_id != nullptr) {
|
||||
jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "setUnchangeableSystemProperty",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)V");
|
||||
if (set_prop_id != nullptr) {
|
||||
// Init os.arch to the value reqired by the apps running with native bridge.
|
||||
env->CallStaticVoidMethod(sclass_id, set_prop_id, env->NewStringUTF("os.arch"),
|
||||
env->NewStringUTF(env_values->os_arch));
|
||||
} else {
|
||||
env->ExceptionClear();
|
||||
ALOGW("Could not find System#setUnchangeableSystemProperty.");
|
||||
}
|
||||
} else {
|
||||
env->ExceptionClear();
|
||||
ALOGW("Could not find System class.");
|
||||
}
|
||||
}
|
||||
|
||||
// Make it pristine again.
|
||||
env->PopLocalFrame(nullptr);
|
||||
}
|
||||
|
||||
bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
|
||||
// We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that
|
||||
// point we are not multi-threaded, so we do not need locking here.
|
||||
|
||||
if (state == NativeBridgeState::kPreInitialized) {
|
||||
// Check for code cache: if it doesn't exist try to create it.
|
||||
struct stat st;
|
||||
if (stat(app_code_cache_dir, &st) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) {
|
||||
ALOGW("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
|
||||
ReleaseAppCodeCacheDir();
|
||||
}
|
||||
} else {
|
||||
ALOGW("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
|
||||
ReleaseAppCodeCacheDir();
|
||||
}
|
||||
} else if (!S_ISDIR(st.st_mode)) {
|
||||
ALOGW("Code cache is not a directory %s.", app_code_cache_dir);
|
||||
ReleaseAppCodeCacheDir();
|
||||
}
|
||||
|
||||
// If we're still PreInitialized (dind't fail the code cache checks) try to initialize.
|
||||
if (state == NativeBridgeState::kPreInitialized) {
|
||||
if (callbacks->initialize(runtime_callbacks, app_code_cache_dir, instruction_set)) {
|
||||
SetupEnvironment(callbacks, env, instruction_set);
|
||||
state = NativeBridgeState::kInitialized;
|
||||
// We no longer need the code cache path, release the memory.
|
||||
ReleaseAppCodeCacheDir();
|
||||
} else {
|
||||
// Unload the library.
|
||||
dlclose(native_bridge_handle);
|
||||
CloseNativeBridge(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CloseNativeBridge(true);
|
||||
}
|
||||
|
||||
return state == NativeBridgeState::kInitialized;
|
||||
}
|
||||
|
||||
void UnloadNativeBridge() {
|
||||
// We expect only one place that calls UnloadNativeBridge: Runtime::DidForkFromZygote. At that
|
||||
// point we are not multi-threaded, so we do not need locking here.
|
||||
|
||||
switch(state) {
|
||||
case NativeBridgeState::kOpened:
|
||||
case NativeBridgeState::kPreInitialized:
|
||||
case NativeBridgeState::kInitialized:
|
||||
// Unload.
|
||||
dlclose(native_bridge_handle);
|
||||
CloseNativeBridge(false);
|
||||
break;
|
||||
|
||||
case NativeBridgeState::kNotSetup:
|
||||
// Not even set up. Error.
|
||||
CloseNativeBridge(true);
|
||||
break;
|
||||
|
||||
case NativeBridgeState::kClosed:
|
||||
// Ignore.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeBridgeError() {
|
||||
return had_error;
|
||||
}
|
||||
|
||||
bool NativeBridgeAvailable() {
|
||||
return state == NativeBridgeState::kOpened
|
||||
|| state == NativeBridgeState::kPreInitialized
|
||||
|| state == NativeBridgeState::kInitialized;
|
||||
}
|
||||
|
||||
bool NativeBridgeInitialized() {
|
||||
// Calls of this are supposed to happen in a state where the native bridge is stable, i.e., after
|
||||
// Runtime::DidForkFromZygote. In that case we do not need a lock.
|
||||
return state == NativeBridgeState::kInitialized;
|
||||
}
|
||||
|
||||
void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
return callbacks->loadLibrary(libpath, flag);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
|
||||
uint32_t len) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
return callbacks->getTrampoline(handle, name, shorty, len);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NativeBridgeIsSupported(const char* libpath) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
return callbacks->isSupported(libpath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t NativeBridgeGetVersion() {
|
||||
if (NativeBridgeAvailable()) {
|
||||
return callbacks->version;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(SIGNAL_VERSION)) {
|
||||
return callbacks->getSignalHandler(signal);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot get signal handler", SIGNAL_VERSION);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int NativeBridgeUnloadLibrary(void* handle) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->unloadLibrary(handle);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot unload library", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* NativeBridgeGetError() {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->getError();
|
||||
} else {
|
||||
return "native bridge implementation is not compatible with version 3, cannot get message";
|
||||
}
|
||||
}
|
||||
return "native bridge is not initialized";
|
||||
}
|
||||
|
||||
bool NativeBridgeIsPathSupported(const char* path) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->isPathSupported(path);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot check via library path", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
|
||||
const char* anon_ns_library_path) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->initAnonymousNamespace(public_ns_sonames, anon_ns_library_path);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path,
|
||||
native_bridge_namespace_t* parent_ns) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->createNamespace(name,
|
||||
ld_library_path,
|
||||
default_library_path,
|
||||
type,
|
||||
permitted_when_isolated_path,
|
||||
parent_ns);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot create namespace %s", NAMESPACE_VERSION, name);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
|
||||
const char* shared_libs_sonames) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->linkNamespaces(from, to, shared_libs_sonames);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
|
||||
if (!NativeBridgeInitialized()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isCompatibleWith(RUNTIME_NAMESPACE_VERSION)) {
|
||||
return callbacks->getExportedNamespace(name);
|
||||
}
|
||||
|
||||
// sphal is vendor namespace name -> use v4 callback in the case NB callbacks
|
||||
// are not compatible with v5
|
||||
if (isCompatibleWith(VENDOR_NAMESPACE_VERSION) && name != nullptr && strcmp("sphal", name) == 0) {
|
||||
return callbacks->getVendorNamespace();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
|
||||
if (NativeBridgeInitialized()) {
|
||||
if (isCompatibleWith(NAMESPACE_VERSION)) {
|
||||
return callbacks->loadLibraryExt(libpath, flag, ns);
|
||||
} else {
|
||||
ALOGE("not compatible with version %d, cannot load library in namespace", NAMESPACE_VERSION);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
} // namespace android
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "nativebridge/native_bridge.h"
|
||||
#define LOG_TAG "nativebridge"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace {
|
||||
|
||||
void* GetLibHandle() {
|
||||
static void* handle = dlopen("libnativebridge.so", RTLD_NOW);
|
||||
LOG_FATAL_IF(handle == nullptr, "Failed to load libnativebridge.so: %s", dlerror());
|
||||
return handle;
|
||||
}
|
||||
|
||||
template <typename FuncPtr>
|
||||
FuncPtr GetFuncPtr(const char* function_name) {
|
||||
auto f = reinterpret_cast<FuncPtr>(dlsym(GetLibHandle(), function_name));
|
||||
LOG_FATAL_IF(f == nullptr, "Failed to get address of %s: %s", function_name, dlerror());
|
||||
return f;
|
||||
}
|
||||
|
||||
#define GET_FUNC_PTR(name) GetFuncPtr<decltype(&name)>(#name)
|
||||
|
||||
} // namespace
|
||||
|
||||
bool LoadNativeBridge(const char* native_bridge_library_filename,
|
||||
const struct NativeBridgeRuntimeCallbacks* runtime_callbacks) {
|
||||
static auto f = GET_FUNC_PTR(LoadNativeBridge);
|
||||
return f(native_bridge_library_filename, runtime_callbacks);
|
||||
}
|
||||
|
||||
bool NeedsNativeBridge(const char* instruction_set) {
|
||||
static auto f = GET_FUNC_PTR(NeedsNativeBridge);
|
||||
return f(instruction_set);
|
||||
}
|
||||
|
||||
bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set) {
|
||||
static auto f = GET_FUNC_PTR(PreInitializeNativeBridge);
|
||||
return f(app_data_dir, instruction_set);
|
||||
}
|
||||
|
||||
bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
|
||||
static auto f = GET_FUNC_PTR(InitializeNativeBridge);
|
||||
return f(env, instruction_set);
|
||||
}
|
||||
|
||||
void UnloadNativeBridge() {
|
||||
static auto f = GET_FUNC_PTR(UnloadNativeBridge);
|
||||
return f();
|
||||
}
|
||||
|
||||
bool NativeBridgeAvailable() {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeAvailable);
|
||||
return f();
|
||||
}
|
||||
|
||||
bool NativeBridgeInitialized() {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeInitialized);
|
||||
return f();
|
||||
}
|
||||
|
||||
void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeLoadLibrary);
|
||||
return f(libpath, flag);
|
||||
}
|
||||
|
||||
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeGetTrampoline);
|
||||
return f(handle, name, shorty, len);
|
||||
}
|
||||
|
||||
bool NativeBridgeIsSupported(const char* libpath) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeIsSupported);
|
||||
return f(libpath);
|
||||
}
|
||||
|
||||
uint32_t NativeBridgeGetVersion() {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeGetVersion);
|
||||
return f();
|
||||
}
|
||||
|
||||
NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeGetSignalHandler);
|
||||
return f(signal);
|
||||
}
|
||||
|
||||
bool NativeBridgeError() {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeError);
|
||||
return f();
|
||||
}
|
||||
|
||||
bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeNameAcceptable);
|
||||
return f(native_bridge_library_filename);
|
||||
}
|
||||
|
||||
int NativeBridgeUnloadLibrary(void* handle) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeUnloadLibrary);
|
||||
return f(handle);
|
||||
}
|
||||
|
||||
const char* NativeBridgeGetError() {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeGetError);
|
||||
return f();
|
||||
}
|
||||
|
||||
bool NativeBridgeIsPathSupported(const char* path) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeIsPathSupported);
|
||||
return f(path);
|
||||
}
|
||||
|
||||
bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
|
||||
const char* anon_ns_library_path) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeInitAnonymousNamespace);
|
||||
return f(public_ns_sonames, anon_ns_library_path);
|
||||
}
|
||||
|
||||
struct native_bridge_namespace_t* 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_ns) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeCreateNamespace);
|
||||
return f(name, ld_library_path, default_library_path, type, permitted_when_isolated_path,
|
||||
parent_ns);
|
||||
}
|
||||
|
||||
bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
|
||||
struct native_bridge_namespace_t* to,
|
||||
const char* shared_libs_sonames) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeLinkNamespaces);
|
||||
return f(from, to, shared_libs_sonames);
|
||||
}
|
||||
|
||||
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
|
||||
struct native_bridge_namespace_t* ns) {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeLoadLibraryExt);
|
||||
return f(libpath, flag, ns);
|
||||
}
|
||||
|
||||
struct native_bridge_namespace_t* NativeBridgeGetVendorNamespace() {
|
||||
static auto f = GET_FUNC_PTR(NativeBridgeGetVendorNamespace);
|
||||
return f();
|
||||
}
|
||||
|
||||
#undef GET_FUNC_PTR
|
||||
|
||||
} // namespace android
|
|
@ -1,110 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2017 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.
|
||||
//
|
||||
|
||||
cc_defaults {
|
||||
name: "libnativebridge-dummy-defaults",
|
||||
|
||||
host_supported: true,
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
],
|
||||
header_libs: ["libnativebridge-headers"],
|
||||
cppflags: ["-fvisibility=protected"],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libnativebridge-dummy",
|
||||
srcs: ["DummyNativeBridge.cpp"],
|
||||
defaults: ["libnativebridge-dummy-defaults"],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libnativebridge2-dummy",
|
||||
srcs: ["DummyNativeBridge2.cpp"],
|
||||
defaults: ["libnativebridge-dummy-defaults"],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libnativebridge3-dummy",
|
||||
srcs: ["DummyNativeBridge3.cpp"],
|
||||
defaults: ["libnativebridge-dummy-defaults"],
|
||||
}
|
||||
|
||||
// Build the unit tests.
|
||||
cc_defaults {
|
||||
name: "libnativebridge-tests-defaults",
|
||||
test_per_src: true,
|
||||
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"CodeCacheCreate_test.cpp",
|
||||
"CodeCacheExists_test.cpp",
|
||||
"CodeCacheStatFail_test.cpp",
|
||||
"CompleteFlow_test.cpp",
|
||||
"InvalidCharsNativeBridge_test.cpp",
|
||||
"NativeBridge2Signal_test.cpp",
|
||||
"NativeBridgeVersion_test.cpp",
|
||||
"NeedsNativeBridge_test.cpp",
|
||||
"PreInitializeNativeBridge_test.cpp",
|
||||
"PreInitializeNativeBridgeFail1_test.cpp",
|
||||
"PreInitializeNativeBridgeFail2_test.cpp",
|
||||
"ReSetupNativeBridge_test.cpp",
|
||||
"UnavailableNativeBridge_test.cpp",
|
||||
"ValidNameNativeBridge_test.cpp",
|
||||
"NativeBridge3UnloadLibrary_test.cpp",
|
||||
"NativeBridge3GetError_test.cpp",
|
||||
"NativeBridge3IsPathSupported_test.cpp",
|
||||
"NativeBridge3InitAnonymousNamespace_test.cpp",
|
||||
"NativeBridge3CreateNamespace_test.cpp",
|
||||
"NativeBridge3LoadLibraryExt_test.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"liblog",
|
||||
"libnativebridge-dummy",
|
||||
],
|
||||
header_libs: ["libbase_headers"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libnativebridge-tests",
|
||||
defaults: ["libnativebridge-tests-defaults"],
|
||||
host_supported: true,
|
||||
shared_libs: ["libnativebridge"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libnativebridge-lazy-tests",
|
||||
defaults: ["libnativebridge-tests-defaults"],
|
||||
shared_libs: ["libnativebridge_lazy"],
|
||||
}
|
||||
|
||||
// Build the test for the C API.
|
||||
cc_test {
|
||||
name: "libnativebridge-api-tests",
|
||||
host_supported: true,
|
||||
test_per_src: true,
|
||||
srcs: [
|
||||
"NativeBridgeApi.c",
|
||||
],
|
||||
header_libs: ["libnativebridge-headers"],
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// Tests that the bridge initialization creates the code_cache if it doesn't
|
||||
// exists.
|
||||
TEST_F(NativeBridgeTest, CodeCacheCreate) {
|
||||
// Make sure that code_cache does not exists
|
||||
struct stat st;
|
||||
ASSERT_EQ(-1, stat(kCodeCache, &st));
|
||||
ASSERT_EQ(ENOENT, errno);
|
||||
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_FALSE(NativeBridgeError());
|
||||
|
||||
// Check that code_cache was created
|
||||
ASSERT_EQ(0, stat(kCodeCache, &st));
|
||||
ASSERT_TRUE(S_ISDIR(st.st_mode));
|
||||
|
||||
// Clean up
|
||||
UnloadNativeBridge();
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
|
||||
ASSERT_FALSE(NativeBridgeError());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// Tests that the bridge is initialized without errors if the code_cache already
|
||||
// exists.
|
||||
TEST_F(NativeBridgeTest, CodeCacheExists) {
|
||||
// Make sure that code_cache does not exists
|
||||
struct stat st;
|
||||
ASSERT_EQ(-1, stat(kCodeCache, &st));
|
||||
ASSERT_EQ(ENOENT, errno);
|
||||
|
||||
// Create the code_cache
|
||||
ASSERT_EQ(0, mkdir(kCodeCache, S_IRWXU | S_IRWXG | S_IXOTH));
|
||||
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_FALSE(NativeBridgeError());
|
||||
|
||||
// Check that the code cache is still there
|
||||
ASSERT_EQ(0, stat(kCodeCache, &st));
|
||||
ASSERT_TRUE(S_ISDIR(st.st_mode));
|
||||
|
||||
// Clean up
|
||||
UnloadNativeBridge();
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
|
||||
ASSERT_FALSE(NativeBridgeError());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// Tests that the bridge is initialized without errors if the code_cache is
|
||||
// existed as a file.
|
||||
TEST_F(NativeBridgeTest, CodeCacheStatFail) {
|
||||
int fd = creat(kCodeCache, O_RDWR);
|
||||
ASSERT_NE(-1, fd);
|
||||
close(fd);
|
||||
|
||||
struct stat st;
|
||||
ASSERT_EQ(-1, stat(kCodeCacheStatFail, &st));
|
||||
ASSERT_EQ(ENOTDIR, errno);
|
||||
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(kCodeCacheStatFail, "isa"));
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_FALSE(NativeBridgeError());
|
||||
|
||||
// Clean up
|
||||
UnloadNativeBridge();
|
||||
|
||||
ASSERT_FALSE(NativeBridgeError());
|
||||
unlink(kCodeCache);
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST_F(NativeBridgeTest, CompleteFlow) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
// Basic calls to check that nothing crashes
|
||||
ASSERT_FALSE(NativeBridgeIsSupported(nullptr));
|
||||
ASSERT_EQ(nullptr, NativeBridgeLoadLibrary(nullptr, 0));
|
||||
ASSERT_EQ(nullptr, NativeBridgeGetTrampoline(nullptr, nullptr, nullptr, 0));
|
||||
|
||||
// Unload
|
||||
UnloadNativeBridge();
|
||||
|
||||
ASSERT_FALSE(NativeBridgeAvailable());
|
||||
ASSERT_FALSE(NativeBridgeError());
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
// A dummy implementation of the native-bridge interface.
|
||||
|
||||
#include "nativebridge/native_bridge.h"
|
||||
|
||||
// NativeBridgeCallbacks implementations
|
||||
extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
|
||||
const char* /* app_code_cache_dir */,
|
||||
const char* /* isa */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge_loadLibrary(const char* /* libpath */, int /* flag */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge_getTrampoline(void* /* handle */, const char* /* name */,
|
||||
const char* /* shorty */, uint32_t /* len */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge_isSupported(const char* /* libpath */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv(
|
||||
const char* /* abi */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
android::NativeBridgeCallbacks NativeBridgeItf {
|
||||
.version = 1,
|
||||
.initialize = &native_bridge_initialize,
|
||||
.loadLibrary = &native_bridge_loadLibrary,
|
||||
.getTrampoline = &native_bridge_getTrampoline,
|
||||
.isSupported = &native_bridge_isSupported,
|
||||
.getAppEnv = &native_bridge_getAppEnv
|
||||
};
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
// A dummy implementation of the native-bridge interface.
|
||||
|
||||
#include "nativebridge/native_bridge.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
// NativeBridgeCallbacks implementations
|
||||
extern "C" bool native_bridge2_initialize(const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
|
||||
const char* /* app_code_cache_dir */,
|
||||
const char* /* isa */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge2_loadLibrary(const char* /* libpath */, int /* flag */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge2_getTrampoline(void* /* handle */, const char* /* name */,
|
||||
const char* /* shorty */, uint32_t /* len */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge2_isSupported(const char* /* libpath */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge2_getAppEnv(
|
||||
const char* /* abi */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge2_is_compatible_compatible_with(uint32_t version) {
|
||||
// For testing, allow 1 and 2, but disallow 3+.
|
||||
return version <= 2;
|
||||
}
|
||||
|
||||
static bool native_bridge2_dummy_signal_handler(int, siginfo_t*, void*) {
|
||||
// TODO: Implement something here. We'd either have to have a death test with a log here, or
|
||||
// we'd have to be able to resume after the faulting instruction...
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" android::NativeBridgeSignalHandlerFn native_bridge2_get_signal_handler(int signal) {
|
||||
if (signal == SIGSEGV) {
|
||||
return &native_bridge2_dummy_signal_handler;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
android::NativeBridgeCallbacks NativeBridgeItf {
|
||||
.version = 2,
|
||||
.initialize = &native_bridge2_initialize,
|
||||
.loadLibrary = &native_bridge2_loadLibrary,
|
||||
.getTrampoline = &native_bridge2_getTrampoline,
|
||||
.isSupported = &native_bridge2_isSupported,
|
||||
.getAppEnv = &native_bridge2_getAppEnv,
|
||||
.isCompatibleWith = &native_bridge2_is_compatible_compatible_with,
|
||||
.getSignalHandler = &native_bridge2_get_signal_handler
|
||||
};
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
// A dummy implementation of the native-bridge interface.
|
||||
|
||||
#include "nativebridge/native_bridge.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
// NativeBridgeCallbacks implementations
|
||||
extern "C" bool native_bridge3_initialize(
|
||||
const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
|
||||
const char* /* app_code_cache_dir */,
|
||||
const char* /* isa */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge3_loadLibrary(const char* /* libpath */, int /* flag */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge3_getTrampoline(void* /* handle */, const char* /* name */,
|
||||
const char* /* shorty */, uint32_t /* len */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge3_isSupported(const char* /* libpath */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge3_getAppEnv(
|
||||
const char* /* abi */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge3_isCompatibleWith(uint32_t version) {
|
||||
// For testing, allow 1-3, but disallow 4+.
|
||||
return version <= 3;
|
||||
}
|
||||
|
||||
static bool native_bridge3_dummy_signal_handler(int, siginfo_t*, void*) {
|
||||
// TODO: Implement something here. We'd either have to have a death test with a log here, or
|
||||
// we'd have to be able to resume after the faulting instruction...
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" android::NativeBridgeSignalHandlerFn native_bridge3_getSignalHandler(int signal) {
|
||||
if (signal == SIGSEGV) {
|
||||
return &native_bridge3_dummy_signal_handler;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" int native_bridge3_unloadLibrary(void* /* handle */) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" const char* native_bridge3_getError() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge3_isPathSupported(const char* /* path */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge3_initAnonymousNamespace(const char* /* public_ns_sonames */,
|
||||
const char* /* anon_ns_library_path */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" android::native_bridge_namespace_t*
|
||||
native_bridge3_createNamespace(const char* /* name */,
|
||||
const char* /* ld_library_path */,
|
||||
const char* /* default_library_path */,
|
||||
uint64_t /* type */,
|
||||
const char* /* permitted_when_isolated_path */,
|
||||
android::native_bridge_namespace_t* /* parent_ns */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" bool native_bridge3_linkNamespaces(android::native_bridge_namespace_t* /* from */,
|
||||
android::native_bridge_namespace_t* /* to */,
|
||||
const char* /* shared_libs_soname */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
|
||||
int /* flag */,
|
||||
android::native_bridge_namespace_t* /* ns */) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
android::NativeBridgeCallbacks NativeBridgeItf{
|
||||
// v1
|
||||
.version = 3,
|
||||
.initialize = &native_bridge3_initialize,
|
||||
.loadLibrary = &native_bridge3_loadLibrary,
|
||||
.getTrampoline = &native_bridge3_getTrampoline,
|
||||
.isSupported = &native_bridge3_isSupported,
|
||||
.getAppEnv = &native_bridge3_getAppEnv,
|
||||
// v2
|
||||
.isCompatibleWith = &native_bridge3_isCompatibleWith,
|
||||
.getSignalHandler = &native_bridge3_getSignalHandler,
|
||||
// v3
|
||||
.unloadLibrary = &native_bridge3_unloadLibrary,
|
||||
.getError = &native_bridge3_getError,
|
||||
.isPathSupported = &native_bridge3_isPathSupported,
|
||||
.initAnonymousNamespace = &native_bridge3_initAnonymousNamespace,
|
||||
.createNamespace = &native_bridge3_createNamespace,
|
||||
.linkNamespaces = &native_bridge3_linkNamespaces,
|
||||
.loadLibraryExt = &native_bridge3_loadLibraryExt};
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* kTestName = "../librandom$@-bridge_not.existing.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, InvalidChars) {
|
||||
// Do one test actually calling setup.
|
||||
EXPECT_EQ(false, NativeBridgeError());
|
||||
LoadNativeBridge(kTestName, nullptr);
|
||||
// This should lead to an error for invalid characters.
|
||||
EXPECT_EQ(true, NativeBridgeError());
|
||||
|
||||
// Further tests need to use NativeBridgeNameAcceptable, as the error
|
||||
// state can't be changed back.
|
||||
EXPECT_EQ(false, NativeBridgeNameAcceptable("."));
|
||||
EXPECT_EQ(false, NativeBridgeNameAcceptable(".."));
|
||||
EXPECT_EQ(false, NativeBridgeNameAcceptable("_"));
|
||||
EXPECT_EQ(false, NativeBridgeNameAcceptable("-"));
|
||||
EXPECT_EQ(false, NativeBridgeNameAcceptable("lib@.so"));
|
||||
EXPECT_EQ(false, NativeBridgeNameAcceptable("lib$.so"));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V2_Signal) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary2, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
ASSERT_EQ(2U, NativeBridgeGetVersion());
|
||||
ASSERT_NE(nullptr, NativeBridgeGetSignalHandler(SIGSEGV));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_CreateNamespace) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
ASSERT_EQ(3U, NativeBridgeGetVersion());
|
||||
ASSERT_EQ(nullptr, NativeBridgeCreateNamespace(nullptr, nullptr, nullptr,
|
||||
0, nullptr, nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_GetError) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
ASSERT_EQ(3U, NativeBridgeGetVersion());
|
||||
ASSERT_EQ(nullptr, NativeBridgeGetError());
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_InitAnonymousNamespace) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
ASSERT_EQ(3U, NativeBridgeGetVersion());
|
||||
ASSERT_EQ(true, NativeBridgeInitAnonymousNamespace(nullptr, nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_IsPathSupported) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
ASSERT_EQ(3U, NativeBridgeGetVersion());
|
||||
ASSERT_EQ(true, NativeBridgeIsPathSupported(nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_LoadLibraryExt) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
ASSERT_EQ(3U, NativeBridgeGetVersion());
|
||||
ASSERT_EQ(nullptr, NativeBridgeLoadLibraryExt(nullptr, 0, nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, V3_UnloadLibrary) {
|
||||
// Init
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
|
||||
ASSERT_TRUE(NativeBridgeAvailable());
|
||||
|
||||
ASSERT_EQ(3U, NativeBridgeGetVersion());
|
||||
ASSERT_EQ(0, NativeBridgeUnloadLibrary(nullptr));
|
||||
|
||||
// Clean-up code_cache
|
||||
ASSERT_EQ(0, rmdir(kCodeCache));
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* 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 "nativebridge/native_bridge.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return 0;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#ifndef NATIVE_BRIDGE_TEST_H_
|
||||
#define NATIVE_BRIDGE_TEST_H_
|
||||
|
||||
#define LOG_TAG "NativeBridge_test"
|
||||
|
||||
#include <nativebridge/native_bridge.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
|
||||
constexpr const char* kCodeCache = "./code_cache";
|
||||
constexpr const char* kCodeCacheStatFail = "./code_cache/temp";
|
||||
constexpr const char* kNativeBridgeLibrary2 = "libnativebridge2-dummy.so";
|
||||
constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
|
||||
|
||||
namespace android {
|
||||
|
||||
class NativeBridgeTest : public testing::Test {
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // NATIVE_BRIDGE_H_
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST_F(NativeBridgeTest, Version) {
|
||||
// When a bridge isn't loaded, we expect 0.
|
||||
EXPECT_EQ(NativeBridgeGetVersion(), 0U);
|
||||
|
||||
// After our dummy bridge has been loaded, we expect 1.
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
|
||||
EXPECT_EQ(NativeBridgeGetVersion(), 1U);
|
||||
|
||||
// Unload
|
||||
UnloadNativeBridge();
|
||||
|
||||
// Version information is gone.
|
||||
EXPECT_EQ(NativeBridgeGetVersion(), 0U);
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <android-base/macros.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* kISAs[] = { "arm", "arm64", "mips", "mips64", "x86", "x86_64", "random", "64arm",
|
||||
"64_x86", "64_x86_64", "", "reallylongstringabcd", nullptr };
|
||||
|
||||
TEST_F(NativeBridgeTest, NeedsNativeBridge) {
|
||||
EXPECT_EQ(false, NeedsNativeBridge(ABI_STRING));
|
||||
|
||||
const size_t kISACount = sizeof(kISAs) / sizeof(kISAs[0]);
|
||||
for (size_t i = 0; i < kISACount; i++) {
|
||||
EXPECT_EQ(kISAs[i] == nullptr ? false : strcmp(kISAs[i], ABI_STRING) != 0,
|
||||
NeedsNativeBridge(kISAs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail1) {
|
||||
// Needs a valid application directory.
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
|
||||
ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa"));
|
||||
ASSERT_TRUE(NativeBridgeError());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail2) {
|
||||
// Needs LoadNativeBridge() first
|
||||
ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa"));
|
||||
ASSERT_TRUE(NativeBridgeError());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST_F(NativeBridgeTest, PreInitializeNativeBridge) {
|
||||
ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
|
||||
#if !defined(__APPLE__) // Mac OS does not support bind-mount.
|
||||
#if !defined(__ANDROID__) // Cannot write into the hard-wired location.
|
||||
static constexpr const char* kTestData = "PreInitializeNativeBridge test.";
|
||||
|
||||
// Try to create our mount namespace.
|
||||
if (unshare(CLONE_NEWNS) != -1) {
|
||||
// Create a dummy file.
|
||||
FILE* cpuinfo = fopen("./cpuinfo", "w");
|
||||
ASSERT_NE(nullptr, cpuinfo) << strerror(errno);
|
||||
fprintf(cpuinfo, kTestData);
|
||||
fclose(cpuinfo);
|
||||
|
||||
ASSERT_TRUE(PreInitializeNativeBridge("does not matter 1", "short 2"));
|
||||
|
||||
// Read /proc/cpuinfo
|
||||
FILE* proc_cpuinfo = fopen("/proc/cpuinfo", "r");
|
||||
ASSERT_NE(nullptr, proc_cpuinfo) << strerror(errno);
|
||||
char buf[1024];
|
||||
EXPECT_NE(nullptr, fgets(buf, sizeof(buf), proc_cpuinfo)) << "Error reading.";
|
||||
fclose(proc_cpuinfo);
|
||||
|
||||
EXPECT_EQ(0, strcmp(buf, kTestData));
|
||||
|
||||
// Delete the file.
|
||||
ASSERT_EQ(0, unlink("./cpuinfo")) << "Error unlinking temporary file.";
|
||||
// Ending the test will tear down the mount namespace.
|
||||
} else {
|
||||
GTEST_LOG_(WARNING) << "Could not create mount namespace. Are you running this as root?";
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST_F(NativeBridgeTest, ReSetup) {
|
||||
EXPECT_EQ(false, NativeBridgeError());
|
||||
LoadNativeBridge("", nullptr);
|
||||
EXPECT_EQ(false, NativeBridgeError());
|
||||
LoadNativeBridge("", nullptr);
|
||||
// This should lead to an error for trying to re-setup a native bridge.
|
||||
EXPECT_EQ(true, NativeBridgeError());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
#include "NativeBridgeTest.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
TEST_F(NativeBridgeTest, NoNativeBridge) {
|
||||
EXPECT_EQ(false, NativeBridgeAvailable());
|
||||
// Try to initialize. This should fail as we are not set up.
|
||||
EXPECT_EQ(false, InitializeNativeBridge(nullptr, nullptr));
|
||||
EXPECT_EQ(true, NativeBridgeError());
|
||||
EXPECT_EQ(false, NativeBridgeAvailable());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
|
||||
#include <NativeBridgeTest.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static const char* kTestName = "librandom-bridge_not.existing.so";
|
||||
|
||||
TEST_F(NativeBridgeTest, ValidName) {
|
||||
// Check that the name is acceptable.
|
||||
EXPECT_EQ(true, NativeBridgeNameAcceptable(kTestName));
|
||||
|
||||
// Now check what happens on LoadNativeBridge.
|
||||
EXPECT_EQ(false, NativeBridgeError());
|
||||
LoadNativeBridge(kTestName, nullptr);
|
||||
// This will lead to an error as the library doesn't exist.
|
||||
EXPECT_EQ(true, NativeBridgeError());
|
||||
EXPECT_EQ(false, NativeBridgeAvailable());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1 +0,0 @@
|
|||
../.clang-format-2
|
|
@ -1,97 +0,0 @@
|
|||
// Shared library for target
|
||||
// ========================================================
|
||||
cc_defaults {
|
||||
name: "libnativeloader-defaults",
|
||||
cflags: [
|
||||
"-Werror",
|
||||
"-Wall",
|
||||
],
|
||||
cppflags: [
|
||||
"-fvisibility=hidden",
|
||||
],
|
||||
header_libs: ["libnativeloader-headers"],
|
||||
export_header_lib_headers: ["libnativeloader-headers"],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libnativeloader",
|
||||
defaults: ["libnativeloader-defaults"],
|
||||
// TODO(oth): remove after moving under art/ (b/137364733)
|
||||
visibility: ["//visibility:public"],
|
||||
host_supported: true,
|
||||
srcs: [
|
||||
"native_loader.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libnativehelper",
|
||||
"liblog",
|
||||
"libnativebridge",
|
||||
"libbase",
|
||||
],
|
||||
target: {
|
||||
android: {
|
||||
srcs: [
|
||||
"library_namespaces.cpp",
|
||||
"native_loader_namespace.cpp",
|
||||
"public_libraries.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libdl_android",
|
||||
],
|
||||
},
|
||||
},
|
||||
required: [
|
||||
"llndk.libraries.txt",
|
||||
"vndksp.libraries.txt",
|
||||
],
|
||||
stubs: {
|
||||
symbol_file: "libnativeloader.map.txt",
|
||||
versions: ["1"],
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(b/124250621) eliminate the need for this library
|
||||
cc_library {
|
||||
name: "libnativeloader_lazy",
|
||||
defaults: ["libnativeloader-defaults"],
|
||||
// TODO(oth): remove after moving under art/ (b/137364733)
|
||||
visibility: ["//visibility:public"],
|
||||
host_supported: false,
|
||||
srcs: ["native_loader_lazy.cpp"],
|
||||
required: ["libnativeloader"],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libnativeloader-headers",
|
||||
// TODO(oth): remove after moving under art/ (b/137364733)
|
||||
visibility: ["//visibility:public"],
|
||||
host_supported: true,
|
||||
export_include_dirs: ["include"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libnativeloader_test",
|
||||
srcs: [
|
||||
"native_loader_test.cpp",
|
||||
"native_loader.cpp",
|
||||
"library_namespaces.cpp",
|
||||
"native_loader_namespace.cpp",
|
||||
"public_libraries.cpp",
|
||||
],
|
||||
cflags: ["-DANDROID"],
|
||||
static_libs: [
|
||||
"libbase",
|
||||
"liblog",
|
||||
"libnativehelper",
|
||||
"libgmock",
|
||||
],
|
||||
header_libs: [
|
||||
"libnativebridge-headers",
|
||||
"libnativeloader-headers",
|
||||
],
|
||||
system_shared_libs: [
|
||||
"libc",
|
||||
"libm",
|
||||
],
|
||||
test_suites: ["device-tests"],
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
filter=-build/header_guard
|
||||
filter=-readability/check
|
||||
filter=-build/namespaces
|
|
@ -1,6 +0,0 @@
|
|||
dimitry@google.com
|
||||
jiyong@google.com
|
||||
ngeoffray@google.com
|
||||
oth@google.com
|
||||
mast@google.com
|
||||
rpl@google.com
|
|
@ -1,84 +0,0 @@
|
|||
libnativeloader
|
||||
===============================================================================
|
||||
|
||||
Overview
|
||||
-------------------------------------------------------------------------------
|
||||
libnativeloader is responsible for loading native shared libraries (`*.so`
|
||||
files) inside the Android Runtime (ART). The native shared libraries could be
|
||||
app-provided JNI libraries or public native libraries like `libc.so` provided
|
||||
by the platform.
|
||||
|
||||
The most typical use case of this library is calling `System.loadLibrary(name)`.
|
||||
When the method is called, the ART runtime delegates the call to this library
|
||||
along with the reference to the classloader where the call was made. Then this
|
||||
library finds the linker namespace (named `classloader-namespace`) that is
|
||||
associated with the given classloader, and tries to load the requested library
|
||||
from the namespace. The actual searching, loading, and linking of the library
|
||||
is performed by the dynamic linker.
|
||||
|
||||
The linker namespace is created when an APK is loaded into the process, and is
|
||||
associated with the classloader that loaded the APK. The linker namespace is
|
||||
configured so that only the JNI libraries embedded in the APK is accessible
|
||||
from the namespace, thus preventing an APK from loading JNI libraries of other
|
||||
APKs.
|
||||
|
||||
The linker namespace is also configured differently depending on other
|
||||
characteristics of the APK such as whether or not the APK is bundled with the
|
||||
platform. In case of the unbundled, i.e., downloaded or updated APK, only the
|
||||
public native libraries that is listed in `/system/etc/public.libraries.txt`
|
||||
are available from the platform, whereas in case of the bundled, all libraries
|
||||
under `/system/lib` are available (i.e. shared). In case when the unbundled
|
||||
app is from `/vendor` or `/product` partition, the app is additionally provided
|
||||
with the [VNDK-SP](https://source.android.com/devices/architecture/vndk#sp-hal)
|
||||
libraries. As the platform is getting modularized with
|
||||
[APEX](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/docs/README.md),
|
||||
some libraries are no longer provided from platform, but from the APEXes which
|
||||
have their own linker namespaces. For example, ICU libraries `libicuuc.so` and
|
||||
`libicui18n.so` are from the runtime APEX.
|
||||
|
||||
The list of public native libraries is not static. The default set of libraries
|
||||
are defined in AOSP, but partners can extend it to include their own libraries.
|
||||
Currently, following extensions are available:
|
||||
|
||||
- `/vendor/etc/public.libraries.txt`: libraries in `/vendor/lib` that are
|
||||
specific to the underlying SoC, e.g. GPU, DSP, etc.
|
||||
- `/{system|product}/etc/public.libraries-<companyname>.txt`: libraries in
|
||||
`/{system|product}/lib` that a device manufacturer has newly added. The
|
||||
libraries should be named as `lib<name>.<companyname>.so` as in
|
||||
`libFoo.acme.so`.
|
||||
|
||||
Note that, due to the naming constraint requiring `.<companyname>.so` suffix, it
|
||||
is prohibited for a device manufacturer to expose an AOSP-defined private
|
||||
library, e.g. libgui.so, libart.so, etc., to APKs.
|
||||
|
||||
Lastly, libnativeloader is responsible for abstracting the two types of the
|
||||
dynamic linker interface: `libdl.so` and `libnativebridge.so`. The former is
|
||||
for non-translated, e.g. ARM-on-ARM, libraries, while the latter is for
|
||||
loading libraries in a translated environment such as ARM-on-x86.
|
||||
|
||||
Implementation
|
||||
-------------------------------------------------------------------------------
|
||||
Implementation wise, libnativeloader consists of four parts:
|
||||
|
||||
- `native_loader.cpp`
|
||||
- `library_namespaces.cpp`
|
||||
- `native_loader_namespace.cpp`
|
||||
- `public_libraries.cpp`
|
||||
|
||||
`native_loader.cpp` implements the public interface of this library. It is just
|
||||
a thin wrapper around `library_namespaces.cpp` and `native_loader_namespace.cpp`.
|
||||
|
||||
`library_namespaces.cpp` implements the singleton class `LibraryNamespaces` which
|
||||
is a manager-like entity that is responsible for creating and configuring
|
||||
linker namespaces and finding an already created linker namespace for a given
|
||||
classloader.
|
||||
|
||||
`native_loader_namespace.cpp` implements the class `NativeLoaderNamespace` that
|
||||
models a linker namespace. Its main job is to abstract the two types of the
|
||||
dynamic linker interface so that other parts of this library do not have to know
|
||||
the differences of the interfaces.
|
||||
|
||||
`public_libraries.cpp` is responsible for reading `*.txt` files for the public
|
||||
native libraries from the various partitions. It can be considered as a part of
|
||||
`LibraryNamespaces` but is separated from it to hide the details of the parsing
|
||||
routines.
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "libnativeloader_test"
|
||||
}
|
||||
],
|
||||
"imports": [
|
||||
{
|
||||
"path": "cts/tests/tests/jni"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#ifndef __ANDROID_DLEXT_NAMESPACES_H__
|
||||
#define __ANDROID_DLEXT_NAMESPACES_H__
|
||||
|
||||
#include <android/dlext.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
enum {
|
||||
/* A regular namespace is the namespace with a custom search path that does
|
||||
* not impose any restrictions on the location of native libraries.
|
||||
*/
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR = 0,
|
||||
|
||||
/* An isolated namespace requires all the libraries to be on the search path
|
||||
* or under permitted_when_isolated_path. The search path is the union of
|
||||
* ld_library_path and default_library_path.
|
||||
*/
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
|
||||
|
||||
/* The shared namespace clones the list of libraries of the caller namespace upon creation
|
||||
* which means that they are shared between namespaces - the caller namespace and the new one
|
||||
* will use the same copy of a library if it was loaded prior to android_create_namespace call.
|
||||
*
|
||||
* Note that libraries loaded after the namespace is created will not be shared.
|
||||
*
|
||||
* Shared namespaces can be isolated or regular. Note that they do not inherit the search path nor
|
||||
* permitted_path from the caller's namespace.
|
||||
*/
|
||||
ANDROID_NAMESPACE_TYPE_SHARED = 2,
|
||||
|
||||
/* This flag instructs linker to enable grey-list workaround for the namespace.
|
||||
* See http://b/26394120 for details.
|
||||
*/
|
||||
ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
|
||||
|
||||
/* This flag instructs linker to use this namespace as the anonymous
|
||||
* namespace. The anonymous namespace is used in the case when linker cannot
|
||||
* identify the caller of dlopen/dlsym. This happens for the code not loaded
|
||||
* by dynamic linker; for example calls from the mono-compiled code. There can
|
||||
* be only one anonymous namespace in a process. If there already is an
|
||||
* anonymous namespace in the process, using this flag when creating a new
|
||||
* namespace causes an error.
|
||||
*/
|
||||
ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS = 0x10000000,
|
||||
|
||||
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED =
|
||||
ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
};
|
||||
|
||||
/*
|
||||
* Creates new linker namespace.
|
||||
* ld_library_path and default_library_path represent the search path
|
||||
* for the libraries in the namespace.
|
||||
*
|
||||
* The libraries in the namespace are searched by folowing order:
|
||||
* 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
|
||||
* 2. In directories specified by DT_RUNPATH of the "needed by" binary.
|
||||
* 3. deault_library_path (This of this as namespace-local default library path)
|
||||
*
|
||||
* When type is ANDROID_NAMESPACE_TYPE_ISOLATED the resulting namespace requires all of
|
||||
* the libraries to be on the search path or under the permitted_when_isolated_path;
|
||||
* the search_path is ld_library_path:default_library_path. Note that the
|
||||
* permitted_when_isolated_path path is not part of the search_path and
|
||||
* does not affect the search order. It is a way to allow loading libraries from specific
|
||||
* locations when using absolute path.
|
||||
* 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, struct android_namespace_t* parent);
|
||||
|
||||
/*
|
||||
* Creates a link between namespaces. Every link has list of sonames of
|
||||
* shared libraries. These are the libraries which are accessible from
|
||||
* namespace 'from' but loaded within namespace 'to' context.
|
||||
* When to namespace is nullptr this function establishes a link between
|
||||
* 'from' namespace and the default namespace.
|
||||
*
|
||||
* The lookup order of the libraries in namespaces with links is following:
|
||||
* 1. Look inside current namespace using 'this' namespace search path.
|
||||
* 2. Look in linked namespaces
|
||||
* 2.1. Perform soname check - if library soname is not in the list of shared
|
||||
* libraries sonames skip this link, otherwise
|
||||
* 2.2. Search library using linked namespace search path. Note that this
|
||||
* step will not go deeper into linked namespaces for this library but
|
||||
* will do so for DT_NEEDED libraries.
|
||||
*/
|
||||
extern bool android_link_namespaces(struct android_namespace_t* from,
|
||||
struct android_namespace_t* to,
|
||||
const char* shared_libs_sonames);
|
||||
|
||||
extern struct android_namespace_t* android_get_exported_namespace(const char* name);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* __ANDROID_DLEXT_NAMESPACES_H__ */
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#ifndef NATIVE_LOADER_H_
|
||||
#define NATIVE_LOADER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#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();
|
||||
|
||||
__attribute__((visibility("default"))) jstring CreateClassLoaderNamespace(
|
||||
JNIEnv* env, int32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path,
|
||||
jstring library_path, jstring permitted_path);
|
||||
|
||||
__attribute__((visibility("default"))) void* OpenNativeLibrary(
|
||||
JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader,
|
||||
const char* caller_location, jstring library_path, bool* needs_native_bridge, char** error_msg);
|
||||
|
||||
__attribute__((visibility("default"))) bool CloseNativeLibrary(void* handle,
|
||||
const bool needs_native_bridge,
|
||||
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"))) 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* OpenNativeLibraryInNamespace(
|
||||
struct NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
|
||||
char** error_msg);
|
||||
#endif
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void ResetNativeLoader();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
} // namespace android
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // NATIVE_BRIDGE_H_
|
|
@ -1,31 +0,0 @@
|
|||
#
|
||||
# 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:
|
||||
*;
|
||||
};
|
|
@ -1,319 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include "library_namespaces.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/macros.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
|
||||
#include "nativeloader/dlext_namespaces.h"
|
||||
#include "public_libraries.h"
|
||||
#include "utils.h"
|
||||
|
||||
using android::base::Error;
|
||||
|
||||
namespace android::nativeloader {
|
||||
|
||||
namespace {
|
||||
// The device may be configured to have the vendor libraries loaded to a separate namespace.
|
||||
// For historical reasons this namespace was named sphal but effectively it is intended
|
||||
// to use to load vendor libraries to separate namespace with controlled interface between
|
||||
// vendor and system namespaces.
|
||||
constexpr const char* kVendorNamespaceName = "sphal";
|
||||
constexpr const char* kVndkNamespaceName = "vndk";
|
||||
constexpr const char* kArtNamespaceName = "art";
|
||||
constexpr const char* kNeuralNetworksNamespaceName = "neuralnetworks";
|
||||
|
||||
// classloader-namespace is a linker namespace that is created for the loaded
|
||||
// app. To be specific, it is created for the app classloader. When
|
||||
// System.load() is called from a Java class that is loaded from the
|
||||
// classloader, the classloader-namespace namespace associated with that
|
||||
// classloader is selected for dlopen. The namespace is configured so that its
|
||||
// search path is set to the app-local JNI directory and it is linked to the
|
||||
// platform namespace with the names of libs listed in the public.libraries.txt.
|
||||
// This way an app can only load its own JNI libraries along with the public libs.
|
||||
constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
|
||||
// Same thing for vendor APKs.
|
||||
constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
|
||||
|
||||
// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
|
||||
// System.load() with an absolute path which is outside of the classloader library search path.
|
||||
// This list includes all directories app is allowed to access this way.
|
||||
constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
|
||||
|
||||
constexpr const char* kVendorLibPath = "/vendor/" LIB;
|
||||
constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB;
|
||||
|
||||
const std::regex kVendorDexPathRegex("(^|:)/vendor/");
|
||||
const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
|
||||
|
||||
// Define origin of APK if it is from vendor partition or product partition
|
||||
typedef enum {
|
||||
APK_ORIGIN_DEFAULT = 0,
|
||||
APK_ORIGIN_VENDOR = 1,
|
||||
APK_ORIGIN_PRODUCT = 2,
|
||||
} ApkOrigin;
|
||||
|
||||
jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
|
||||
jmethodID get_parent =
|
||||
env->GetMethodID(class_loader_class, "getParent", "()Ljava/lang/ClassLoader;");
|
||||
|
||||
return env->CallObjectMethod(class_loader, get_parent);
|
||||
}
|
||||
|
||||
ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
|
||||
ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
|
||||
|
||||
if (dex_path != nullptr) {
|
||||
ScopedUtfChars dex_path_utf_chars(env, dex_path);
|
||||
|
||||
if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
|
||||
apk_origin = APK_ORIGIN_VENDOR;
|
||||
}
|
||||
|
||||
if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
|
||||
LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
|
||||
"Dex path contains both vendor and product partition : %s",
|
||||
dex_path_utf_chars.c_str());
|
||||
|
||||
apk_origin = APK_ORIGIN_PRODUCT;
|
||||
}
|
||||
}
|
||||
return apk_origin;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void LibraryNamespaces::Initialize() {
|
||||
// Once public namespace is initialized there is no
|
||||
// point in running this code - it will have no effect
|
||||
// on the current list of public libraries.
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// android_init_namespaces() expects all the public libraries
|
||||
// to be loaded so that they can be found by soname alone.
|
||||
//
|
||||
// TODO(dimitry): this is a bit misleading since we do not know
|
||||
// if the vendor public library is going to be opened from /vendor/lib
|
||||
// we might as well end up loading them from /system/lib or /product/lib
|
||||
// For now we rely on CTS test to catch things like this but
|
||||
// it should probably be addressed in the future.
|
||||
for (const auto& soname : android::base::Split(preloadable_public_libraries(), ":")) {
|
||||
LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
|
||||
"Error preloading public library %s: %s", soname.c_str(), dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
|
||||
jobject class_loader, bool is_shared,
|
||||
jstring dex_path,
|
||||
jstring java_library_path,
|
||||
jstring java_permitted_path) {
|
||||
std::string library_path; // empty string by default.
|
||||
|
||||
if (java_library_path != nullptr) {
|
||||
ScopedUtfChars library_path_utf_chars(env, java_library_path);
|
||||
library_path = library_path_utf_chars.c_str();
|
||||
}
|
||||
|
||||
ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
|
||||
|
||||
// (http://b/27588281) This is a workaround for apps using custom
|
||||
// classloaders and calling System.load() with an absolute path which
|
||||
// is outside of the classloader library search path.
|
||||
//
|
||||
// This part effectively allows such a classloader to access anything
|
||||
// under /data and /mnt/expand
|
||||
std::string permitted_path = kWhitelistedDirectories;
|
||||
|
||||
if (java_permitted_path != nullptr) {
|
||||
ScopedUtfChars path(env, java_permitted_path);
|
||||
if (path.c_str() != nullptr && path.size() > 0) {
|
||||
permitted_path = permitted_path + ":" + path.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr,
|
||||
"There is already a namespace associated with this classloader");
|
||||
|
||||
std::string system_exposed_libraries = default_public_libraries();
|
||||
const char* namespace_name = kClassloaderNamespaceName;
|
||||
bool unbundled_vendor_or_product_app = false;
|
||||
if ((apk_origin == APK_ORIGIN_VENDOR ||
|
||||
(apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
|
||||
!is_shared) {
|
||||
unbundled_vendor_or_product_app = true;
|
||||
// For vendor / product apks, give access to the vendor / product lib even though
|
||||
// they are treated as unbundled; the libs and apks are still bundled
|
||||
// together in the vendor / product partition.
|
||||
const char* origin_partition;
|
||||
const char* origin_lib_path;
|
||||
|
||||
switch (apk_origin) {
|
||||
case APK_ORIGIN_VENDOR:
|
||||
origin_partition = "vendor";
|
||||
origin_lib_path = kVendorLibPath;
|
||||
break;
|
||||
case APK_ORIGIN_PRODUCT:
|
||||
origin_partition = "product";
|
||||
origin_lib_path = kProductLibPath;
|
||||
break;
|
||||
default:
|
||||
origin_partition = "unknown";
|
||||
origin_lib_path = "";
|
||||
}
|
||||
library_path = library_path + ":" + origin_lib_path;
|
||||
permitted_path = permitted_path + ":" + origin_lib_path;
|
||||
|
||||
// Also give access to LLNDK libraries since they are available to vendors
|
||||
system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries().c_str();
|
||||
|
||||
// Different name is useful for debugging
|
||||
namespace_name = kVendorClassloaderNamespaceName;
|
||||
ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
|
||||
origin_partition, library_path.c_str());
|
||||
} else {
|
||||
// extended public libraries are NOT available to vendor apks, otherwise it
|
||||
// would be system->vendor violation.
|
||||
if (!extended_public_libraries().empty()) {
|
||||
system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries();
|
||||
}
|
||||
}
|
||||
|
||||
// Create the app namespace
|
||||
NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
|
||||
// Heuristic: the first classloader with non-empty library_path is assumed to
|
||||
// be the main classloader for app
|
||||
// TODO(b/139178525) remove this heuristic by determining this in LoadedApk (or its
|
||||
// friends) and then passing it down to here.
|
||||
bool is_main_classloader = app_main_namespace_ == nullptr && !library_path.empty();
|
||||
// Policy: the namespace for the main classloader is also used as the
|
||||
// anonymous namespace.
|
||||
bool also_used_as_anonymous = is_main_classloader;
|
||||
// Note: this function is executed with g_namespaces_mutex held, thus no
|
||||
// racing here.
|
||||
auto app_ns = NativeLoaderNamespace::Create(
|
||||
namespace_name, library_path, permitted_path, parent_ns, is_shared,
|
||||
target_sdk_version < 24 /* is_greylist_enabled */, also_used_as_anonymous);
|
||||
if (!app_ns) {
|
||||
return app_ns.error();
|
||||
}
|
||||
// ... and link to other namespaces to allow access to some public libraries
|
||||
bool is_bridged = app_ns->IsBridged();
|
||||
|
||||
auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged);
|
||||
if (!platform_ns) {
|
||||
return platform_ns.error();
|
||||
}
|
||||
|
||||
auto linked = app_ns->Link(*platform_ns, system_exposed_libraries);
|
||||
if (!linked) {
|
||||
return linked.error();
|
||||
}
|
||||
|
||||
auto art_ns = NativeLoaderNamespace::GetExportedNamespace(kArtNamespaceName, is_bridged);
|
||||
// ART APEX does not exist on host, and under certain build conditions.
|
||||
if (art_ns) {
|
||||
linked = app_ns->Link(*art_ns, art_public_libraries());
|
||||
if (!linked) {
|
||||
return linked.error();
|
||||
}
|
||||
}
|
||||
|
||||
// Give access to NNAPI libraries (apex-updated LLNDK library).
|
||||
auto nnapi_ns =
|
||||
NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged);
|
||||
if (nnapi_ns) {
|
||||
linked = app_ns->Link(*nnapi_ns, neuralnetworks_public_libraries());
|
||||
if (!linked) {
|
||||
return linked.error();
|
||||
}
|
||||
}
|
||||
|
||||
// Give access to VNDK-SP libraries from the 'vndk' namespace.
|
||||
if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) {
|
||||
auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
|
||||
if (vndk_ns) {
|
||||
linked = app_ns->Link(*vndk_ns, vndksp_libraries());
|
||||
if (!linked) {
|
||||
return linked.error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!vendor_public_libraries().empty()) {
|
||||
auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged);
|
||||
// when vendor_ns is not configured, link to the platform namespace
|
||||
auto target_ns = vendor_ns ? vendor_ns : platform_ns;
|
||||
if (target_ns) {
|
||||
linked = app_ns->Link(*target_ns, vendor_public_libraries());
|
||||
if (!linked) {
|
||||
return linked.error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
|
||||
if (is_main_classloader) {
|
||||
app_main_namespace_ = &(*app_ns);
|
||||
}
|
||||
|
||||
return &(namespaces_.back().second);
|
||||
}
|
||||
|
||||
NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env,
|
||||
jobject class_loader) {
|
||||
auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
|
||||
[&](const std::pair<jweak, NativeLoaderNamespace>& value) {
|
||||
return env->IsSameObject(value.first, class_loader);
|
||||
});
|
||||
if (it != namespaces_.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
|
||||
jobject class_loader) {
|
||||
jobject parent_class_loader = GetParentClassLoader(env, class_loader);
|
||||
|
||||
while (parent_class_loader != nullptr) {
|
||||
NativeLoaderNamespace* ns;
|
||||
if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
|
||||
return ns;
|
||||
}
|
||||
|
||||
parent_class_loader = GetParentClassLoader(env, parent_class_loader);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace android::nativeloader
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
#if !defined(__ANDROID__)
|
||||
#error "Not available for host"
|
||||
#endif
|
||||
|
||||
#define LOG_TAG "nativeloader"
|
||||
|
||||
#include "native_loader_namespace.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/result.h>
|
||||
#include <jni.h>
|
||||
|
||||
namespace android::nativeloader {
|
||||
|
||||
using android::base::Result;
|
||||
|
||||
// LibraryNamespaces is a singleton object that manages NativeLoaderNamespace
|
||||
// objects for an app process. Its main job is to create (and configure) a new
|
||||
// NativeLoaderNamespace object for a Java ClassLoader, and to find an existing
|
||||
// object for a given ClassLoader.
|
||||
class LibraryNamespaces {
|
||||
public:
|
||||
LibraryNamespaces() : initialized_(false), app_main_namespace_(nullptr) {}
|
||||
|
||||
LibraryNamespaces(LibraryNamespaces&&) = default;
|
||||
LibraryNamespaces(const LibraryNamespaces&) = delete;
|
||||
LibraryNamespaces& operator=(const LibraryNamespaces&) = delete;
|
||||
|
||||
void Initialize();
|
||||
void Reset() {
|
||||
namespaces_.clear();
|
||||
initialized_ = false;
|
||||
app_main_namespace_ = nullptr;
|
||||
}
|
||||
Result<NativeLoaderNamespace*> Create(JNIEnv* env, uint32_t target_sdk_version,
|
||||
jobject class_loader, bool is_shared, jstring dex_path,
|
||||
jstring java_library_path, jstring java_permitted_path);
|
||||
NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
|
||||
|
||||
private:
|
||||
Result<void> InitPublicNamespace(const char* library_path);
|
||||
NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
|
||||
|
||||
bool initialized_;
|
||||
NativeLoaderNamespace* app_main_namespace_;
|
||||
std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
|
||||
};
|
||||
|
||||
} // namespace android::nativeloader
|
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "nativeloader"
|
||||
|
||||
#include "nativeloader/native_loader.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/macros.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <nativebridge/native_bridge.h>
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <log/log.h>
|
||||
#include "library_namespaces.h"
|
||||
#include "nativeloader/dlext_namespaces.h"
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace {
|
||||
#if defined(__ANDROID__)
|
||||
using android::nativeloader::LibraryNamespaces;
|
||||
|
||||
constexpr const char* kApexPath = "/apex/";
|
||||
|
||||
std::mutex g_namespaces_mutex;
|
||||
LibraryNamespaces* g_namespaces = new LibraryNamespaces;
|
||||
|
||||
android_namespace_t* FindExportedNamespace(const char* caller_location) {
|
||||
std::string location = caller_location;
|
||||
// Lots of implicit assumptions here: we expect `caller_location` to be of the form:
|
||||
// /apex/com.android...modulename/...
|
||||
//
|
||||
// And we extract from it 'modulename', which is the name of the linker namespace.
|
||||
if (android::base::StartsWith(location, kApexPath)) {
|
||||
size_t slash_index = location.find_first_of('/', strlen(kApexPath));
|
||||
LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
|
||||
"Error finding namespace of apex: no slash in path %s", caller_location);
|
||||
size_t dot_index = location.find_last_of('.', slash_index);
|
||||
LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
|
||||
"Error finding namespace of apex: no dot in apex name %s", caller_location);
|
||||
std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
|
||||
android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
|
||||
LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
|
||||
"Error finding namespace of apex: no namespace called %s", name.c_str());
|
||||
return boot_namespace;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
#endif // #if defined(__ANDROID__)
|
||||
} // namespace
|
||||
|
||||
void InitializeNativeLoader() {
|
||||
#if defined(__ANDROID__)
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
g_namespaces->Initialize();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ResetNativeLoader() {
|
||||
#if defined(__ANDROID__)
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
g_namespaces->Reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
|
||||
bool is_shared, jstring dex_path, jstring library_path,
|
||||
jstring permitted_path) {
|
||||
#if defined(__ANDROID__)
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
auto ns = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
|
||||
library_path, permitted_path);
|
||||
if (!ns) {
|
||||
return env->NewStringUTF(ns.error().message().c_str());
|
||||
}
|
||||
#else
|
||||
UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path);
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
|
||||
jobject class_loader, const char* caller_location, jstring library_path,
|
||||
bool* needs_native_bridge, char** error_msg) {
|
||||
#if defined(__ANDROID__)
|
||||
UNUSED(target_sdk_version);
|
||||
if (class_loader == nullptr) {
|
||||
*needs_native_bridge = false;
|
||||
if (caller_location != nullptr) {
|
||||
android_namespace_t* boot_namespace = FindExportedNamespace(caller_location);
|
||||
if (boot_namespace != nullptr) {
|
||||
const android_dlextinfo dlextinfo = {
|
||||
.flags = ANDROID_DLEXT_USE_NAMESPACE,
|
||||
.library_namespace = boot_namespace,
|
||||
};
|
||||
void* handle = android_dlopen_ext(path, RTLD_NOW, &dlextinfo);
|
||||
if (handle == nullptr) {
|
||||
*error_msg = strdup(dlerror());
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
void* handle = dlopen(path, RTLD_NOW);
|
||||
if (handle == nullptr) {
|
||||
*error_msg = strdup(dlerror());
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
NativeLoaderNamespace* ns;
|
||||
|
||||
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.
|
||||
Result<NativeLoaderNamespace*> isolated_ns =
|
||||
g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr,
|
||||
library_path, nullptr);
|
||||
if (!isolated_ns) {
|
||||
*error_msg = strdup(isolated_ns.error().message().c_str());
|
||||
return nullptr;
|
||||
} else {
|
||||
ns = *isolated_ns;
|
||||
}
|
||||
}
|
||||
|
||||
return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);
|
||||
#else
|
||||
UNUSED(env, target_sdk_version, class_loader, caller_location);
|
||||
|
||||
// Do some best effort to emulate library-path support. It will not
|
||||
// work for dependencies.
|
||||
//
|
||||
// Note: null has a special meaning and must be preserved.
|
||||
std::string c_library_path; // Empty string by default.
|
||||
if (library_path != nullptr && path != nullptr && path[0] != '/') {
|
||||
ScopedUtfChars library_path_utf_chars(env, library_path);
|
||||
c_library_path = library_path_utf_chars.c_str();
|
||||
}
|
||||
|
||||
std::vector<std::string> library_paths = base::Split(c_library_path, ":");
|
||||
|
||||
for (const std::string& lib_path : library_paths) {
|
||||
*needs_native_bridge = false;
|
||||
const char* path_arg;
|
||||
std::string complete_path;
|
||||
if (path == nullptr) {
|
||||
// Preserve null.
|
||||
path_arg = nullptr;
|
||||
} else {
|
||||
complete_path = lib_path;
|
||||
if (!complete_path.empty()) {
|
||||
complete_path.append("/");
|
||||
}
|
||||
complete_path.append(path);
|
||||
path_arg = complete_path.c_str();
|
||||
}
|
||||
void* handle = dlopen(path_arg, RTLD_NOW);
|
||||
if (handle != nullptr) {
|
||||
return handle;
|
||||
}
|
||||
if (NativeBridgeIsSupported(path_arg)) {
|
||||
*needs_native_bridge = true;
|
||||
handle = NativeBridgeLoadLibrary(path_arg, RTLD_NOW);
|
||||
if (handle != nullptr) {
|
||||
return handle;
|
||||
}
|
||||
*error_msg = strdup(NativeBridgeGetError());
|
||||
} else {
|
||||
*error_msg = strdup(dlerror());
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
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 = strdup(NativeBridgeGetError());
|
||||
}
|
||||
} else {
|
||||
success = (dlclose(handle) == 0);
|
||||
if (!success) {
|
||||
*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* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
|
||||
bool* needs_native_bridge, char** error_msg) {
|
||||
auto handle = ns->Load(path);
|
||||
if (!handle && error_msg != nullptr) {
|
||||
*error_msg = strdup(handle.error().message().c_str());
|
||||
}
|
||||
if (needs_native_bridge != nullptr) {
|
||||
*needs_native_bridge = ns->IsBridged();
|
||||
}
|
||||
return handle ? *handle : nullptr;
|
||||
}
|
||||
|
||||
// native_bridge_namespaces are not supported for callers of this function.
|
||||
// This function will return nullptr in the case when application is running
|
||||
// on native bridge.
|
||||
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
|
||||
if (ns != nullptr && !ns->IsBridged()) {
|
||||
return ns->ToRawAndroidNamespace();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
|
||||
}
|
||||
#endif
|
||||
|
||||
}; // namespace android
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "nativeloader/native_loader.h"
|
||||
#define LOG_TAG "nativeloader"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <log/log.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace {
|
||||
|
||||
void* GetLibHandle() {
|
||||
static void* handle = dlopen("libnativeloader.so", RTLD_NOW);
|
||||
LOG_FATAL_IF(handle == nullptr, "Failed to load libnativeloader.so: %s", dlerror());
|
||||
return handle;
|
||||
}
|
||||
|
||||
template <typename FuncPtr>
|
||||
FuncPtr GetFuncPtr(const char* function_name) {
|
||||
auto f = reinterpret_cast<FuncPtr>(dlsym(GetLibHandle(), function_name));
|
||||
LOG_FATAL_IF(f == nullptr, "Failed to get address of %s: %s", function_name, dlerror());
|
||||
return f;
|
||||
}
|
||||
|
||||
#define GET_FUNC_PTR(name) GetFuncPtr<decltype(&name)>(#name)
|
||||
|
||||
} // namespace
|
||||
|
||||
void InitializeNativeLoader() {
|
||||
static auto f = GET_FUNC_PTR(InitializeNativeLoader);
|
||||
return f();
|
||||
}
|
||||
|
||||
jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader,
|
||||
bool is_shared, jstring dex_path, jstring library_path,
|
||||
jstring permitted_path) {
|
||||
static auto f = GET_FUNC_PTR(CreateClassLoaderNamespace);
|
||||
return f(env, target_sdk_version, class_loader, is_shared, dex_path, library_path,
|
||||
permitted_path);
|
||||
}
|
||||
|
||||
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
|
||||
jobject class_loader, const char* caller_location, jstring library_path,
|
||||
bool* needs_native_bridge, char** error_msg) {
|
||||
static auto f = GET_FUNC_PTR(OpenNativeLibrary);
|
||||
return f(env, target_sdk_version, path, class_loader, caller_location, library_path,
|
||||
needs_native_bridge, error_msg);
|
||||
}
|
||||
|
||||
bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
|
||||
static auto f = GET_FUNC_PTR(CloseNativeLibrary);
|
||||
return f(handle, needs_native_bridge, error_msg);
|
||||
}
|
||||
|
||||
void NativeLoaderFreeErrorMessage(char* msg) {
|
||||
static auto f = GET_FUNC_PTR(NativeLoaderFreeErrorMessage);
|
||||
return f(msg);
|
||||
}
|
||||
|
||||
struct android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
static auto f = GET_FUNC_PTR(FindNamespaceByClassLoader);
|
||||
return f(env, class_loader);
|
||||
}
|
||||
|
||||
struct NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env,
|
||||
jobject class_loader) {
|
||||
static auto f = GET_FUNC_PTR(FindNativeLoaderNamespaceByClassLoader);
|
||||
return f(env, class_loader);
|
||||
}
|
||||
|
||||
void* OpenNativeLibraryInNamespace(struct NativeLoaderNamespace* ns, const char* path,
|
||||
bool* needs_native_bridge, char** error_msg) {
|
||||
static auto f = GET_FUNC_PTR(OpenNativeLibraryInNamespace);
|
||||
return f(ns, path, needs_native_bridge, error_msg);
|
||||
}
|
||||
|
||||
void ResetNativeLoader() {
|
||||
static auto f = GET_FUNC_PTR(ResetNativeLoader);
|
||||
return f();
|
||||
}
|
||||
|
||||
#undef GET_FUNC_PTR
|
||||
|
||||
} // namespace android
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "nativeloader"
|
||||
|
||||
#include "native_loader_namespace.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
#include <log/log.h>
|
||||
#include <nativebridge/native_bridge.h>
|
||||
|
||||
#include "nativeloader/dlext_namespaces.h"
|
||||
|
||||
using android::base::Error;
|
||||
using android::base::Errorf;
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kDefaultNamespaceName = "default";
|
||||
constexpr const char* kPlatformNamespaceName = "platform";
|
||||
|
||||
std::string GetLinkerError(bool is_bridged) {
|
||||
const char* msg = is_bridged ? NativeBridgeGetError() : dlerror();
|
||||
if (msg == nullptr) {
|
||||
return "no error";
|
||||
}
|
||||
return std::string(msg);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result<NativeLoaderNamespace> NativeLoaderNamespace::GetExportedNamespace(const std::string& name,
|
||||
bool is_bridged) {
|
||||
if (!is_bridged) {
|
||||
auto raw = android_get_exported_namespace(name.c_str());
|
||||
if (raw != nullptr) {
|
||||
return NativeLoaderNamespace(name, raw);
|
||||
}
|
||||
} else {
|
||||
auto raw = NativeBridgeGetExportedNamespace(name.c_str());
|
||||
if (raw != nullptr) {
|
||||
return NativeLoaderNamespace(name, raw);
|
||||
}
|
||||
}
|
||||
return Errorf("namespace {} does not exist or exported", name);
|
||||
}
|
||||
|
||||
// The platform namespace is called "default" for binaries in /system and
|
||||
// "platform" for those in the Runtime APEX. Try "platform" first since
|
||||
// "default" always exists.
|
||||
Result<NativeLoaderNamespace> NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) {
|
||||
auto ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged);
|
||||
if (ns) return ns;
|
||||
ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged);
|
||||
if (ns) return ns;
|
||||
|
||||
// If nothing is found, return NativeLoaderNamespace constructed from nullptr.
|
||||
// nullptr also means default namespace to the linker.
|
||||
if (!is_bridged) {
|
||||
return NativeLoaderNamespace(kDefaultNamespaceName, static_cast<android_namespace_t*>(nullptr));
|
||||
} else {
|
||||
return NativeLoaderNamespace(kDefaultNamespaceName,
|
||||
static_cast<native_bridge_namespace_t*>(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
Result<NativeLoaderNamespace> NativeLoaderNamespace::Create(
|
||||
const std::string& name, const std::string& search_paths, const std::string& permitted_paths,
|
||||
const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled,
|
||||
bool also_used_as_anonymous) {
|
||||
bool is_bridged = false;
|
||||
if (parent != nullptr) {
|
||||
is_bridged = parent->IsBridged();
|
||||
} else if (!search_paths.empty()) {
|
||||
is_bridged = NativeBridgeIsPathSupported(search_paths.c_str());
|
||||
}
|
||||
|
||||
// Fall back to the platform namespace if no parent is set.
|
||||
auto platform_ns = GetPlatformNamespace(is_bridged);
|
||||
if (!platform_ns) {
|
||||
return platform_ns.error();
|
||||
}
|
||||
const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns;
|
||||
|
||||
// All namespaces for apps are isolated
|
||||
uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
|
||||
// The namespace is also used as the anonymous namespace
|
||||
// which is used when the linker fails to determine the caller address
|
||||
if (also_used_as_anonymous) {
|
||||
type |= ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
|
||||
}
|
||||
|
||||
// Bundled apps have access to all system libraries that are currently loaded
|
||||
// in the default namespace
|
||||
if (is_shared) {
|
||||
type |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
}
|
||||
if (is_greylist_enabled) {
|
||||
type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
|
||||
}
|
||||
|
||||
if (!is_bridged) {
|
||||
android_namespace_t* raw =
|
||||
android_create_namespace(name.c_str(), nullptr, search_paths.c_str(), type,
|
||||
permitted_paths.c_str(), effective_parent.ToRawAndroidNamespace());
|
||||
if (raw != nullptr) {
|
||||
return NativeLoaderNamespace(name, raw);
|
||||
}
|
||||
} else {
|
||||
native_bridge_namespace_t* raw = NativeBridgeCreateNamespace(
|
||||
name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(),
|
||||
effective_parent.ToRawNativeBridgeNamespace());
|
||||
if (raw != nullptr) {
|
||||
return NativeLoaderNamespace(name, raw);
|
||||
}
|
||||
}
|
||||
return Errorf("failed to create {} namespace name:{}, search_paths:{}, permitted_paths:{}",
|
||||
is_bridged ? "bridged" : "native", name, search_paths, permitted_paths);
|
||||
}
|
||||
|
||||
Result<void> NativeLoaderNamespace::Link(const NativeLoaderNamespace& target,
|
||||
const std::string& shared_libs) const {
|
||||
LOG_ALWAYS_FATAL_IF(shared_libs.empty(), "empty share lib when linking %s to %s",
|
||||
this->name().c_str(), target.name().c_str());
|
||||
if (!IsBridged()) {
|
||||
if (android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(),
|
||||
shared_libs.c_str())) {
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
if (NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(),
|
||||
target.ToRawNativeBridgeNamespace(), shared_libs.c_str())) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return Error() << GetLinkerError(IsBridged());
|
||||
}
|
||||
|
||||
Result<void*> NativeLoaderNamespace::Load(const char* lib_name) const {
|
||||
if (!IsBridged()) {
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = this->ToRawAndroidNamespace();
|
||||
void* handle = android_dlopen_ext(lib_name, RTLD_NOW, &extinfo);
|
||||
if (handle != nullptr) {
|
||||
return handle;
|
||||
}
|
||||
} else {
|
||||
void* handle =
|
||||
NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace());
|
||||
if (handle != nullptr) {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
return Error() << GetLinkerError(IsBridged());
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/result.h>
|
||||
#include <android/dlext.h>
|
||||
#include <log/log.h>
|
||||
#include <nativebridge/native_bridge.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
using android::base::Result;
|
||||
|
||||
// NativeLoaderNamespace abstracts a linker namespace for the native
|
||||
// architecture (ex: arm on arm) or the translated architecture (ex: arm on
|
||||
// x86). Instances of this class are managed by LibraryNamespaces object.
|
||||
struct NativeLoaderNamespace {
|
||||
public:
|
||||
static Result<NativeLoaderNamespace> Create(const std::string& name,
|
||||
const std::string& search_paths,
|
||||
const std::string& permitted_paths,
|
||||
const NativeLoaderNamespace* parent, bool is_shared,
|
||||
bool is_greylist_enabled,
|
||||
bool also_used_as_anonymous);
|
||||
|
||||
NativeLoaderNamespace(NativeLoaderNamespace&&) = default;
|
||||
NativeLoaderNamespace(const NativeLoaderNamespace&) = default;
|
||||
NativeLoaderNamespace& operator=(const NativeLoaderNamespace&) = default;
|
||||
|
||||
android_namespace_t* ToRawAndroidNamespace() const { return std::get<0>(raw_); }
|
||||
native_bridge_namespace_t* ToRawNativeBridgeNamespace() const { return std::get<1>(raw_); }
|
||||
|
||||
std::string name() const { return name_; }
|
||||
bool IsBridged() const { return raw_.index() == 1; }
|
||||
|
||||
Result<void> Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const;
|
||||
Result<void*> Load(const char* lib_name) const;
|
||||
|
||||
static Result<NativeLoaderNamespace> GetExportedNamespace(const std::string& name,
|
||||
bool is_bridged);
|
||||
static Result<NativeLoaderNamespace> GetPlatformNamespace(bool is_bridged);
|
||||
|
||||
private:
|
||||
explicit NativeLoaderNamespace(const std::string& name, android_namespace_t* ns)
|
||||
: name_(name), raw_(ns) {}
|
||||
explicit NativeLoaderNamespace(const std::string& name, native_bridge_namespace_t* ns)
|
||||
: name_(name), raw_(ns) {}
|
||||
|
||||
std::string name_;
|
||||
std::variant<android_namespace_t*, native_bridge_namespace_t*> raw_;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
#endif // #if defined(__ANDROID__)
|
|
@ -1,663 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include "native_loader_namespace.h"
|
||||
#include "nativeloader/dlext_namespaces.h"
|
||||
#include "nativeloader/native_loader.h"
|
||||
#include "public_libraries.h"
|
||||
|
||||
using namespace ::testing;
|
||||
using namespace ::android::nativeloader::internal;
|
||||
|
||||
namespace android {
|
||||
namespace nativeloader {
|
||||
|
||||
// gmock interface that represents interested platform APIs on libdl and libnativebridge
|
||||
class Platform {
|
||||
public:
|
||||
virtual ~Platform() {}
|
||||
|
||||
// libdl APIs
|
||||
virtual void* dlopen(const char* filename, int flags) = 0;
|
||||
virtual int dlclose(void* handle) = 0;
|
||||
virtual char* dlerror(void) = 0;
|
||||
|
||||
// These mock_* are the APIs semantically the same across libdl and libnativebridge.
|
||||
// Instead of having two set of mock APIs for the two, define only one set with an additional
|
||||
// argument 'bool bridged' to identify the context (i.e., called for libdl or libnativebridge).
|
||||
typedef char* mock_namespace_handle;
|
||||
virtual bool mock_init_anonymous_namespace(bool bridged, const char* sonames,
|
||||
const char* search_paths) = 0;
|
||||
virtual mock_namespace_handle mock_create_namespace(
|
||||
bool bridged, const char* name, const char* ld_library_path, const char* default_library_path,
|
||||
uint64_t type, const char* permitted_when_isolated_path, mock_namespace_handle parent) = 0;
|
||||
virtual bool mock_link_namespaces(bool bridged, mock_namespace_handle from,
|
||||
mock_namespace_handle to, const char* sonames) = 0;
|
||||
virtual mock_namespace_handle mock_get_exported_namespace(bool bridged, const char* name) = 0;
|
||||
virtual void* mock_dlopen_ext(bool bridged, const char* filename, int flags,
|
||||
mock_namespace_handle ns) = 0;
|
||||
|
||||
// libnativebridge APIs for which libdl has no corresponding APIs
|
||||
virtual bool NativeBridgeInitialized() = 0;
|
||||
virtual const char* NativeBridgeGetError() = 0;
|
||||
virtual bool NativeBridgeIsPathSupported(const char*) = 0;
|
||||
virtual bool NativeBridgeIsSupported(const char*) = 0;
|
||||
|
||||
// To mock "ClassLoader Object.getParent()"
|
||||
virtual const char* JniObject_getParent(const char*) = 0;
|
||||
};
|
||||
|
||||
// The mock does not actually create a namespace object. But simply casts the pointer to the
|
||||
// string for the namespace name as the handle to the namespace object.
|
||||
#define TO_ANDROID_NAMESPACE(str) \
|
||||
reinterpret_cast<struct android_namespace_t*>(const_cast<char*>(str))
|
||||
|
||||
#define TO_BRIDGED_NAMESPACE(str) \
|
||||
reinterpret_cast<struct native_bridge_namespace_t*>(const_cast<char*>(str))
|
||||
|
||||
#define TO_MOCK_NAMESPACE(ns) reinterpret_cast<Platform::mock_namespace_handle>(ns)
|
||||
|
||||
// These represents built-in namespaces created by the linker according to ld.config.txt
|
||||
static std::unordered_map<std::string, Platform::mock_namespace_handle> namespaces = {
|
||||
{"platform", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("platform"))},
|
||||
{"default", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("default"))},
|
||||
{"art", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("art"))},
|
||||
{"sphal", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("sphal"))},
|
||||
{"vndk", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("vndk"))},
|
||||
{"neuralnetworks", TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("neuralnetworks"))},
|
||||
};
|
||||
|
||||
// The actual gmock object
|
||||
class MockPlatform : public Platform {
|
||||
public:
|
||||
explicit MockPlatform(bool is_bridged) : is_bridged_(is_bridged) {
|
||||
ON_CALL(*this, NativeBridgeIsSupported(_)).WillByDefault(Return(is_bridged_));
|
||||
ON_CALL(*this, NativeBridgeIsPathSupported(_)).WillByDefault(Return(is_bridged_));
|
||||
ON_CALL(*this, mock_get_exported_namespace(_, _))
|
||||
.WillByDefault(Invoke([](bool, const char* name) -> mock_namespace_handle {
|
||||
if (namespaces.find(name) != namespaces.end()) {
|
||||
return namespaces[name];
|
||||
}
|
||||
return TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE("(namespace not found"));
|
||||
}));
|
||||
}
|
||||
|
||||
// Mocking libdl APIs
|
||||
MOCK_METHOD2(dlopen, void*(const char*, int));
|
||||
MOCK_METHOD1(dlclose, int(void*));
|
||||
MOCK_METHOD0(dlerror, char*());
|
||||
|
||||
// Mocking the common APIs
|
||||
MOCK_METHOD3(mock_init_anonymous_namespace, bool(bool, const char*, const char*));
|
||||
MOCK_METHOD7(mock_create_namespace,
|
||||
mock_namespace_handle(bool, const char*, const char*, const char*, uint64_t,
|
||||
const char*, mock_namespace_handle));
|
||||
MOCK_METHOD4(mock_link_namespaces,
|
||||
bool(bool, mock_namespace_handle, mock_namespace_handle, const char*));
|
||||
MOCK_METHOD2(mock_get_exported_namespace, mock_namespace_handle(bool, const char*));
|
||||
MOCK_METHOD4(mock_dlopen_ext, void*(bool, const char*, int, mock_namespace_handle));
|
||||
|
||||
// Mocking libnativebridge APIs
|
||||
MOCK_METHOD0(NativeBridgeInitialized, bool());
|
||||
MOCK_METHOD0(NativeBridgeGetError, const char*());
|
||||
MOCK_METHOD1(NativeBridgeIsPathSupported, bool(const char*));
|
||||
MOCK_METHOD1(NativeBridgeIsSupported, bool(const char*));
|
||||
|
||||
// Mocking "ClassLoader Object.getParent()"
|
||||
MOCK_METHOD1(JniObject_getParent, const char*(const char*));
|
||||
|
||||
private:
|
||||
bool is_bridged_;
|
||||
};
|
||||
|
||||
static std::unique_ptr<MockPlatform> mock;
|
||||
|
||||
// Provide C wrappers for the mock object.
|
||||
extern "C" {
|
||||
void* dlopen(const char* file, int flag) {
|
||||
return mock->dlopen(file, flag);
|
||||
}
|
||||
|
||||
int dlclose(void* handle) {
|
||||
return mock->dlclose(handle);
|
||||
}
|
||||
|
||||
char* dlerror(void) {
|
||||
return mock->dlerror();
|
||||
}
|
||||
|
||||
bool android_init_anonymous_namespace(const char* sonames, const char* search_path) {
|
||||
return mock->mock_init_anonymous_namespace(false, sonames, search_path);
|
||||
}
|
||||
|
||||
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) {
|
||||
return TO_ANDROID_NAMESPACE(
|
||||
mock->mock_create_namespace(false, name, ld_library_path, default_library_path, type,
|
||||
permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
|
||||
}
|
||||
|
||||
bool android_link_namespaces(struct android_namespace_t* from, struct android_namespace_t* to,
|
||||
const char* sonames) {
|
||||
return mock->mock_link_namespaces(false, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
|
||||
}
|
||||
|
||||
struct android_namespace_t* android_get_exported_namespace(const char* name) {
|
||||
return TO_ANDROID_NAMESPACE(mock->mock_get_exported_namespace(false, name));
|
||||
}
|
||||
|
||||
void* android_dlopen_ext(const char* filename, int flags, const android_dlextinfo* info) {
|
||||
return mock->mock_dlopen_ext(false, filename, flags, TO_MOCK_NAMESPACE(info->library_namespace));
|
||||
}
|
||||
|
||||
// libnativebridge APIs
|
||||
bool NativeBridgeIsSupported(const char* libpath) {
|
||||
return mock->NativeBridgeIsSupported(libpath);
|
||||
}
|
||||
|
||||
struct native_bridge_namespace_t* NativeBridgeGetExportedNamespace(const char* name) {
|
||||
return TO_BRIDGED_NAMESPACE(mock->mock_get_exported_namespace(true, name));
|
||||
}
|
||||
|
||||
struct native_bridge_namespace_t* 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) {
|
||||
return TO_BRIDGED_NAMESPACE(
|
||||
mock->mock_create_namespace(true, name, ld_library_path, default_library_path, type,
|
||||
permitted_when_isolated_path, TO_MOCK_NAMESPACE(parent)));
|
||||
}
|
||||
|
||||
bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
|
||||
struct native_bridge_namespace_t* to, const char* sonames) {
|
||||
return mock->mock_link_namespaces(true, TO_MOCK_NAMESPACE(from), TO_MOCK_NAMESPACE(to), sonames);
|
||||
}
|
||||
|
||||
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
|
||||
struct native_bridge_namespace_t* ns) {
|
||||
return mock->mock_dlopen_ext(true, libpath, flag, TO_MOCK_NAMESPACE(ns));
|
||||
}
|
||||
|
||||
bool NativeBridgeInitialized() {
|
||||
return mock->NativeBridgeInitialized();
|
||||
}
|
||||
|
||||
bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
|
||||
const char* anon_ns_library_path) {
|
||||
return mock->mock_init_anonymous_namespace(true, public_ns_sonames, anon_ns_library_path);
|
||||
}
|
||||
|
||||
const char* NativeBridgeGetError() {
|
||||
return mock->NativeBridgeGetError();
|
||||
}
|
||||
|
||||
bool NativeBridgeIsPathSupported(const char* path) {
|
||||
return mock->NativeBridgeIsPathSupported(path);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// A very simple JNI mock.
|
||||
// jstring is a pointer to utf8 char array. We don't need utf16 char here.
|
||||
// jobject, jclass, and jmethodID are also a pointer to utf8 char array
|
||||
// Only a few JNI methods that are actually used in libnativeloader are mocked.
|
||||
JNINativeInterface* CreateJNINativeInterface() {
|
||||
JNINativeInterface* inf = new JNINativeInterface();
|
||||
memset(inf, 0, sizeof(JNINativeInterface));
|
||||
|
||||
inf->GetStringUTFChars = [](JNIEnv*, jstring s, jboolean*) -> const char* {
|
||||
return reinterpret_cast<const char*>(s);
|
||||
};
|
||||
|
||||
inf->ReleaseStringUTFChars = [](JNIEnv*, jstring, const char*) -> void { return; };
|
||||
|
||||
inf->NewStringUTF = [](JNIEnv*, const char* bytes) -> jstring {
|
||||
return reinterpret_cast<jstring>(const_cast<char*>(bytes));
|
||||
};
|
||||
|
||||
inf->FindClass = [](JNIEnv*, const char* name) -> jclass {
|
||||
return reinterpret_cast<jclass>(const_cast<char*>(name));
|
||||
};
|
||||
|
||||
inf->CallObjectMethodV = [](JNIEnv*, jobject obj, jmethodID mid, va_list) -> jobject {
|
||||
if (strcmp("getParent", reinterpret_cast<const char*>(mid)) == 0) {
|
||||
// JniObject_getParent can be a valid jobject or nullptr if there is
|
||||
// no parent classloader.
|
||||
const char* ret = mock->JniObject_getParent(reinterpret_cast<const char*>(obj));
|
||||
return reinterpret_cast<jobject>(const_cast<char*>(ret));
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
inf->GetMethodID = [](JNIEnv*, jclass, const char* name, const char*) -> jmethodID {
|
||||
return reinterpret_cast<jmethodID>(const_cast<char*>(name));
|
||||
};
|
||||
|
||||
inf->NewWeakGlobalRef = [](JNIEnv*, jobject obj) -> jobject { return obj; };
|
||||
|
||||
inf->IsSameObject = [](JNIEnv*, jobject a, jobject b) -> jboolean {
|
||||
return strcmp(reinterpret_cast<const char*>(a), reinterpret_cast<const char*>(b)) == 0;
|
||||
};
|
||||
|
||||
return inf;
|
||||
}
|
||||
|
||||
static void* const any_nonnull = reinterpret_cast<void*>(0x12345678);
|
||||
|
||||
// Custom matcher for comparing namespace handles
|
||||
MATCHER_P(NsEq, other, "") {
|
||||
*result_listener << "comparing " << reinterpret_cast<const char*>(arg) << " and " << other;
|
||||
return strcmp(reinterpret_cast<const char*>(arg), reinterpret_cast<const char*>(other)) == 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// Test fixture
|
||||
class NativeLoaderTest : public ::testing::TestWithParam<bool> {
|
||||
protected:
|
||||
bool IsBridged() { return GetParam(); }
|
||||
|
||||
void SetUp() override {
|
||||
mock = std::make_unique<NiceMock<MockPlatform>>(IsBridged());
|
||||
|
||||
env = std::make_unique<JNIEnv>();
|
||||
env->functions = CreateJNINativeInterface();
|
||||
}
|
||||
|
||||
void SetExpectations() {
|
||||
std::vector<std::string> default_public_libs =
|
||||
android::base::Split(preloadable_public_libraries(), ":");
|
||||
for (auto l : default_public_libs) {
|
||||
EXPECT_CALL(*mock, dlopen(StrEq(l.c_str()), RTLD_NOW | RTLD_NODELETE))
|
||||
.WillOnce(Return(any_nonnull));
|
||||
}
|
||||
}
|
||||
|
||||
void RunTest() { InitializeNativeLoader(); }
|
||||
|
||||
void TearDown() override {
|
||||
ResetNativeLoader();
|
||||
delete env->functions;
|
||||
mock.reset();
|
||||
}
|
||||
|
||||
std::unique_ptr<JNIEnv> env;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST_P(NativeLoaderTest, InitializeLoadsDefaultPublicLibraries) {
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(NativeLoaderTests, NativeLoaderTest, testing::Bool());
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
class NativeLoaderTest_Create : public NativeLoaderTest {
|
||||
protected:
|
||||
// Test inputs (initialized to the default values). Overriding these
|
||||
// must be done before calling SetExpectations() and RunTest().
|
||||
uint32_t target_sdk_version = 29;
|
||||
std::string class_loader = "my_classloader";
|
||||
bool is_shared = false;
|
||||
std::string dex_path = "/data/app/foo/classes.dex";
|
||||
std::string library_path = "/data/app/foo/lib/arm";
|
||||
std::string permitted_path = "/data/app/foo/lib";
|
||||
|
||||
// expected output (.. for the default test inputs)
|
||||
std::string expected_namespace_name = "classloader-namespace";
|
||||
uint64_t expected_namespace_flags =
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS;
|
||||
std::string expected_library_path = library_path;
|
||||
std::string expected_permitted_path = std::string("/data:/mnt/expand:") + permitted_path;
|
||||
std::string expected_parent_namespace = "platform";
|
||||
bool expected_link_with_platform_ns = true;
|
||||
bool expected_link_with_art_ns = true;
|
||||
bool expected_link_with_sphal_ns = !vendor_public_libraries().empty();
|
||||
bool expected_link_with_vndk_ns = false;
|
||||
bool expected_link_with_default_ns = false;
|
||||
bool expected_link_with_neuralnetworks_ns = true;
|
||||
std::string expected_shared_libs_to_platform_ns = default_public_libraries();
|
||||
std::string expected_shared_libs_to_art_ns = art_public_libraries();
|
||||
std::string expected_shared_libs_to_sphal_ns = vendor_public_libraries();
|
||||
std::string expected_shared_libs_to_vndk_ns = vndksp_libraries();
|
||||
std::string expected_shared_libs_to_default_ns = default_public_libraries();
|
||||
std::string expected_shared_libs_to_neuralnetworks_ns = neuralnetworks_public_libraries();
|
||||
|
||||
void SetExpectations() {
|
||||
NativeLoaderTest::SetExpectations();
|
||||
|
||||
ON_CALL(*mock, JniObject_getParent(StrEq(class_loader))).WillByDefault(Return(nullptr));
|
||||
|
||||
EXPECT_CALL(*mock, NativeBridgeIsPathSupported(_)).Times(AnyNumber());
|
||||
EXPECT_CALL(*mock, NativeBridgeInitialized()).Times(AnyNumber());
|
||||
|
||||
EXPECT_CALL(*mock, mock_create_namespace(
|
||||
Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
|
||||
StrEq(expected_library_path), expected_namespace_flags,
|
||||
StrEq(expected_permitted_path), NsEq(expected_parent_namespace.c_str())))
|
||||
.WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(dex_path.c_str()))));
|
||||
if (expected_link_with_platform_ns) {
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("platform"),
|
||||
StrEq(expected_shared_libs_to_platform_ns)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
if (expected_link_with_art_ns) {
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("art"),
|
||||
StrEq(expected_shared_libs_to_art_ns)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
if (expected_link_with_sphal_ns) {
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("sphal"),
|
||||
StrEq(expected_shared_libs_to_sphal_ns)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
if (expected_link_with_vndk_ns) {
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("vndk"),
|
||||
StrEq(expected_shared_libs_to_vndk_ns)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
if (expected_link_with_default_ns) {
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("default"),
|
||||
StrEq(expected_shared_libs_to_default_ns)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
if (expected_link_with_neuralnetworks_ns) {
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), _, NsEq("neuralnetworks"),
|
||||
StrEq(expected_shared_libs_to_neuralnetworks_ns)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
}
|
||||
|
||||
void RunTest() {
|
||||
NativeLoaderTest::RunTest();
|
||||
|
||||
jstring err = CreateClassLoaderNamespace(
|
||||
env(), target_sdk_version, env()->NewStringUTF(class_loader.c_str()), is_shared,
|
||||
env()->NewStringUTF(dex_path.c_str()), env()->NewStringUTF(library_path.c_str()),
|
||||
env()->NewStringUTF(permitted_path.c_str()));
|
||||
|
||||
// no error
|
||||
EXPECT_EQ(err, nullptr);
|
||||
|
||||
if (!IsBridged()) {
|
||||
struct android_namespace_t* ns =
|
||||
FindNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
|
||||
|
||||
// The created namespace is for this apk
|
||||
EXPECT_EQ(dex_path.c_str(), reinterpret_cast<const char*>(ns));
|
||||
} else {
|
||||
struct NativeLoaderNamespace* ns =
|
||||
FindNativeLoaderNamespaceByClassLoader(env(), env()->NewStringUTF(class_loader.c_str()));
|
||||
|
||||
// The created namespace is for the this apk
|
||||
EXPECT_STREQ(dex_path.c_str(),
|
||||
reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* env() { return NativeLoaderTest::env.get(); }
|
||||
};
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, DownloadedApp) {
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, BundledSystemApp) {
|
||||
dex_path = "/system/app/foo/foo.apk";
|
||||
is_shared = true;
|
||||
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, BundledVendorApp) {
|
||||
dex_path = "/vendor/app/foo/foo.apk";
|
||||
is_shared = true;
|
||||
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, UnbundledVendorApp) {
|
||||
dex_path = "/vendor/app/foo/foo.apk";
|
||||
is_shared = false;
|
||||
|
||||
expected_namespace_name = "vendor-classloader-namespace";
|
||||
expected_library_path = expected_library_path + ":/vendor/lib";
|
||||
expected_permitted_path = expected_permitted_path + ":/vendor/lib";
|
||||
expected_shared_libs_to_platform_ns =
|
||||
expected_shared_libs_to_platform_ns + ":" + llndk_libraries();
|
||||
expected_link_with_vndk_ns = true;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, BundledProductApp_pre30) {
|
||||
dex_path = "/product/app/foo/foo.apk";
|
||||
is_shared = true;
|
||||
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, BundledProductApp_post30) {
|
||||
dex_path = "/product/app/foo/foo.apk";
|
||||
is_shared = true;
|
||||
target_sdk_version = 30;
|
||||
|
||||
expected_namespace_flags |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, UnbundledProductApp_pre30) {
|
||||
dex_path = "/product/app/foo/foo.apk";
|
||||
is_shared = false;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, UnbundledProductApp_post30) {
|
||||
dex_path = "/product/app/foo/foo.apk";
|
||||
is_shared = false;
|
||||
target_sdk_version = 30;
|
||||
|
||||
expected_namespace_name = "vendor-classloader-namespace";
|
||||
expected_library_path = expected_library_path + ":/product/lib:/system/product/lib";
|
||||
expected_permitted_path = expected_permitted_path + ":/product/lib:/system/product/lib";
|
||||
expected_shared_libs_to_platform_ns =
|
||||
expected_shared_libs_to_platform_ns + ":" + llndk_libraries();
|
||||
expected_link_with_vndk_ns = true;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, NamespaceForSharedLibIsNotUsedAsAnonymousNamespace) {
|
||||
if (IsBridged()) {
|
||||
// There is no shared lib in translated arch
|
||||
// TODO(jiyong): revisit this
|
||||
return;
|
||||
}
|
||||
// compared to apks, for java shared libs, library_path is empty; java shared
|
||||
// libs don't have their own native libs. They use platform's.
|
||||
library_path = "";
|
||||
expected_library_path = library_path;
|
||||
// no ALSO_USED_AS_ANONYMOUS
|
||||
expected_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
SetExpectations();
|
||||
RunTest();
|
||||
}
|
||||
|
||||
TEST_P(NativeLoaderTest_Create, TwoApks) {
|
||||
SetExpectations();
|
||||
const uint32_t second_app_target_sdk_version = 29;
|
||||
const std::string second_app_class_loader = "second_app_classloader";
|
||||
const bool second_app_is_shared = false;
|
||||
const std::string second_app_dex_path = "/data/app/bar/classes.dex";
|
||||
const std::string second_app_library_path = "/data/app/bar/lib/arm";
|
||||
const std::string second_app_permitted_path = "/data/app/bar/lib";
|
||||
const std::string expected_second_app_permitted_path =
|
||||
std::string("/data:/mnt/expand:") + second_app_permitted_path;
|
||||
const std::string expected_second_app_parent_namespace = "classloader-namespace";
|
||||
// no ALSO_USED_AS_ANONYMOUS
|
||||
const uint64_t expected_second_namespace_flags = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
|
||||
// The scenario is that second app is loaded by the first app.
|
||||
// So the first app's classloader (`classloader`) is parent of the second
|
||||
// app's classloader.
|
||||
ON_CALL(*mock, JniObject_getParent(StrEq(second_app_class_loader)))
|
||||
.WillByDefault(Return(class_loader.c_str()));
|
||||
|
||||
// namespace for the second app is created. Its parent is set to the namespace
|
||||
// of the first app.
|
||||
EXPECT_CALL(*mock, mock_create_namespace(
|
||||
Eq(IsBridged()), StrEq(expected_namespace_name), nullptr,
|
||||
StrEq(second_app_library_path), expected_second_namespace_flags,
|
||||
StrEq(expected_second_app_permitted_path), NsEq(dex_path.c_str())))
|
||||
.WillOnce(Return(TO_MOCK_NAMESPACE(TO_ANDROID_NAMESPACE(second_app_dex_path.c_str()))));
|
||||
EXPECT_CALL(*mock, mock_link_namespaces(Eq(IsBridged()), NsEq(second_app_dex_path.c_str()), _, _))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
RunTest();
|
||||
jstring err = CreateClassLoaderNamespace(
|
||||
env(), second_app_target_sdk_version, env()->NewStringUTF(second_app_class_loader.c_str()),
|
||||
second_app_is_shared, env()->NewStringUTF(second_app_dex_path.c_str()),
|
||||
env()->NewStringUTF(second_app_library_path.c_str()),
|
||||
env()->NewStringUTF(second_app_permitted_path.c_str()));
|
||||
|
||||
// success
|
||||
EXPECT_EQ(err, nullptr);
|
||||
|
||||
if (!IsBridged()) {
|
||||
struct android_namespace_t* ns =
|
||||
FindNamespaceByClassLoader(env(), env()->NewStringUTF(second_app_class_loader.c_str()));
|
||||
|
||||
// The created namespace is for the second apk
|
||||
EXPECT_EQ(second_app_dex_path.c_str(), reinterpret_cast<const char*>(ns));
|
||||
} else {
|
||||
struct NativeLoaderNamespace* ns = FindNativeLoaderNamespaceByClassLoader(
|
||||
env(), env()->NewStringUTF(second_app_class_loader.c_str()));
|
||||
|
||||
// The created namespace is for the second apk
|
||||
EXPECT_STREQ(second_app_dex_path.c_str(),
|
||||
reinterpret_cast<const char*>(ns->ToRawNativeBridgeNamespace()));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(NativeLoaderTests_Create, NativeLoaderTest_Create, testing::Bool());
|
||||
|
||||
const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
|
||||
[](const struct ConfigEntry&) -> Result<bool> { return true; };
|
||||
|
||||
TEST(NativeLoaderConfigParser, NamesAndComments) {
|
||||
const char file_content[] = R"(
|
||||
######
|
||||
|
||||
libA.so
|
||||
#libB.so
|
||||
|
||||
|
||||
libC.so
|
||||
libD.so
|
||||
#### libE.so
|
||||
)";
|
||||
const std::vector<std::string> expected_result = {"libA.so", "libC.so", "libD.so"};
|
||||
Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
|
||||
ASSERT_TRUE(result) << result.error().message();
|
||||
ASSERT_EQ(expected_result, *result);
|
||||
}
|
||||
|
||||
TEST(NativeLoaderConfigParser, WithBitness) {
|
||||
const char file_content[] = R"(
|
||||
libA.so 32
|
||||
libB.so 64
|
||||
libC.so
|
||||
)";
|
||||
#if defined(__LP64__)
|
||||
const std::vector<std::string> expected_result = {"libB.so", "libC.so"};
|
||||
#else
|
||||
const std::vector<std::string> expected_result = {"libA.so", "libC.so"};
|
||||
#endif
|
||||
Result<std::vector<std::string>> result = ParseConfig(file_content, always_true);
|
||||
ASSERT_TRUE(result) << result.error().message();
|
||||
ASSERT_EQ(expected_result, *result);
|
||||
}
|
||||
|
||||
TEST(NativeLoaderConfigParser, WithNoPreload) {
|
||||
const char file_content[] = R"(
|
||||
libA.so nopreload
|
||||
libB.so nopreload
|
||||
libC.so
|
||||
)";
|
||||
|
||||
const std::vector<std::string> expected_result = {"libC.so"};
|
||||
Result<std::vector<std::string>> result =
|
||||
ParseConfig(file_content,
|
||||
[](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
|
||||
ASSERT_TRUE(result) << result.error().message();
|
||||
ASSERT_EQ(expected_result, *result);
|
||||
}
|
||||
|
||||
TEST(NativeLoaderConfigParser, WithNoPreloadAndBitness) {
|
||||
const char file_content[] = R"(
|
||||
libA.so nopreload 32
|
||||
libB.so 64 nopreload
|
||||
libC.so 32
|
||||
libD.so 64
|
||||
libE.so nopreload
|
||||
)";
|
||||
|
||||
#if defined(__LP64__)
|
||||
const std::vector<std::string> expected_result = {"libD.so"};
|
||||
#else
|
||||
const std::vector<std::string> expected_result = {"libC.so"};
|
||||
#endif
|
||||
Result<std::vector<std::string>> result =
|
||||
ParseConfig(file_content,
|
||||
[](const struct ConfigEntry& entry) -> Result<bool> { return !entry.nopreload; });
|
||||
ASSERT_TRUE(result) << result.error().message();
|
||||
ASSERT_EQ(expected_result, *result);
|
||||
}
|
||||
|
||||
TEST(NativeLoaderConfigParser, RejectMalformed) {
|
||||
ASSERT_FALSE(ParseConfig("libA.so 32 64", always_true));
|
||||
ASSERT_FALSE(ParseConfig("libA.so 32 32", always_true));
|
||||
ASSERT_FALSE(ParseConfig("libA.so 32 nopreload 64", always_true));
|
||||
ASSERT_FALSE(ParseConfig("32 libA.so nopreload", always_true));
|
||||
ASSERT_FALSE(ParseConfig("nopreload libA.so 32", always_true));
|
||||
ASSERT_FALSE(ParseConfig("libA.so nopreload # comment", always_true));
|
||||
}
|
||||
|
||||
} // namespace nativeloader
|
||||
} // namespace android
|
|
@ -1,371 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "nativeloader"
|
||||
|
||||
#include "public_libraries.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/result.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
namespace android::nativeloader {
|
||||
|
||||
using namespace internal;
|
||||
using namespace ::std::string_literals;
|
||||
using android::base::ErrnoError;
|
||||
using android::base::Errorf;
|
||||
using android::base::Result;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kDefaultPublicLibrariesFile = "/etc/public.libraries.txt";
|
||||
constexpr const char* kExtendedPublicLibrariesFilePrefix = "public.libraries-";
|
||||
constexpr const char* kExtendedPublicLibrariesFileSuffix = ".txt";
|
||||
constexpr const char* kVendorPublicLibrariesFile = "/vendor/etc/public.libraries.txt";
|
||||
constexpr const char* kLlndkLibrariesFile = "/system/etc/llndk.libraries.txt";
|
||||
constexpr const char* kVndkLibrariesFile = "/system/etc/vndksp.libraries.txt";
|
||||
|
||||
const std::vector<const std::string> kArtApexPublicLibraries = {
|
||||
"libicuuc.so",
|
||||
"libicui18n.so",
|
||||
};
|
||||
|
||||
constexpr const char* kArtApexLibPath = "/apex/com.android.art/" LIB;
|
||||
|
||||
constexpr const char* kNeuralNetworksApexPublicLibrary = "libneuralnetworks.so";
|
||||
|
||||
// TODO(b/130388701): do we need this?
|
||||
std::string root_dir() {
|
||||
static const char* android_root_env = getenv("ANDROID_ROOT");
|
||||
return android_root_env != nullptr ? android_root_env : "/system";
|
||||
}
|
||||
|
||||
bool debuggable() {
|
||||
static bool debuggable = android::base::GetBoolProperty("ro.debuggable", false);
|
||||
return debuggable;
|
||||
}
|
||||
|
||||
std::string vndk_version_str() {
|
||||
static std::string version = android::base::GetProperty("ro.vndk.version", "");
|
||||
if (version != "" && version != "current") {
|
||||
return "." + version;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
|
||||
// variable to add libraries to the list. This is intended for platform tests only.
|
||||
std::string additional_public_libraries() {
|
||||
if (debuggable()) {
|
||||
const char* val = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
|
||||
return val ? val : "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void InsertVndkVersionStr(std::string* file_name) {
|
||||
CHECK(file_name != nullptr);
|
||||
size_t insert_pos = file_name->find_last_of(".");
|
||||
if (insert_pos == std::string::npos) {
|
||||
insert_pos = file_name->length();
|
||||
}
|
||||
file_name->insert(insert_pos, vndk_version_str());
|
||||
}
|
||||
|
||||
const std::function<Result<bool>(const struct ConfigEntry&)> always_true =
|
||||
[](const struct ConfigEntry&) -> Result<bool> { return true; };
|
||||
|
||||
Result<std::vector<std::string>> ReadConfig(
|
||||
const std::string& configFile,
|
||||
const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
|
||||
std::string file_content;
|
||||
if (!base::ReadFileToString(configFile, &file_content)) {
|
||||
return ErrnoError();
|
||||
}
|
||||
Result<std::vector<std::string>> result = ParseConfig(file_content, filter_fn);
|
||||
if (!result) {
|
||||
return Errorf("Cannot parse {}: {}", configFile, result.error().message());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
|
||||
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
|
||||
if (dir != nullptr) {
|
||||
// Failing to opening the dir is not an error, which can happen in
|
||||
// webview_zygote.
|
||||
while (struct dirent* ent = readdir(dir.get())) {
|
||||
if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
|
||||
continue;
|
||||
}
|
||||
const std::string filename(ent->d_name);
|
||||
std::string_view fn = filename;
|
||||
if (android::base::ConsumePrefix(&fn, kExtendedPublicLibrariesFilePrefix) &&
|
||||
android::base::ConsumeSuffix(&fn, kExtendedPublicLibrariesFileSuffix)) {
|
||||
const std::string company_name(fn);
|
||||
const std::string config_file_path = dirname + "/"s + filename;
|
||||
LOG_ALWAYS_FATAL_IF(
|
||||
company_name.empty(),
|
||||
"Error extracting company name from public native library list file path \"%s\"",
|
||||
config_file_path.c_str());
|
||||
|
||||
auto ret = ReadConfig(
|
||||
config_file_path, [&company_name](const struct ConfigEntry& entry) -> Result<bool> {
|
||||
if (android::base::StartsWith(entry.soname, "lib") &&
|
||||
android::base::EndsWith(entry.soname, "." + company_name + ".so")) {
|
||||
return true;
|
||||
} else {
|
||||
return Errorf("Library name \"{}\" does not end with the company name {}.",
|
||||
entry.soname, company_name);
|
||||
}
|
||||
});
|
||||
if (ret) {
|
||||
sonames->insert(sonames->end(), ret->begin(), ret->end());
|
||||
} else {
|
||||
LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
|
||||
config_file_path.c_str(), ret.error().message().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string InitDefaultPublicLibraries(bool for_preload) {
|
||||
std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
|
||||
auto sonames =
|
||||
ReadConfig(config_file, [&for_preload](const struct ConfigEntry& entry) -> Result<bool> {
|
||||
if (for_preload) {
|
||||
return !entry.nopreload;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (!sonames) {
|
||||
LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
|
||||
config_file.c_str(), sonames.error().message().c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string additional_libs = additional_public_libraries();
|
||||
if (!additional_libs.empty()) {
|
||||
auto vec = base::Split(additional_libs, ":");
|
||||
std::copy(vec.begin(), vec.end(), std::back_inserter(*sonames));
|
||||
}
|
||||
|
||||
// If this is for preloading libs, don't remove the libs from APEXes.
|
||||
if (for_preload) {
|
||||
return android::base::Join(*sonames, ':');
|
||||
}
|
||||
|
||||
// Remove the public libs in the art namespace.
|
||||
// These libs are listed in public.android.txt, but we don't want the rest of android
|
||||
// in default namespace to dlopen the libs.
|
||||
// For example, libicuuc.so is exposed to classloader namespace from art namespace.
|
||||
// Unfortunately, it does not have stable C symbols, and default namespace should only use
|
||||
// stable symbols in libandroidicu.so. http://b/120786417
|
||||
for (const std::string& lib_name : kArtApexPublicLibraries) {
|
||||
std::string path(kArtApexLibPath);
|
||||
path.append("/").append(lib_name);
|
||||
|
||||
struct stat s;
|
||||
// Do nothing if the path in /apex does not exist.
|
||||
// Runtime APEX must be mounted since libnativeloader is in the same APEX
|
||||
if (stat(path.c_str(), &s) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = std::find(sonames->begin(), sonames->end(), lib_name);
|
||||
if (it != sonames->end()) {
|
||||
sonames->erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the public libs in the nnapi namespace.
|
||||
auto it = std::find(sonames->begin(), sonames->end(), kNeuralNetworksApexPublicLibrary);
|
||||
if (it != sonames->end()) {
|
||||
sonames->erase(it);
|
||||
}
|
||||
return android::base::Join(*sonames, ':');
|
||||
}
|
||||
|
||||
static std::string InitArtPublicLibraries() {
|
||||
CHECK(sizeof(kArtApexPublicLibraries) > 0);
|
||||
std::string list = android::base::Join(kArtApexPublicLibraries, ":");
|
||||
|
||||
std::string additional_libs = additional_public_libraries();
|
||||
if (!additional_libs.empty()) {
|
||||
list = list + ':' + additional_libs;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static std::string InitVendorPublicLibraries() {
|
||||
// This file is optional, quietly ignore if the file does not exist.
|
||||
auto sonames = ReadConfig(kVendorPublicLibrariesFile, always_true);
|
||||
if (!sonames) {
|
||||
return "";
|
||||
}
|
||||
return android::base::Join(*sonames, ':');
|
||||
}
|
||||
|
||||
// read /system/etc/public.libraries-<companyname>.txt and
|
||||
// /product/etc/public.libraries-<companyname>.txt which contain partner defined
|
||||
// system libs that are exposed to apps. The libs in the txt files must be
|
||||
// named as lib<name>.<companyname>.so.
|
||||
static std::string InitExtendedPublicLibraries() {
|
||||
std::vector<std::string> sonames;
|
||||
ReadExtensionLibraries("/system/etc", &sonames);
|
||||
ReadExtensionLibraries("/product/etc", &sonames);
|
||||
return android::base::Join(sonames, ':');
|
||||
}
|
||||
|
||||
static std::string InitLlndkLibraries() {
|
||||
std::string config_file = kLlndkLibrariesFile;
|
||||
InsertVndkVersionStr(&config_file);
|
||||
auto sonames = ReadConfig(config_file, always_true);
|
||||
if (!sonames) {
|
||||
LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
|
||||
return "";
|
||||
}
|
||||
return android::base::Join(*sonames, ':');
|
||||
}
|
||||
|
||||
static std::string InitVndkspLibraries() {
|
||||
std::string config_file = kVndkLibrariesFile;
|
||||
InsertVndkVersionStr(&config_file);
|
||||
auto sonames = ReadConfig(config_file, always_true);
|
||||
if (!sonames) {
|
||||
LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
|
||||
return "";
|
||||
}
|
||||
return android::base::Join(*sonames, ':');
|
||||
}
|
||||
|
||||
static std::string InitNeuralNetworksPublicLibraries() {
|
||||
return kNeuralNetworksApexPublicLibrary;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const std::string& preloadable_public_libraries() {
|
||||
static std::string list = InitDefaultPublicLibraries(/*for_preload*/ true);
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::string& default_public_libraries() {
|
||||
static std::string list = InitDefaultPublicLibraries(/*for_preload*/ false);
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::string& art_public_libraries() {
|
||||
static std::string list = InitArtPublicLibraries();
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::string& vendor_public_libraries() {
|
||||
static std::string list = InitVendorPublicLibraries();
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::string& extended_public_libraries() {
|
||||
static std::string list = InitExtendedPublicLibraries();
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::string& neuralnetworks_public_libraries() {
|
||||
static std::string list = InitNeuralNetworksPublicLibraries();
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::string& llndk_libraries() {
|
||||
static std::string list = InitLlndkLibraries();
|
||||
return list;
|
||||
}
|
||||
|
||||
const std::string& vndksp_libraries() {
|
||||
static std::string list = InitVndkspLibraries();
|
||||
return list;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// Exported for testing
|
||||
Result<std::vector<std::string>> ParseConfig(
|
||||
const std::string& file_content,
|
||||
const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn) {
|
||||
std::vector<std::string> lines = base::Split(file_content, "\n");
|
||||
|
||||
std::vector<std::string> sonames;
|
||||
for (auto& line : lines) {
|
||||
auto trimmed_line = base::Trim(line);
|
||||
if (trimmed_line[0] == '#' || trimmed_line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<std::string> tokens = android::base::Split(trimmed_line, " ");
|
||||
if (tokens.size() < 1 || tokens.size() > 3) {
|
||||
return Errorf("Malformed line \"{}\"", line);
|
||||
}
|
||||
struct ConfigEntry entry = {.soname = "", .nopreload = false, .bitness = ALL};
|
||||
size_t i = tokens.size();
|
||||
while (i-- > 0) {
|
||||
if (tokens[i] == "nopreload") {
|
||||
entry.nopreload = true;
|
||||
} else if (tokens[i] == "32" || tokens[i] == "64") {
|
||||
if (entry.bitness != ALL) {
|
||||
return Errorf("Malformed line \"{}\": bitness can be specified only once", line);
|
||||
}
|
||||
entry.bitness = tokens[i] == "32" ? ONLY_32 : ONLY_64;
|
||||
} else {
|
||||
if (i != 0) {
|
||||
return Errorf("Malformed line \"{}\"", line);
|
||||
}
|
||||
entry.soname = tokens[i];
|
||||
}
|
||||
}
|
||||
|
||||
// skip 32-bit lib on 64-bit process and vice versa
|
||||
#if defined(__LP64__)
|
||||
if (entry.bitness == ONLY_32) continue;
|
||||
#else
|
||||
if (entry.bitness == ONLY_64) continue;
|
||||
#endif
|
||||
|
||||
Result<bool> ret = filter_fn(entry);
|
||||
if (!ret) {
|
||||
return ret.error();
|
||||
}
|
||||
if (*ret) {
|
||||
// filter_fn has returned true.
|
||||
sonames.push_back(entry.soname);
|
||||
}
|
||||
}
|
||||
return sonames;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace android::nativeloader
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include <android-base/result.h>
|
||||
|
||||
namespace android::nativeloader {
|
||||
|
||||
using android::base::Result;
|
||||
|
||||
// These provide the list of libraries that are available to the namespace for apps.
|
||||
// Not all of the libraries are available to apps. Depending on the context,
|
||||
// e.g., if it is a vendor app or not, different set of libraries are made available.
|
||||
const std::string& preloadable_public_libraries();
|
||||
const std::string& default_public_libraries();
|
||||
const std::string& art_public_libraries();
|
||||
const std::string& vendor_public_libraries();
|
||||
const std::string& extended_public_libraries();
|
||||
const std::string& neuralnetworks_public_libraries();
|
||||
const std::string& llndk_libraries();
|
||||
const std::string& vndksp_libraries();
|
||||
|
||||
// These are exported for testing
|
||||
namespace internal {
|
||||
|
||||
enum Bitness { ALL = 0, ONLY_32, ONLY_64 };
|
||||
|
||||
struct ConfigEntry {
|
||||
std::string soname;
|
||||
bool nopreload;
|
||||
Bitness bitness;
|
||||
};
|
||||
|
||||
Result<std::vector<std::string>> ParseConfig(
|
||||
const std::string& file_content,
|
||||
const std::function<Result<bool>(const ConfigEntry& /* entry */)>& filter_fn);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace android::nativeloader
|
|
@ -1,82 +0,0 @@
|
|||
//
|
||||
// Copyright (C) 2017 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.
|
||||
//
|
||||
|
||||
cc_library {
|
||||
name: "libfoo.oem1",
|
||||
srcs: ["test.cpp"],
|
||||
cflags: ["-DLIBNAME=\"libfoo.oem1.so\""],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libbar.oem1",
|
||||
srcs: ["test.cpp"],
|
||||
cflags: ["-DLIBNAME=\"libbar.oem1.so\""],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libfoo.oem2",
|
||||
srcs: ["test.cpp"],
|
||||
cflags: ["-DLIBNAME=\"libfoo.oem2.so\""],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libbar.oem2",
|
||||
srcs: ["test.cpp"],
|
||||
cflags: ["-DLIBNAME=\"libbar.oem2.so\""],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libfoo.product1",
|
||||
srcs: ["test.cpp"],
|
||||
cflags: ["-DLIBNAME=\"libfoo.product1.so\""],
|
||||
product_specific: true,
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libbar.product1",
|
||||
srcs: ["test.cpp"],
|
||||
cflags: ["-DLIBNAME=\"libbar.product1.so\""],
|
||||
product_specific: true,
|
||||
shared_libs: [
|
||||
"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-headers"],
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2017 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.
|
||||
#
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := public.libraries-oem1.txt
|
||||
LOCAL_SRC_FILES:= $(LOCAL_MODULE)
|
||||
LOCAL_MODULE_CLASS := ETC
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := public.libraries-oem2.txt
|
||||
LOCAL_SRC_FILES:= $(LOCAL_MODULE)
|
||||
LOCAL_MODULE_CLASS := ETC
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := public.libraries-product1.txt
|
||||
LOCAL_SRC_FILES:= $(LOCAL_MODULE)
|
||||
LOCAL_MODULE_CLASS := ETC
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)
|
||||
include $(BUILD_PREBUILT)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_PACKAGE_NAME := oemlibrarytest-system
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_PROGUARD_ENABLED := disabled
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_APPS)
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_PACKAGE_NAME := oemlibrarytest-vendor
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
LOCAL_SDK_VERSION := current
|
||||
LOCAL_PROGUARD_ENABLED := disabled
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_APPS)
|
||||
include $(BUILD_PACKAGE)
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
libfoo.oem1.so
|
||||
libbar.oem1.so
|
|
@ -1,2 +0,0 @@
|
|||
libfoo.oem2.so
|
||||
libbar.oem2.so
|
|
@ -1,2 +0,0 @@
|
|||
libfoo.product1.so
|
||||
libbar.product1.so
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/bash
|
||||
adb root
|
||||
adb remount
|
||||
adb sync
|
||||
adb shell stop
|
||||
adb shell start
|
||||
sleep 5 # wait until device reboots
|
||||
adb logcat -c;
|
||||
adb shell am start -n android.test.app.system/android.test.app.TestActivity
|
||||
adb shell am start -n android.test.app.vendor/android.test.app.TestActivity
|
||||
adb logcat | grep android.test.app
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
|
||||
package android.test.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
public class TestActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
tryLoadingLib("foo.oem1");
|
||||
tryLoadingLib("bar.oem1");
|
||||
tryLoadingLib("foo.oem2");
|
||||
tryLoadingLib("bar.oem2");
|
||||
tryLoadingLib("foo.product1");
|
||||
tryLoadingLib("bar.product1");
|
||||
}
|
||||
|
||||
private void tryLoadingLib(String name) {
|
||||
try {
|
||||
System.loadLibrary(name);
|
||||
Log.d(getPackageName(), "library " + name + " is successfully loaded");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
Log.d(getPackageName(), "failed to load libarary " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.test.app.system">
|
||||
|
||||
<application>
|
||||
<activity android:name="android.test.app.TestActivity" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
#define LOG_TAG "oemlib"
|
||||
#include <android-base/logging.h>
|
||||
|
||||
static __attribute__((constructor)) void test_lib_init() {
|
||||
LOG(DEBUG) << LIBNAME << " loaded";
|
||||
}
|
31
libnativeloader/test/vendor/AndroidManifest.xml
vendored
31
libnativeloader/test/vendor/AndroidManifest.xml
vendored
|
@ -1,31 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2018 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.test.app.vendor">
|
||||
|
||||
<application>
|
||||
<activity android:name="android.test.app.TestActivity" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace android::nativeloader {
|
||||
|
||||
#if defined(__LP64__)
|
||||
#define LIB "lib64"
|
||||
#else
|
||||
#define LIB "lib"
|
||||
#endif
|
||||
|
||||
} // namespace android::nativeloader
|
Loading…
Reference in a new issue