Hide non-bridged/bridged namespaces behind NativeLoaderNamespace class
NativeLoaderNamespace fully abstracts the non-bridged (so called android-) and bridged namespaces. Bug: 130388701 Test: build & pass presubmit tests Change-Id: I3d5ca7515711e7638f4a5ab4d3a150185c3d17ac
This commit is contained in:
parent
3afe5f22b3
commit
8537781cc7
|
@ -30,6 +30,7 @@ cc_library {
|
|||
android: {
|
||||
srcs: [
|
||||
"library_namespaces.cpp",
|
||||
"native_loader_namespace.cpp",
|
||||
"public_libraries.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
|
|
|
@ -41,8 +41,6 @@ namespace {
|
|||
// vendor and system namespaces.
|
||||
constexpr const char* kVendorNamespaceName = "sphal";
|
||||
constexpr const char* kVndkNamespaceName = "vndk";
|
||||
constexpr const char* kDefaultNamespaceName = "default";
|
||||
constexpr const char* kPlatformNamespaceName = "platform";
|
||||
constexpr const char* kRuntimeNamespaceName = "runtime";
|
||||
|
||||
// classloader-namespace is a linker namespace that is created for the loaded
|
||||
|
@ -167,34 +165,13 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd
|
|||
|
||||
LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader");
|
||||
|
||||
uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
if (is_shared) {
|
||||
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
}
|
||||
|
||||
if (target_sdk_version < 24) {
|
||||
namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
|
||||
}
|
||||
|
||||
NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
|
||||
|
||||
bool is_native_bridge = false;
|
||||
|
||||
if (parent_ns != nullptr) {
|
||||
is_native_bridge = !parent_ns->is_android_namespace();
|
||||
} else if (!library_path.empty()) {
|
||||
is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
|
||||
}
|
||||
|
||||
std::string system_exposed_libraries = default_public_libraries();
|
||||
const char* namespace_name = kClassloaderNamespaceName;
|
||||
android_namespace_t* vndk_ns = nullptr;
|
||||
bool unbundled_vendor_or_product_app = false;
|
||||
if ((apk_origin == APK_ORIGIN_VENDOR ||
|
||||
(apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
|
||||
!is_shared) {
|
||||
LOG_FATAL_IF(is_native_bridge,
|
||||
"Unbundled vendor / product apk must not use translated architecture");
|
||||
|
||||
unbundled_vendor_or_product_app = true;
|
||||
// For vendor / product apks, give access to the vendor / product lib even though
|
||||
// they are treated as unbundled; the libs and apks are still bundled
|
||||
// together in the vendor / product partition.
|
||||
|
@ -214,22 +191,12 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd
|
|||
origin_partition = "unknown";
|
||||
origin_lib_path = "";
|
||||
}
|
||||
|
||||
LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture",
|
||||
origin_partition);
|
||||
|
||||
library_path = library_path + ":" + origin_lib_path;
|
||||
permitted_path = permitted_path + ":" + origin_lib_path;
|
||||
|
||||
// Also give access to LLNDK libraries since they are available to vendors
|
||||
system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries().c_str();
|
||||
|
||||
// Give access to VNDK-SP libraries from the 'vndk' namespace.
|
||||
vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
|
||||
if (vndk_ns == nullptr) {
|
||||
ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition);
|
||||
}
|
||||
|
||||
// Different name is useful for debugging
|
||||
namespace_name = kVendorClassloaderNamespaceName;
|
||||
ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
|
||||
|
@ -241,120 +208,56 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd
|
|||
system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries();
|
||||
}
|
||||
}
|
||||
std::string runtime_exposed_libraries = runtime_public_libraries();
|
||||
|
||||
NativeLoaderNamespace native_loader_ns;
|
||||
if (!is_native_bridge) {
|
||||
// The platform namespace is called "default" for binaries in /system and
|
||||
// "platform" for those in the Runtime APEX. Try "platform" first since
|
||||
// "default" always exists.
|
||||
android_namespace_t* platform_ns = android_get_exported_namespace(kPlatformNamespaceName);
|
||||
if (platform_ns == nullptr) {
|
||||
platform_ns = android_get_exported_namespace(kDefaultNamespaceName);
|
||||
}
|
||||
|
||||
android_namespace_t* android_parent_ns;
|
||||
if (parent_ns != nullptr) {
|
||||
android_parent_ns = parent_ns->get_android_ns();
|
||||
} else {
|
||||
// Fall back to the platform namespace if no parent is found.
|
||||
android_parent_ns = platform_ns;
|
||||
}
|
||||
|
||||
android_namespace_t* ns =
|
||||
android_create_namespace(namespace_name, nullptr, library_path.c_str(), namespace_type,
|
||||
permitted_path.c_str(), android_parent_ns);
|
||||
if (ns == nullptr) {
|
||||
*error_msg = dlerror();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Note that when vendor_ns is not configured this function will return nullptr
|
||||
// and it will result in linking vendor_public_libraries_ to the default namespace
|
||||
// which is expected behavior in this case.
|
||||
android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName);
|
||||
|
||||
android_namespace_t* runtime_ns = android_get_exported_namespace(kRuntimeNamespaceName);
|
||||
|
||||
if (!android_link_namespaces(ns, platform_ns, system_exposed_libraries.c_str())) {
|
||||
*error_msg = dlerror();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Runtime apex does not exist in host, and under certain build conditions.
|
||||
if (runtime_ns != nullptr) {
|
||||
if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
|
||||
*error_msg = dlerror();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (vndk_ns != nullptr && !vndksp_libraries().empty()) {
|
||||
// vendor apks are allowed to use VNDK-SP libraries.
|
||||
if (!android_link_namespaces(ns, vndk_ns, vndksp_libraries().c_str())) {
|
||||
*error_msg = dlerror();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vendor_public_libraries().empty()) {
|
||||
if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries().c_str())) {
|
||||
*error_msg = dlerror();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
native_loader_ns = NativeLoaderNamespace(ns);
|
||||
} else {
|
||||
// Same functionality as in the branch above, but calling through native bridge.
|
||||
|
||||
native_bridge_namespace_t* platform_ns =
|
||||
NativeBridgeGetExportedNamespace(kPlatformNamespaceName);
|
||||
if (platform_ns == nullptr) {
|
||||
platform_ns = NativeBridgeGetExportedNamespace(kDefaultNamespaceName);
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* native_bridge_parent_namespace;
|
||||
if (parent_ns != nullptr) {
|
||||
native_bridge_parent_namespace = parent_ns->get_native_bridge_ns();
|
||||
} else {
|
||||
native_bridge_parent_namespace = platform_ns;
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* ns =
|
||||
NativeBridgeCreateNamespace(namespace_name, nullptr, library_path.c_str(), namespace_type,
|
||||
permitted_path.c_str(), native_bridge_parent_namespace);
|
||||
if (ns == nullptr) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* vendor_ns = NativeBridgeGetExportedNamespace(kVendorNamespaceName);
|
||||
native_bridge_namespace_t* runtime_ns = NativeBridgeGetExportedNamespace(kRuntimeNamespaceName);
|
||||
|
||||
if (!NativeBridgeLinkNamespaces(ns, platform_ns, system_exposed_libraries.c_str())) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Runtime apex does not exist in host, and under certain build conditions.
|
||||
if (runtime_ns != nullptr) {
|
||||
if (!NativeBridgeLinkNamespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (!vendor_public_libraries().empty()) {
|
||||
if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries().c_str())) {
|
||||
*error_msg = NativeBridgeGetError();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
native_loader_ns = NativeLoaderNamespace(ns);
|
||||
// Create the app namespace
|
||||
NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
|
||||
auto app_ns =
|
||||
NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns,
|
||||
is_shared, target_sdk_version < 24 /* is_greylist_enabled */);
|
||||
if (app_ns.IsNil()) {
|
||||
*error_msg = app_ns.GetError();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
|
||||
// ... and link to other namespaces to allow access to some public libraries
|
||||
bool is_bridged = app_ns.IsBridged();
|
||||
|
||||
auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged);
|
||||
if (!app_ns.Link(platform_ns, system_exposed_libraries)) {
|
||||
*error_msg = app_ns.GetError();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged);
|
||||
// Runtime apex does not exist in host, and under certain build conditions.
|
||||
if (!runtime_ns.IsNil()) {
|
||||
if (!app_ns.Link(runtime_ns, runtime_public_libraries())) {
|
||||
*error_msg = app_ns.GetError();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Give access to VNDK-SP libraries from the 'vndk' namespace.
|
||||
if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) {
|
||||
auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
|
||||
if (!vndk_ns.IsNil() && !app_ns.Link(vndk_ns, vndksp_libraries())) {
|
||||
*error_msg = app_ns.GetError();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Note that when vendor_ns is not configured, vendor_ns.IsNil() will be true
|
||||
// and it will result in linking to the default namespace which is expected
|
||||
// behavior in this case.
|
||||
if (!vendor_public_libraries().empty()) {
|
||||
auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged);
|
||||
if (!app_ns.Link(vendor_ns, vendor_public_libraries())) {
|
||||
*error_msg = dlerror();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns));
|
||||
|
||||
return &(namespaces_.back().second);
|
||||
}
|
||||
|
|
|
@ -220,25 +220,12 @@ void NativeLoaderFreeErrorMessage(char* msg) {
|
|||
#if defined(__ANDROID__)
|
||||
void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
|
||||
bool* needs_native_bridge, char** error_msg) {
|
||||
if (ns->is_android_namespace()) {
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns->get_android_ns();
|
||||
|
||||
void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
|
||||
if (handle == nullptr) {
|
||||
*error_msg = strdup(dlerror());
|
||||
}
|
||||
*needs_native_bridge = false;
|
||||
return handle;
|
||||
} else {
|
||||
void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns());
|
||||
if (handle == nullptr) {
|
||||
*error_msg = strdup(NativeBridgeGetError());
|
||||
}
|
||||
*needs_native_bridge = true;
|
||||
return handle;
|
||||
void* handle = ns->Load(path);
|
||||
if (handle == nullptr) {
|
||||
*error_msg = ns->GetError();
|
||||
}
|
||||
*needs_native_bridge = ns->IsBridged();
|
||||
return handle;
|
||||
}
|
||||
|
||||
// native_bridge_namespaces are not supported for callers of this function.
|
||||
|
@ -247,10 +234,9 @@ void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
|
|||
android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
|
||||
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
|
||||
NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
|
||||
if (ns != nullptr) {
|
||||
return ns->is_android_namespace() ? ns->get_android_ns() : nullptr;
|
||||
if (ns != nullptr && !ns->IsBridged()) {
|
||||
return ns->ToRawAndroidNamespace();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "nativeloader"
|
||||
#include "native_loader_namespace.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "android-base/strings.h"
|
||||
#include "log/log.h"
|
||||
#include "nativebridge/native_bridge.h"
|
||||
#include "nativeloader/dlext_namespaces.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kDefaultNamespaceName = "default";
|
||||
constexpr const char* kPlatformNamespaceName = "platform";
|
||||
|
||||
} // namespace
|
||||
|
||||
NativeLoaderNamespace NativeLoaderNamespace::GetExportedNamespace(const std::string& name,
|
||||
bool is_bridged) {
|
||||
if (!is_bridged) {
|
||||
return NativeLoaderNamespace(name, android_get_exported_namespace(name.c_str()));
|
||||
} else {
|
||||
return NativeLoaderNamespace(name, NativeBridgeGetExportedNamespace(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
char* NativeLoaderNamespace::GetError() const {
|
||||
if (!IsBridged()) {
|
||||
return strdup(dlerror());
|
||||
} else {
|
||||
return strdup(NativeBridgeGetError());
|
||||
}
|
||||
}
|
||||
|
||||
// The platform namespace is called "default" for binaries in /system and
|
||||
// "platform" for those in the Runtime APEX. Try "platform" first since
|
||||
// "default" always exists.
|
||||
NativeLoaderNamespace NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) {
|
||||
NativeLoaderNamespace ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged);
|
||||
if (ns.IsNil()) {
|
||||
ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name,
|
||||
const std::string& search_paths,
|
||||
const std::string& permitted_paths,
|
||||
const NativeLoaderNamespace* parent,
|
||||
bool is_shared, bool is_greylist_enabled) {
|
||||
bool is_bridged = false;
|
||||
if (parent != nullptr) {
|
||||
is_bridged = parent->IsBridged();
|
||||
} else if (!search_paths.empty()) {
|
||||
is_bridged = NativeBridgeIsPathSupported(search_paths.c_str());
|
||||
}
|
||||
|
||||
// Fall back to the platform namespace if no parent is set.
|
||||
const NativeLoaderNamespace& effective_parent =
|
||||
parent != nullptr ? *parent : GetPlatformNamespace(is_bridged);
|
||||
|
||||
uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;
|
||||
if (is_shared) {
|
||||
type |= ANDROID_NAMESPACE_TYPE_SHARED;
|
||||
}
|
||||
if (is_greylist_enabled) {
|
||||
type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
|
||||
}
|
||||
|
||||
if (!is_bridged) {
|
||||
android_namespace_t* raw =
|
||||
android_create_namespace(name.c_str(), nullptr, search_paths.c_str(), type,
|
||||
permitted_paths.c_str(), effective_parent.ToRawAndroidNamespace());
|
||||
return NativeLoaderNamespace(name, raw);
|
||||
} else {
|
||||
native_bridge_namespace_t* raw = NativeBridgeCreateNamespace(
|
||||
name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(),
|
||||
effective_parent.ToRawNativeBridgeNamespace());
|
||||
return NativeLoaderNamespace(name, raw);
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeLoaderNamespace::Link(const NativeLoaderNamespace& target,
|
||||
const std::string& shared_libs) const {
|
||||
LOG_ALWAYS_FATAL_IF(shared_libs.empty(), "empty share lib when linking %s to %s",
|
||||
this->name().c_str(), target.name().c_str());
|
||||
if (!IsBridged()) {
|
||||
return android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(),
|
||||
shared_libs.c_str());
|
||||
} else {
|
||||
return NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(),
|
||||
target.ToRawNativeBridgeNamespace(), shared_libs.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void* NativeLoaderNamespace::Load(const std::string& lib_name) const {
|
||||
if (!IsBridged()) {
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = this->ToRawAndroidNamespace();
|
||||
return android_dlopen_ext(lib_name.c_str(), RTLD_NOW, &extinfo);
|
||||
} else {
|
||||
return NativeBridgeLoadLibraryExt(lib_name.c_str(), RTLD_NOW,
|
||||
this->ToRawNativeBridgeNamespace());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
|
@ -16,13 +16,14 @@
|
|||
#pragma once
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "android-base/logging.h"
|
||||
#include "android/dlext.h"
|
||||
#include "log/log.h"
|
||||
#include "nativebridge/native_bridge.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
|
@ -31,34 +32,40 @@ namespace android {
|
|||
// x86). Instances of this class are managed by LibraryNamespaces object.
|
||||
struct NativeLoaderNamespace {
|
||||
public:
|
||||
NativeLoaderNamespace() : android_ns_(nullptr), native_bridge_ns_(nullptr) {}
|
||||
|
||||
explicit NativeLoaderNamespace(android_namespace_t* ns)
|
||||
: android_ns_(ns), native_bridge_ns_(nullptr) {}
|
||||
|
||||
explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
|
||||
: android_ns_(nullptr), native_bridge_ns_(ns) {}
|
||||
// TODO(return with errors)
|
||||
static NativeLoaderNamespace Create(const std::string& name, const std::string& search_paths,
|
||||
const std::string& permitted_paths,
|
||||
const NativeLoaderNamespace* parent, bool is_shared,
|
||||
bool is_greylist_enabled);
|
||||
|
||||
NativeLoaderNamespace(NativeLoaderNamespace&&) = default;
|
||||
NativeLoaderNamespace(const NativeLoaderNamespace&) = default;
|
||||
NativeLoaderNamespace& operator=(const NativeLoaderNamespace&) = default;
|
||||
|
||||
android_namespace_t* get_android_ns() const {
|
||||
CHECK(native_bridge_ns_ == nullptr);
|
||||
return android_ns_;
|
||||
android_namespace_t* ToRawAndroidNamespace() const { return std::get<0>(raw_); }
|
||||
native_bridge_namespace_t* ToRawNativeBridgeNamespace() const { return std::get<1>(raw_); }
|
||||
|
||||
std::string name() const { return name_; }
|
||||
bool IsBridged() const { return raw_.index() == 1; }
|
||||
bool IsNil() const {
|
||||
return IsBridged() ? std::get<1>(raw_) == nullptr : std::get<0>(raw_) == nullptr;
|
||||
}
|
||||
|
||||
native_bridge_namespace_t* get_native_bridge_ns() const {
|
||||
CHECK(android_ns_ == nullptr);
|
||||
return native_bridge_ns_;
|
||||
}
|
||||
bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const;
|
||||
void* Load(const std::string& lib_name) const;
|
||||
char* GetError() const;
|
||||
|
||||
bool is_android_namespace() const { return native_bridge_ns_ == nullptr; }
|
||||
static NativeLoaderNamespace GetExportedNamespace(const std::string& name, bool is_bridged);
|
||||
static NativeLoaderNamespace GetPlatformNamespace(bool is_bridged);
|
||||
|
||||
private:
|
||||
// Only one of them can be not null
|
||||
android_namespace_t* android_ns_;
|
||||
native_bridge_namespace_t* native_bridge_ns_;
|
||||
explicit NativeLoaderNamespace(const std::string& name, android_namespace_t* ns)
|
||||
: name_(name), raw_(ns) {}
|
||||
explicit NativeLoaderNamespace(const std::string& name, native_bridge_namespace_t* ns)
|
||||
: name_(name), raw_(ns) {}
|
||||
|
||||
std::string name_;
|
||||
std::variant<android_namespace_t*, native_bridge_namespace_t*> raw_;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
|
Loading…
Reference in New Issue