diff options
author | Orion Hodson <oth@google.com> | 2019-10-09 13:29:16 +0100 |
---|---|---|
committer | Treehugger Robot <treehugger-gerrit@google.com> | 2019-10-11 09:57:02 +0000 |
commit | 9b16e344b246096d228dd4b41ff711884bcfcb3e (patch) | |
tree | ff93f416fcc59fb831202e80b5fb8c8ede99d500 /libnativebridge | |
parent | e828ea0553b3106598071239e8215fca63b15c9b (diff) |
Move libnative{bridge,loader} to art/
This change moves system/core/libnative{bridge,loader} under art/.
Bug: 137364733
Test: m
Change-Id: I9be7333d00fcd3f36cd80520e50a30ea840187ad
Diffstat (limited to 'libnativebridge')
34 files changed, 2627 insertions, 0 deletions
diff --git a/libnativebridge/.clang-format b/libnativebridge/.clang-format new file mode 120000 index 0000000000..fd0645fdf9 --- /dev/null +++ b/libnativebridge/.clang-format @@ -0,0 +1 @@ +../.clang-format-2
\ No newline at end of file diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp new file mode 100644 index 0000000000..c97845d16a --- /dev/null +++ b/libnativebridge/Android.bp @@ -0,0 +1,65 @@ +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"] diff --git a/libnativebridge/CPPLINT.cfg b/libnativebridge/CPPLINT.cfg new file mode 100644 index 0000000000..578047ba10 --- /dev/null +++ b/libnativebridge/CPPLINT.cfg @@ -0,0 +1,19 @@ +# +# 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 diff --git a/libnativebridge/OWNERS b/libnativebridge/OWNERS new file mode 100644 index 0000000000..daf87f47b1 --- /dev/null +++ b/libnativebridge/OWNERS @@ -0,0 +1,4 @@ +dimitry@google.com +eaeltsin@google.com +ngeoffray@google.com +oth@google.com diff --git a/libnativebridge/include/nativebridge/native_bridge.h b/libnativebridge/include/nativebridge/native_bridge.h new file mode 100644 index 0000000000..e9c9500252 --- /dev/null +++ b/libnativebridge/include/nativebridge/native_bridge.h @@ -0,0 +1,418 @@ +/* + * 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_ diff --git a/libnativebridge/libnativebridge.map.txt b/libnativebridge/libnativebridge.map.txt new file mode 100644 index 0000000000..a6841a3a81 --- /dev/null +++ b/libnativebridge/libnativebridge.map.txt @@ -0,0 +1,45 @@ +# +# 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: + *; +}; diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc new file mode 100644 index 0000000000..9adba9a50e --- /dev/null +++ b/libnativebridge/native_bridge.cc @@ -0,0 +1,646 @@ +/* + * 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 diff --git a/libnativebridge/native_bridge_lazy.cc b/libnativebridge/native_bridge_lazy.cc new file mode 100644 index 0000000000..94c80848ee --- /dev/null +++ b/libnativebridge/native_bridge_lazy.cc @@ -0,0 +1,167 @@ +/* + * 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 diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp new file mode 100644 index 0000000000..2bb8467385 --- /dev/null +++ b/libnativebridge/tests/Android.bp @@ -0,0 +1,110 @@ +// +// 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"], +} diff --git a/libnativebridge/tests/CodeCacheCreate_test.cpp b/libnativebridge/tests/CodeCacheCreate_test.cpp new file mode 100644 index 0000000000..58270c43dd --- /dev/null +++ b/libnativebridge/tests/CodeCacheCreate_test.cpp @@ -0,0 +1,51 @@ +/* + * 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 diff --git a/libnativebridge/tests/CodeCacheExists_test.cpp b/libnativebridge/tests/CodeCacheExists_test.cpp new file mode 100644 index 0000000000..8ba01586b5 --- /dev/null +++ b/libnativebridge/tests/CodeCacheExists_test.cpp @@ -0,0 +1,54 @@ +/* + * 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 diff --git a/libnativebridge/tests/CodeCacheStatFail_test.cpp b/libnativebridge/tests/CodeCacheStatFail_test.cpp new file mode 100644 index 0000000000..4ea519ee96 --- /dev/null +++ b/libnativebridge/tests/CodeCacheStatFail_test.cpp @@ -0,0 +1,51 @@ +/* + * 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 diff --git a/libnativebridge/tests/CompleteFlow_test.cpp b/libnativebridge/tests/CompleteFlow_test.cpp new file mode 100644 index 0000000000..b033792301 --- /dev/null +++ b/libnativebridge/tests/CompleteFlow_test.cpp @@ -0,0 +1,47 @@ +/* + * 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 diff --git a/libnativebridge/tests/DummyNativeBridge.cpp b/libnativebridge/tests/DummyNativeBridge.cpp new file mode 100644 index 0000000000..b9894f6b95 --- /dev/null +++ b/libnativebridge/tests/DummyNativeBridge.cpp @@ -0,0 +1,53 @@ +/* + * 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 +}; diff --git a/libnativebridge/tests/DummyNativeBridge2.cpp b/libnativebridge/tests/DummyNativeBridge2.cpp new file mode 100644 index 0000000000..6920c74822 --- /dev/null +++ b/libnativebridge/tests/DummyNativeBridge2.cpp @@ -0,0 +1,76 @@ +/* + * 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 +}; + diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp new file mode 100644 index 0000000000..4ef1c82733 --- /dev/null +++ b/libnativebridge/tests/DummyNativeBridge3.cpp @@ -0,0 +1,124 @@ +/* + * 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}; diff --git a/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp b/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp new file mode 100644 index 0000000000..8f7973df09 --- /dev/null +++ b/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp @@ -0,0 +1,40 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridge2Signal_test.cpp b/libnativebridge/tests/NativeBridge2Signal_test.cpp new file mode 100644 index 0000000000..44e45e3622 --- /dev/null +++ b/libnativebridge/tests/NativeBridge2Signal_test.cpp @@ -0,0 +1,42 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp new file mode 100644 index 0000000000..668d9428a0 --- /dev/null +++ b/libnativebridge/tests/NativeBridge3CreateNamespace_test.cpp @@ -0,0 +1,40 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridge3GetError_test.cpp b/libnativebridge/tests/NativeBridge3GetError_test.cpp new file mode 100644 index 0000000000..0b9f5821f2 --- /dev/null +++ b/libnativebridge/tests/NativeBridge3GetError_test.cpp @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp new file mode 100644 index 0000000000..b0d6b09d13 --- /dev/null +++ b/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp new file mode 100644 index 0000000000..325e40b408 --- /dev/null +++ b/libnativebridge/tests/NativeBridge3IsPathSupported_test.cpp @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp new file mode 100644 index 0000000000..4caeb4481f --- /dev/null +++ b/libnativebridge/tests/NativeBridge3LoadLibraryExt_test.cpp @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp new file mode 100644 index 0000000000..93a979c0a0 --- /dev/null +++ b/libnativebridge/tests/NativeBridge3UnloadLibrary_test.cpp @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/libnativebridge/tests/NativeBridgeApi.c b/libnativebridge/tests/NativeBridgeApi.c new file mode 100644 index 0000000000..7ab71fe814 --- /dev/null +++ b/libnativebridge/tests/NativeBridgeApi.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* The main purpose of this test is to ensure this C header compiles in C, so + * that no C++ features inadvertently leak into the C ABI. */ +#include "nativebridge/native_bridge.h" + +int main(int argc, char** argv) { + (void)argc; + (void)argv; + return 0; +} diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h new file mode 100644 index 0000000000..0f99816c9f --- /dev/null +++ b/libnativebridge/tests/NativeBridgeTest.h @@ -0,0 +1,39 @@ +/* + * 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_ + diff --git a/libnativebridge/tests/NativeBridgeVersion_test.cpp b/libnativebridge/tests/NativeBridgeVersion_test.cpp new file mode 100644 index 0000000000..d3f9a80fc9 --- /dev/null +++ b/libnativebridge/tests/NativeBridgeVersion_test.cpp @@ -0,0 +1,38 @@ +/* + * 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 diff --git a/libnativebridge/tests/NeedsNativeBridge_test.cpp b/libnativebridge/tests/NeedsNativeBridge_test.cpp new file mode 100644 index 0000000000..c8ff743b05 --- /dev/null +++ b/libnativebridge/tests/NeedsNativeBridge_test.cpp @@ -0,0 +1,36 @@ +/* + * 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 diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp new file mode 100644 index 0000000000..5a2b0a150f --- /dev/null +++ b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp @@ -0,0 +1,40 @@ +/* + * 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 diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp new file mode 100644 index 0000000000..af976b1745 --- /dev/null +++ b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp new file mode 100644 index 0000000000..cd5a8e24bb --- /dev/null +++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp @@ -0,0 +1,68 @@ +/* + * 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 diff --git a/libnativebridge/tests/ReSetupNativeBridge_test.cpp b/libnativebridge/tests/ReSetupNativeBridge_test.cpp new file mode 100644 index 0000000000..944e5d7e98 --- /dev/null +++ b/libnativebridge/tests/ReSetupNativeBridge_test.cpp @@ -0,0 +1,30 @@ +/* + * 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 diff --git a/libnativebridge/tests/UnavailableNativeBridge_test.cpp b/libnativebridge/tests/UnavailableNativeBridge_test.cpp new file mode 100644 index 0000000000..ad374a5e96 --- /dev/null +++ b/libnativebridge/tests/UnavailableNativeBridge_test.cpp @@ -0,0 +1,29 @@ +/* + * 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 diff --git a/libnativebridge/tests/ValidNameNativeBridge_test.cpp b/libnativebridge/tests/ValidNameNativeBridge_test.cpp new file mode 100644 index 0000000000..690be4a302 --- /dev/null +++ b/libnativebridge/tests/ValidNameNativeBridge_test.cpp @@ -0,0 +1,35 @@ +/* + * 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 |