Merge "NativeBridge: add "linked namespace" semantic corresponding to linker" am: 1238292db5 am: 21c8a291c5
am: 48e0e59c25

Change-Id: I5e126a5b78a0c360a9131ff9253918443d83544d
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 45266de..929b8ae 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -116,14 +116,25 @@
 // Use NativeBridgeIsSupported() instead in non-namespace scenario.
 bool NativeBridgeIsPathSupported(const char* path);
 
-// Initializes public and anonymous namespace at native bridge side.
+// 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 NativeBridgeInitNamespace(const char* public_ns_sonames,
-                               const char* anon_ns_library_path);
+bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
+                                        const char* anon_ns_library_path);
 
-// Create a namespace and pass the key of related namespaces to native bridge.
+// 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.
@@ -134,7 +145,17 @@
                                                        const char* permitted_when_isolated_path,
                                                        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(native_bridge_namespace_t* from, 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.
@@ -152,7 +173,7 @@
   // Parameters:
   //   runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
   // Returns:
-  //   true iff initialization was successful.
+  //   true if initialization was successful.
   bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
                      const char* instruction_set);
 
@@ -194,10 +215,10 @@
   // instruction set.
   //
   // Parameters:
-  //    instruction_set [IN] the instruction set of the app
+  //   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.
+  //   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.
@@ -206,9 +227,9 @@
   // forwards- or backwards-compatible, and libnativebridge will then stop using it.
   //
   // Parameters:
-  //     bridge_version [IN] the version of libnativebridge.
+  //   bridge_version [IN] the version of libnativebridge.
   // Returns:
-  //     true iff the native bridge supports the given version of libnativebridge.
+  //   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
@@ -217,12 +238,12 @@
   // that will potentially lead to cycles.
   //
   // Parameters:
-  //     signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
+  //   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.
+  //   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.
@@ -231,7 +252,7 @@
   // to zero then the dynamic library is unloaded.
   //
   // Parameters:
-  //     handle [IN] the handler of a dynamic library.
+  //   handle [IN] the handler of a dynamic library.
   //
   // Returns:
   //   0 on success, and nonzero on error.
@@ -257,33 +278,36 @@
   // 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.
+  // 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.
+  //   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.
+  //   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);
+  bool (*initAnonymousNamespace)(const char* public_ns_sonames, const char* anon_ns_library_path);
 
-
-  // Create a namespace and pass the key of releated namespaces to native bridge.
+  // 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.
+  //   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.
+  //   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.
@@ -294,7 +318,25 @@
                                                 const char* permitted_when_isolated_path,
                                                 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)(native_bridge_namespace_t* from, 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
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 83f35b1..050373a 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -573,11 +573,11 @@
   return false;
 }
 
-bool NativeBridgeInitNamespace(const char* public_ns_sonames,
-                               const char* anon_ns_library_path) {
+bool NativeBridgeInitAnonymousNamespace(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);
+      return callbacks->initAnonymousNamespace(public_ns_sonames, anon_ns_library_path);
     } else {
       ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
     }
@@ -608,6 +608,19 @@
   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;
+}
+
 void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
   if (NativeBridgeInitialized()) {
     if (isCompatibleWith(NAMESPACE_VERSION)) {
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 4c3e862..c9468f0 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -24,7 +24,7 @@
     NativeBridge3UnloadLibrary_test.cpp \
     NativeBridge3GetError_test.cpp \
     NativeBridge3IsPathSupported_test.cpp \
-    NativeBridge3InitNamespace_test.cpp \
+    NativeBridge3InitAnonymousNamespace_test.cpp \
     NativeBridge3CreateNamespace_test.cpp \
     NativeBridge3LoadLibraryExt_test.cpp
 
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
index 13fce85..4ef1c82 100644
--- a/libnativebridge/tests/DummyNativeBridge3.cpp
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -76,8 +76,8 @@
   return true;
 }
 
-extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
-                                        const char* /* anon_ns_library_path */) {
+extern "C" bool native_bridge3_initAnonymousNamespace(const char* /* public_ns_sonames */,
+                                                      const char* /* anon_ns_library_path */) {
   return true;
 }
 
@@ -91,30 +91,34 @@
   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,
-  .initNamespace = &native_bridge3_initNamespace,
-  .createNamespace = &native_bridge3_createNamespace,
-  .loadLibraryExt = &native_bridge3_loadLibraryExt
-};
-
+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/NativeBridge3InitAnonymousNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp
new file mode 100644
index 0000000..b0d6b09
--- /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/NativeBridge3InitNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
deleted file mode 100644
index ae0fd2b..0000000
--- a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "NativeBridgeTest.h"
-
-namespace android {
-
-constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
-
-TEST_F(NativeBridgeTest, V3_InitNamespace) {
-    // 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, NativeBridgeInitNamespace(nullptr, nullptr));
-
-    // Clean-up code_cache
-    ASSERT_EQ(0, rmdir(kCodeCache));
-}
-
-}  // namespace android
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 74f2f1d..f3391d1 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -183,6 +183,11 @@
         return false;
       }
 
+      if (!NativeBridgeLinkNamespaces(ns, nullptr, public_libraries_.c_str())) {
+        *error_msg = NativeBridgeGetError();
+        return false;
+      }
+
       native_loader_ns = NativeLoaderNamespace(ns);
     }
 
@@ -324,8 +329,8 @@
 
     // and now initialize native bridge namespaces if necessary.
     if (NativeBridgeInitialized()) {
-      initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
-                                               is_native_bridge ? library_path : nullptr);
+      initialized_ = NativeBridgeInitAnonymousNamespace(public_libraries_.c_str(),
+                                                        is_native_bridge ? library_path : nullptr);
       if (!initialized_) {
         *error_msg = NativeBridgeGetError();
       }