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

Commit 28c0c076 authored by Dimitry Ivanov's avatar Dimitry Ivanov Committed by Gerrit Code Review
Browse files

Merge "Upgrade native bridge to version 3 to support namespace"

parents a16ae871 f2804e59
Loading
Loading
Loading
Loading
+138 −1
Original line number Diff line number Diff line
@@ -62,12 +62,19 @@ bool NativeBridgeAvailable();
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 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);

// 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.
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.
struct NativeBridgeCallbacks {
  // Version number of the interface.
@@ -114,6 +163,9 @@ struct NativeBridgeCallbacks {
  //   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
@@ -133,6 +185,9 @@ struct NativeBridgeCallbacks {
  //   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
@@ -169,6 +224,88 @@ struct NativeBridgeCallbacks {
  //     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.
  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.
+105 −12
Original line number Diff line number Diff line
@@ -80,6 +80,19 @@ static const char* GetNativeBridgeStateString(NativeBridgeState state) {
// 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,
};

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

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

static constexpr uint32_t kLibNativeBridgeVersion = 2;

// 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) {
@@ -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
  // version.
  if (cb == nullptr || cb->version == 0) {
  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 (cb->version >= 2) {
    if (!callbacks->isCompatibleWith(kLibNativeBridgeVersion)) {
      // TODO: Scan which version is supported, and fall back to handle it.
      return false;
    }
  if (callbacks->version >= SIGNAL_VERSION) {
    return callbacks->isCompatibleWith(version);
  }

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

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

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;
}
+7 −1
Original line number Diff line number Diff line
@@ -20,7 +20,13 @@ test_src_files := \
    PreInitializeNativeBridgeFail2_test.cpp \
    ReSetupNativeBridge_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 := \
+38 −0
Original line number Diff line number Diff line
@@ -68,3 +68,41 @@ LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both

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 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