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

Commit 17f119ea authored by Dimitry Ivanov's avatar Dimitry Ivanov Committed by android-build-merger
Browse files

Merge "Native loader as a separate library"

am: beceb6ef

* commit 'beceb6ef':
  Native loader as a separate library
parents 154e1c15 beceb6ef
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef NATIVE_LOADER_H_
#define NATIVE_LOADER_H_

#include "jni.h"
#include <stdint.h>

namespace android {

__attribute__((visibility("default")))
void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
                        jobject class_loader, jstring library_path);

};  // namespace android

#endif  // NATIVE_BRIDGE_H_
+54 −0
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)

NATIVE_LOADER_COMMON_SRC_FILES := \
  native_loader.cpp

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

LOCAL_MODULE:= libnativeloader

LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both

include $(BUILD_SHARED_LIBRARY)

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

LOCAL_MODULE:= libnativeloader

LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both

include $(BUILD_HOST_SHARED_LIBRARY)

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

LOCAL_MODULE:= libnativeloader

LOCAL_SRC_FILES:= $(NATIVE_LOADER_COMMON_SRC_FILES)
LOCAL_STATIC_LIBRARIES := libnativehelper libcutils liblog libbase
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both

include $(BUILD_HOST_STATIC_LIBRARY)
+144 −0
Original line number Diff line number Diff line
/*
 * 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 "nativeloader/native_loader.h"
#include "ScopedUtfChars.h"

#include <dlfcn.h>
#ifdef __ANDROID__
#include <android/dlext.h>
#include "cutils/properties.h"
#endif

#include <algorithm>
#include <vector>
#include <string>
#include <mutex>

#include "base/macros.h"
#include "base/strings.h"

namespace android {

#ifdef __ANDROID__
// TODO(dimitry): move this to system properties.
static const char* kPublicNativeLibraries = "libandroid.so:"
                                            "libc.so:"
                                            "libdl.so:"
                                            "libEGL.so:"
                                            "libGLESv1_CM.so:"
                                            "libGLESv2.so:"
                                            "libGLESv3.so:"
                                            "libjnigraphics.so:"
                                            "liblog.so:"
                                            "libmediandk.so:"
                                            "libm.so:"
                                            "libOpenMAXAL.so:"
                                            "libOpenSLES.so:"
                                            "libstdc++.so:"
                                            "libz.so";

class LibraryNamespaces {
 public:
  LibraryNamespaces() : initialized_(false) { }

  android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader, jstring library_path) {
    ScopedUtfChars libraryPath(env, library_path);

    if (!initialized_ && !InitPublicNamespace(libraryPath.c_str())) {
      return nullptr;
    }

    std::lock_guard<std::mutex> guard(mutex_);

    auto it = FindNamespaceByClassLoader(env, class_loader);

    if (it != namespaces_.end()) {
      return it->second;
    }

    android_namespace_t* ns =
            android_create_namespace("classloader-namespace",
                                     nullptr,
                                     libraryPath.c_str(),
                                     true);

    namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));

    return ns;
  }

 private:
  bool InitPublicNamespace(const char* library_path) {
    // Make sure all the public libraries are loaded
    std::vector<std::string> sonames = android::base::Split(kPublicNativeLibraries, ":");
    for (const auto& soname : sonames) {
      if (dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr) {
        return false;
      }
    }

    // Some apps call dlopen from generated code unknown to linker in which
    // case linker uses anonymous namespace. See b/25844435 for details.
    initialized_ = android_init_namespaces(kPublicNativeLibraries, library_path);

    return initialized_;
  }

  std::vector<std::pair<jweak, android_namespace_t*>>::const_iterator
  FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
    return std::find_if(namespaces_.begin(), namespaces_.end(),
            [&](const std::pair<jweak, android_namespace_t*>& value) {
              return env->IsSameObject(value.first, class_loader);
            });
  }

  bool initialized_;
  std::mutex mutex_;
  std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;

  DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
};

static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
#endif


void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
                        jobject class_loader, jstring library_path) {
#if defined(__ANDROID__)
  if (target_sdk_version == 0 || class_loader == nullptr) {
    return dlopen(path, RTLD_NOW);
  }

  android_namespace_t* ns = g_namespaces->GetOrCreate(env, class_loader, library_path);

  if (ns == nullptr) {
    return nullptr;
  }

  android_dlextinfo extinfo;
  extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
  extinfo.library_namespace = ns;

  return android_dlopen_ext(path, RTLD_NOW, &extinfo);
#else
  UNUSED(env, target_sdk_version, class_loader, library_path);
  return dlopen(path, RTLD_NOW);
#endif
}

}; //  android namespace