Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2804e59 authored by Zhenhua WANG's avatar Zhenhua WANG Committed by Dimitry Ivanov
Browse files

Upgrade native bridge to version 3 to support namespace

Native bridge implements namespace related interfaces in version 3.
The namespace semantic here is same as Android dynamic linker's.
Native loader wraps library loading functions of dynamic linker and
native bridge. Thus, Android runtime is able to load native library
of different ISA on one device by calling native loader directly.

Bug: http://b/28242460


Test: mm && make test-art-host -j48
Change-Id: Idde2b9d99fb6ebe547407c716b5478a231f745a7
Signed-off-by: default avatarZhenhua WANG <zhenhua.wang@intel.com>
parent 0ca2fe4c
Loading
Loading
Loading
Loading
+138 −1
Original line number Original line Diff line number Diff line
@@ -62,12 +62,19 @@ bool NativeBridgeAvailable();
bool NativeBridgeInitialized();
bool NativeBridgeInitialized();


// Load a shared library that is supported by the native bridge.
// 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);
void* NativeBridgeLoadLibrary(const char* libpath, int flag);


// Get a native bridge trampoline for specified native method.
// Get a native bridge trampoline for specified native method.
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);


// True if native library is valid and is for an ABI that is supported by native bridge.
// 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);
bool NativeBridgeIsSupported(const char* libpath);


// Returns the version number of the native bridge. This information is available after a
// Returns the version number of the native bridge. This information is available after a
@@ -91,6 +98,48 @@ bool NativeBridgeError();
// This functionality is exposed mainly for testing.
// This functionality is exposed mainly for testing.
bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
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.
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.
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 public and anonymous namespace at native bridge side.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
bool NativeBridgeInitNamespace(const char* public_ns_sonames,
                               const char* anon_ns_library_path);

// Create a namespace and pass the key of related namespaces to native bridge.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
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);

// Load a shared library with namespace key that is supported by the native bridge.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);

// Native bridge interfaces to runtime.
// Native bridge interfaces to runtime.
struct NativeBridgeCallbacks {
struct NativeBridgeCallbacks {
  // Version number of the interface.
  // Version number of the interface.
@@ -114,6 +163,9 @@ struct NativeBridgeCallbacks {
  //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
  //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
  // Returns:
  // Returns:
  //   The opaque handle of the shared library if sucessful, otherwise NULL
  //   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);
  void* (*loadLibrary)(const char* libpath, int flag);


  // Get a native bridge trampoline for specified native method. The trampoline has same
  // Get a native bridge trampoline for specified native method. The trampoline has same
@@ -133,6 +185,9 @@ struct NativeBridgeCallbacks {
  //   libpath [IN] path to the shared library
  //   libpath [IN] path to the shared library
  // Returns:
  // Returns:
  //   TRUE if library is supported by native bridge, FALSE otherwise
  //   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);
  bool (*isSupported)(const char* libpath);


  // Provide environment values required by the app running with native bridge according to the
  // Provide environment values required by the app running with native bridge according to the
@@ -169,6 +224,88 @@ struct NativeBridgeCallbacks {
  //     runtime.
  //     runtime.
  //     Otherwise, a pointer to the signal handler.
  //     Otherwise, a pointer to the signal handler.
  NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
  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.
  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 and pass the key of
  // two namespaces(default and anonymous) owned by dynamic linker to native bridge.
  //
  // 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 (*initNamespace)(const char* public_ns_sonames,
                        const char* anon_ns_library_path);


  // Create a namespace and pass the key of releated namespaces to native bridge.
  //
  // 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.
  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,
                                                native_bridge_namespace_t* parent_ns);

  // Load a shared library within a namespace.
  //
  // 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, native_bridge_namespace_t* ns);
};
};


// Runtime interfaces to native bridge.
// Runtime interfaces to native bridge.
+105 −12
Original line number Original line Diff line number Diff line
@@ -80,6 +80,19 @@ static const char* GetNativeBridgeStateString(NativeBridgeState state) {
// Current state of the native bridge.
// Current state of the native bridge.
static NativeBridgeState state = NativeBridgeState::kNotSetup;
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,
};

// Whether we had an error at some point.
// Whether we had an error at some point.
static bool had_error = false;
static bool had_error = false;


@@ -100,8 +113,6 @@ static char* app_code_cache_dir = nullptr;
// and hard code the directory name again here.
// and hard code the directory name again here.
static constexpr const char* kCodeCacheDir = "code_cache";
static constexpr const char* kCodeCacheDir = "code_cache";


static constexpr uint32_t kLibNativeBridgeVersion = 2;

// Characters allowed in a native bridge filename. The first character must
// 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._-].
// 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) {
static bool CharacterAllowed(char c, bool first) {
@@ -152,19 +163,18 @@ bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
  }
  }
}
}


static bool VersionCheck(const NativeBridgeCallbacks* cb) {
// 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
  // Libnativebridge is now designed to be forward-compatible. So only "0" is an unsupported
  // version.
  // version.
  if (cb == nullptr || cb->version == 0) {
  if (callbacks == nullptr || callbacks->version == 0 || version == 0) {
    return false;
    return false;
  }
  }


  // If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
  // If this is a v2+ bridge, it may not be forwards- or backwards-compatible. Check.
  if (cb->version >= 2) {
  if (callbacks->version >= SIGNAL_VERSION) {
    if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
    return callbacks->isCompatibleWith(version);
      // TODO: Scan which version is supported, and fall back to handle it.
      return false;
    }
  }
  }


  return true;
  return true;
@@ -205,7 +215,7 @@ bool LoadNativeBridge(const char* nb_library_filename,
        callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
        callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
                                                                   kNativeBridgeInterfaceSymbol));
                                                                   kNativeBridgeInterfaceSymbol));
        if (callbacks != nullptr) {
        if (callbacks != nullptr) {
          if (VersionCheck(callbacks)) {
          if (isCompatibleWith(NAMESPACE_VERSION)) {
            // Store the handle for later.
            // Store the handle for later.
            native_bridge_handle = handle;
            native_bridge_handle = handle;
          } else {
          } else {
@@ -520,8 +530,91 @@ uint32_t NativeBridgeGetVersion() {
}
}


NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
NativeBridgeSignalHandlerFn NativeBridgeGetSignalHandler(int signal) {
  if (NativeBridgeInitialized() && callbacks->version >= 2) {
  if (NativeBridgeInitialized()) {
    if (isCompatibleWith(SIGNAL_VERSION)) {
      return callbacks->getSignalHandler(signal);
      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;
}

char* NativeBridgeGetError() {
  if (NativeBridgeInitialized()) {
    if (isCompatibleWith(NAMESPACE_VERSION)) {
      return callbacks->getError();
    } else {
      ALOGE("not compatible with version %d, cannot get message", NAMESPACE_VERSION);
    }
  }
  return nullptr;
}

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 NativeBridgeInitNamespace(const char* public_ns_sonames,
                               const char* anon_ns_library_path) {
  if (NativeBridgeInitialized()) {
    if (isCompatibleWith(NAMESPACE_VERSION)) {
      return callbacks->initNamespace(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;
}

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;
  return nullptr;
}
}
+7 −1
Original line number Original line Diff line number Diff line
@@ -20,7 +20,13 @@ test_src_files := \
    PreInitializeNativeBridgeFail2_test.cpp \
    PreInitializeNativeBridgeFail2_test.cpp \
    ReSetupNativeBridge_test.cpp \
    ReSetupNativeBridge_test.cpp \
    UnavailableNativeBridge_test.cpp \
    UnavailableNativeBridge_test.cpp \
    ValidNameNativeBridge_test.cpp
    ValidNameNativeBridge_test.cpp \
    NativeBridge3UnloadLibrary_test.cpp \
    NativeBridge3GetError_test.cpp \
    NativeBridge3IsPathSupported_test.cpp \
    NativeBridge3InitNamespace_test.cpp \
    NativeBridge3CreateNamespace_test.cpp \
    NativeBridge3LoadLibraryExt_test.cpp




shared_libraries := \
shared_libraries := \
+38 −0
Original line number Original line Diff line number Diff line
@@ -68,3 +68,41 @@ LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
LOCAL_MULTILIB := both


include $(BUILD_HOST_SHARED_LIBRARY)
include $(BUILD_HOST_SHARED_LIBRARY)


# v3.

NATIVE_BRIDGE3_COMMON_SRC_FILES := \
  DummyNativeBridge3.cpp

# Shared library for target
# ========================================================
include $(CLEAR_VARS)

LOCAL_MODULE:= libnativebridge3-dummy

LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both

include $(BUILD_SHARED_LIBRARY)

# Shared library for host
# ========================================================
include $(CLEAR_VARS)

LOCAL_MODULE:= libnativebridge3-dummy

LOCAL_SRC_FILES:= $(NATIVE_BRIDGE3_COMMON_SRC_FILES)
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both

include $(BUILD_HOST_SHARED_LIBRARY)

+120 −0
Original line number Original line Diff line number Diff line
/*
 * 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" char* native_bridge3_getError() {
  return nullptr;
}

extern "C" bool native_bridge3_isPathSupported(const char* /* path */) {
  return true;
}

extern "C" bool native_bridge3_initNamespace(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" 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,
  .initNamespace = &native_bridge3_initNamespace,
  .createNamespace = &native_bridge3_createNamespace,
  .loadLibraryExt = &native_bridge3_loadLibraryExt
};
Loading