Merge "Fastdeploy converted to c++ and bin2c on the jar."
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index ac15ce4..2f0bf7d 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -1009,7 +1009,7 @@
Fstab candidates;
for (const auto& entry : fstab) {
FstabEntry new_entry = entry;
- if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
+ if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) ||
!fs_mgr_wants_overlayfs(&new_entry)) {
continue;
}
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 0ad8d9d..1d2683a 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -162,6 +162,24 @@
return DmDeviceState::SUSPENDED;
}
+bool DeviceMapper::ChangeState(const std::string& name, DmDeviceState state) {
+ if (state != DmDeviceState::SUSPENDED && state != DmDeviceState::ACTIVE) {
+ return false;
+ }
+
+ struct dm_ioctl io;
+ InitIo(&io, name);
+
+ if (state == DmDeviceState::SUSPENDED) io.flags = DM_SUSPEND_FLAG;
+
+ if (ioctl(fd_, DM_DEV_SUSPEND, &io) < 0) {
+ PLOG(ERROR) << "DM_DEV_SUSPEND "
+ << (state == DmDeviceState::SUSPENDED ? "suspend" : "resume") << " failed";
+ return false;
+ }
+ return true;
+}
+
bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
std::string ignore_path;
if (!CreateDevice(name, table, &ignore_path, 0ms)) {
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index b28a8f2..da1c4a9 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -166,6 +166,34 @@
ASSERT_TRUE(dev.Destroy());
}
+TEST(libdm, DmSuspendResume) {
+ unique_fd tmp1(CreateTempFile("file_suspend_resume", 512));
+ ASSERT_GE(tmp1, 0);
+
+ LoopDevice loop_a(tmp1, 10s);
+ ASSERT_TRUE(loop_a.valid());
+
+ DmTable table;
+ ASSERT_TRUE(table.Emplace<DmTargetLinear>(0, 1, loop_a.device(), 0));
+ ASSERT_TRUE(table.valid());
+
+ TempDevice dev("libdm-test-dm-suspend-resume", table);
+ ASSERT_TRUE(dev.valid());
+ ASSERT_FALSE(dev.path().empty());
+
+ auto& dm = DeviceMapper::Instance();
+
+ // Test Set and Get status of device.
+ vector<DeviceMapper::TargetInfo> targets;
+ ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::ACTIVE);
+
+ ASSERT_TRUE(dm.ChangeState(dev.name(), DmDeviceState::SUSPENDED));
+ ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::SUSPENDED);
+
+ ASSERT_TRUE(dm.ChangeState(dev.name(), DmDeviceState::ACTIVE));
+ ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::ACTIVE);
+}
+
TEST(libdm, DmVerityArgsAvb2) {
std::string device = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a";
std::string algorithm = "sha1";
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 9c0c2f3..753b8c9 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -79,6 +79,11 @@
// One of INVALID, SUSPENDED or ACTIVE.
DmDeviceState GetState(const std::string& name) const;
+ // Puts the given device to the specified status, which must be either:
+ // - SUSPENDED: suspend the device, or
+ // - ACTIVE: resumes the device.
+ bool ChangeState(const std::string& name, DmDeviceState state);
+
// Creates a device, loads the given table, and activates it. If the device
// is not able to be activated, it is destroyed, and false is returned.
// After creation, |path| contains the result of calling
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index c12e3b2..8797ea9 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -1060,7 +1060,7 @@
if (sRetrofitDap.has_value()) {
return *sRetrofitDap;
}
- return !android::base::GetBoolProperty("ro.boot.dynamic_partitions_retrofit", false);
+ return android::base::GetBoolProperty("ro.boot.dynamic_partitions_retrofit", false);
}
bool MetadataBuilder::IsRetrofitMetadata() const {
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 7e6ad5b..d6fb006 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -50,6 +50,8 @@
std::cerr << " list <devices | targets> [-v]" << std::endl;
std::cerr << " getpath <dm-name>" << std::endl;
std::cerr << " status <dm-name>" << std::endl;
+ std::cerr << " resume <dm-name>" << std::endl;
+ std::cerr << " suspend <dm-name>" << std::endl;
std::cerr << " table <dm-name>" << std::endl;
std::cerr << " help" << std::endl;
std::cerr << std::endl;
@@ -399,6 +401,34 @@
return DumpTable("status", argc, argv);
}
+static int ResumeCmdHandler(int argc, char** argv) {
+ if (argc != 1) {
+ std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
+ return -EINVAL;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ if (!dm.ChangeState(argv[0], DmDeviceState::ACTIVE)) {
+ std::cerr << "Could not resume device \"" << argv[0] << "\"." << std::endl;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int SuspendCmdHandler(int argc, char** argv) {
+ if (argc != 1) {
+ std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
+ return -EINVAL;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ if (!dm.ChangeState(argv[0], DmDeviceState::SUSPENDED)) {
+ std::cerr << "Could not suspend device \"" << argv[0] << "\"." << std::endl;
+ return -EINVAL;
+ }
+ return 0;
+}
+
static std::map<std::string, std::function<int(int, char**)>> cmdmap = {
// clang-format off
{"create", DmCreateCmdHandler},
@@ -408,6 +438,8 @@
{"getpath", GetPathCmdHandler},
{"table", TableCmdHandler},
{"status", StatusCmdHandler},
+ {"resume", ResumeCmdHandler},
+ {"suspend", SuspendCmdHandler},
// clang-format on
};
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index c22ce8a..a9eea8c 100644
--- a/libnativeloader/library_namespaces.cpp
+++ b/libnativeloader/library_namespaces.cpp
@@ -33,6 +33,8 @@
#include "public_libraries.h"
#include "utils.h"
+using android::base::Error;
+
namespace android::nativeloader {
namespace {
@@ -128,11 +130,11 @@
}
}
-NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
- jobject class_loader, bool is_shared,
- jstring dex_path, jstring java_library_path,
- jstring java_permitted_path,
- std::string* error_msg) {
+Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
+ jobject class_loader, bool is_shared,
+ jstring dex_path,
+ jstring java_library_path,
+ jstring java_permitted_path) {
std::string library_path; // empty string by default.
if (java_library_path != nullptr) {
@@ -158,14 +160,14 @@
}
// Initialize the anonymous namespace with the first non-empty library path.
+ Result<void> ret;
if (!library_path.empty() && !initialized_ &&
- !InitPublicNamespace(library_path.c_str(), error_msg)) {
- return nullptr;
+ !(ret = InitPublicNamespace(library_path.c_str()))) {
+ return ret.error();
}
- bool found = FindNamespaceByClassLoader(env, class_loader);
-
- LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader");
+ LOG_ALWAYS_FATAL_IF(FindNamespaceByClassLoader(env, class_loader) != nullptr,
+ "There is already a namespace associated with this classloader");
std::string system_exposed_libraries = default_public_libraries();
const char* namespace_name = kClassloaderNamespaceName;
@@ -216,58 +218,66 @@
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;
+ if (!app_ns) {
+ return app_ns.error();
}
// ... and link to other namespaces to allow access to some public libraries
- bool is_bridged = app_ns.IsBridged();
+ 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;
+ if (!platform_ns) {
+ return platform_ns.error();
+ }
+
+ auto linked = app_ns->Link(*platform_ns, system_exposed_libraries);
+ if (!linked) {
+ return linked.error();
}
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;
+ if (runtime_ns) {
+ linked = app_ns->Link(*runtime_ns, runtime_public_libraries());
+ if (!linked) {
+ return linked.error();
}
}
// Give access to NNAPI libraries (apex-updated LLNDK library).
auto nnapi_ns =
NativeLoaderNamespace::GetExportedNamespace(kNeuralNetworksNamespaceName, is_bridged);
- if (!app_ns.Link(nnapi_ns, neuralnetworks_public_libraries())) {
- *error_msg = app_ns.GetError();
- return nullptr;
+ if (nnapi_ns) {
+ linked = app_ns->Link(*nnapi_ns, neuralnetworks_public_libraries());
+ if (!linked) {
+ return linked.error();
+ }
}
// 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;
+ if (vndk_ns) {
+ linked = app_ns->Link(*vndk_ns, vndksp_libraries());
+ if (!linked) {
+ return linked.error();
+ }
}
}
- // 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;
+ // when vendor_ns is not configured, link to the platform namespace
+ auto target_ns = vendor_ns ? vendor_ns : platform_ns;
+ if (target_ns) {
+ linked = app_ns->Link(*target_ns, vendor_public_libraries());
+ if (!linked) {
+ return linked.error();
+ }
}
}
- namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns));
+ namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), *app_ns));
return &(namespaces_.back().second);
}
@@ -285,7 +295,7 @@
return nullptr;
}
-bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::string* error_msg) {
+Result<void> LibraryNamespaces::InitPublicNamespace(const char* library_path) {
// Ask native bride if this apps library path should be handled by it
bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
@@ -296,8 +306,7 @@
initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(),
is_native_bridge ? nullptr : library_path);
if (!initialized_) {
- *error_msg = dlerror();
- return false;
+ return Error() << dlerror();
}
// and now initialize native bridge namespaces if necessary.
@@ -305,11 +314,11 @@
initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(),
is_native_bridge ? library_path : nullptr);
if (!initialized_) {
- *error_msg = NativeBridgeGetError();
+ return Error() << NativeBridgeGetError();
}
}
- return initialized_;
+ return {};
}
NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h
index 6e9a190..e54bc0a 100644
--- a/libnativeloader/library_namespaces.h
+++ b/libnativeloader/library_namespaces.h
@@ -25,10 +25,13 @@
#include <list>
#include <string>
+#include <android-base/result.h>
#include <jni.h>
namespace android::nativeloader {
+using android::base::Result;
+
// LibraryNamespaces is a singleton object that manages NativeLoaderNamespace
// objects for an app process. Its main job is to create (and configure) a new
// NativeLoaderNamespace object for a Java ClassLoader, and to find an existing
@@ -46,13 +49,13 @@
namespaces_.clear();
initialized_ = false;
}
- NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
- bool is_shared, jstring dex_path, jstring java_library_path,
- jstring java_permitted_path, std::string* error_msg);
+ Result<NativeLoaderNamespace*> Create(JNIEnv* env, uint32_t target_sdk_version,
+ jobject class_loader, bool is_shared, jstring dex_path,
+ jstring java_library_path, jstring java_permitted_path);
NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
private:
- bool InitPublicNamespace(const char* library_path, std::string* error_msg);
+ Result<void> InitPublicNamespace(const char* library_path);
NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
bool initialized_;
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 0c29324..6d3c057 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -92,12 +92,10 @@
jstring permitted_path) {
#if defined(__ANDROID__)
std::lock_guard<std::mutex> guard(g_namespaces_mutex);
-
- std::string error_msg;
- bool success = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
- library_path, permitted_path, &error_msg) != nullptr;
- if (!success) {
- return env->NewStringUTF(error_msg.c_str());
+ auto ns = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path,
+ library_path, permitted_path);
+ if (!ns) {
+ return env->NewStringUTF(ns.error().message().c_str());
}
#else
UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path);
@@ -139,11 +137,14 @@
if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
// This is the case where the classloader was not created by ApplicationLoaders
// In this case we create an isolated not-shared namespace for it.
- std::string create_error_msg;
- if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */,
- nullptr, library_path, nullptr, &create_error_msg)) == nullptr) {
- *error_msg = strdup(create_error_msg.c_str());
+ Result<NativeLoaderNamespace*> isolated_ns =
+ g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, nullptr,
+ library_path, nullptr);
+ if (!isolated_ns) {
+ *error_msg = strdup(isolated_ns.error().message().c_str());
return nullptr;
+ } else {
+ ns = *isolated_ns;
}
}
@@ -222,12 +223,14 @@
#if defined(__ANDROID__)
void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
bool* needs_native_bridge, char** error_msg) {
- void* handle = ns->Load(path);
- if (handle == nullptr) {
- *error_msg = ns->GetError();
+ auto handle = ns->Load(path);
+ if (!handle && error_msg != nullptr) {
+ *error_msg = strdup(handle.error().message().c_str());
}
- *needs_native_bridge = ns->IsBridged();
- return handle;
+ if (needs_native_bridge != nullptr) {
+ *needs_native_bridge = ns->IsBridged();
+ }
+ return handle ? *handle : nullptr;
}
// native_bridge_namespaces are not supported for callers of this function.
diff --git a/libnativeloader/native_loader_namespace.cpp b/libnativeloader/native_loader_namespace.cpp
index 58ac686..4b02116 100644
--- a/libnativeloader/native_loader_namespace.cpp
+++ b/libnativeloader/native_loader_namespace.cpp
@@ -28,6 +28,9 @@
#include "nativeloader/dlext_namespaces.h"
+using android::base::Error;
+using android::base::Errorf;
+
namespace android {
namespace {
@@ -35,41 +38,46 @@
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()));
+std::string GetLinkerError(bool is_bridged) {
+ const char* msg = is_bridged ? NativeBridgeGetError() : dlerror();
+ if (msg == nullptr) {
+ return "no error";
}
+ return std::string(msg);
}
-char* NativeLoaderNamespace::GetError() const {
- if (!IsBridged()) {
- return strdup(dlerror());
+} // namespace
+
+Result<NativeLoaderNamespace> NativeLoaderNamespace::GetExportedNamespace(const std::string& name,
+ bool is_bridged) {
+ if (!is_bridged) {
+ auto raw = android_get_exported_namespace(name.c_str());
+ if (raw != nullptr) {
+ return NativeLoaderNamespace(name, raw);
+ }
} else {
- return strdup(NativeBridgeGetError());
+ auto raw = NativeBridgeGetExportedNamespace(name.c_str());
+ if (raw != nullptr) {
+ return NativeLoaderNamespace(name, raw);
+ }
}
+ return Errorf("namespace {} does not exist or exported", name);
}
// 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()) {
+Result<NativeLoaderNamespace> NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) {
+ auto ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged);
+ if (!ns) {
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) {
+Result<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();
@@ -78,8 +86,11 @@
}
// Fall back to the platform namespace if no parent is set.
- const NativeLoaderNamespace& effective_parent =
- parent != nullptr ? *parent : GetPlatformNamespace(is_bridged);
+ auto platform_ns = GetPlatformNamespace(is_bridged);
+ if (!platform_ns) {
+ return platform_ns.error();
+ }
+ const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *platform_ns;
uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;
if (is_shared) {
@@ -93,37 +104,56 @@
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);
+ if (raw != nullptr) {
+ 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);
+ if (raw != nullptr) {
+ return NativeLoaderNamespace(name, raw);
+ }
}
+ return Errorf("failed to create {} namespace name:{}, search_paths:{}, permitted_paths:{}",
+ is_bridged ? "bridged" : "native", name, search_paths, permitted_paths);
}
-bool NativeLoaderNamespace::Link(const NativeLoaderNamespace& target,
- const std::string& shared_libs) const {
+Result<void> 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());
+ if (android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(),
+ shared_libs.c_str())) {
+ return {};
+ }
} else {
- return NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(),
- target.ToRawNativeBridgeNamespace(), shared_libs.c_str());
+ if (NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(),
+ target.ToRawNativeBridgeNamespace(), shared_libs.c_str())) {
+ return {};
+ }
}
+ return Error() << GetLinkerError(IsBridged());
}
-void* NativeLoaderNamespace::Load(const char* lib_name) const {
+Result<void*> NativeLoaderNamespace::Load(const char* 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, RTLD_NOW, &extinfo);
+ void* handle = android_dlopen_ext(lib_name, RTLD_NOW, &extinfo);
+ if (handle != nullptr) {
+ return handle;
+ }
} else {
- return NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace());
+ void* handle =
+ NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace());
+ if (handle != nullptr) {
+ return handle;
+ }
}
+ return Error() << GetLinkerError(IsBridged());
}
} // namespace android
diff --git a/libnativeloader/native_loader_namespace.h b/libnativeloader/native_loader_namespace.h
index 71e4247..29b759c 100644
--- a/libnativeloader/native_loader_namespace.h
+++ b/libnativeloader/native_loader_namespace.h
@@ -21,22 +21,25 @@
#include <vector>
#include <android-base/logging.h>
+#include <android-base/result.h>
#include <android/dlext.h>
#include <log/log.h>
#include <nativebridge/native_bridge.h>
namespace android {
+using android::base::Result;
+
// NativeLoaderNamespace abstracts a linker namespace for the native
// architecture (ex: arm on arm) or the translated architecture (ex: arm on
// x86). Instances of this class are managed by LibraryNamespaces object.
struct NativeLoaderNamespace {
public:
- // 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);
+ static Result<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;
@@ -47,16 +50,13 @@
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;
- }
- bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const;
- void* Load(const char* lib_name) const;
- char* GetError() const;
+ Result<void> Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const;
+ Result<void*> Load(const char* lib_name) const;
- static NativeLoaderNamespace GetExportedNamespace(const std::string& name, bool is_bridged);
- static NativeLoaderNamespace GetPlatformNamespace(bool is_bridged);
+ static Result<NativeLoaderNamespace> GetExportedNamespace(const std::string& name,
+ bool is_bridged);
+ static Result<NativeLoaderNamespace> GetPlatformNamespace(bool is_bridged);
private:
explicit NativeLoaderNamespace(const std::string& name, android_namespace_t* ns)
diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp
index 10e23fd..6cee668 100644
--- a/libnativeloader/public_libraries.cpp
+++ b/libnativeloader/public_libraries.cpp
@@ -26,6 +26,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/result.h>
#include <android-base/strings.h>
#include <log/log.h>
@@ -34,6 +35,9 @@
namespace android::nativeloader {
using namespace std::string_literals;
+using android::base::ErrnoError;
+using android::base::Errorf;
+using android::base::Result;
namespace {
@@ -91,22 +95,21 @@
file_name->insert(insert_pos, vndk_version_str());
}
-const std::function<bool(const std::string&, std::string*)> always_true =
- [](const std::string&, std::string*) { return true; };
+const std::function<Result<void>(const std::string&)> always_true =
+ [](const std::string&) -> Result<void> { return {}; };
-bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
- const std::function<bool(const std::string& /* soname */,
- std::string* /* error_msg */)>& check_soname,
- std::string* error_msg = nullptr) {
+Result<std::vector<std::string>> ReadConfig(
+ const std::string& configFile,
+ const std::function<Result<void>(const std::string& /* soname */)>& check_soname) {
// Read list of public native libraries from the config file.
std::string file_content;
if (!base::ReadFileToString(configFile, &file_content)) {
- if (error_msg) *error_msg = strerror(errno);
- return false;
+ return ErrnoError();
}
std::vector<std::string> lines = base::Split(file_content, "\n");
+ std::vector<std::string> sonames;
for (auto& line : lines) {
auto trimmed_line = base::Trim(line);
if (trimmed_line[0] == '#' || trimmed_line.empty()) {
@@ -116,8 +119,7 @@
if (space_pos != std::string::npos) {
std::string type = trimmed_line.substr(space_pos + 1);
if (type != "32" && type != "64") {
- if (error_msg) *error_msg = "Malformed line: " + line;
- return false;
+ return Errorf("Malformed line: {}", line);
}
#if defined(__LP64__)
// Skip 32 bit public library.
@@ -133,13 +135,13 @@
trimmed_line.resize(space_pos);
}
- if (check_soname(trimmed_line, error_msg)) {
- sonames->push_back(trimmed_line);
- } else {
- return false;
+ auto ret = check_soname(trimmed_line);
+ if (!ret) {
+ return ret.error();
}
+ sonames.push_back(trimmed_line);
}
- return true;
+ return sonames;
}
void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
@@ -162,24 +164,22 @@
"Error extracting company name from public native library list file path \"%s\"",
config_file_path.c_str());
- std::string error_msg;
-
- LOG_ALWAYS_FATAL_IF(
- !ReadConfig(config_file_path, sonames,
- [&company_name](const std::string& soname, std::string* error_msg) {
- if (android::base::StartsWith(soname, "lib") &&
- android::base::EndsWith(soname, "." + company_name + ".so")) {
- return true;
- } else {
- *error_msg = "Library name \"" + soname +
- "\" does not end with the company name: " + company_name +
- ".";
- return false;
- }
- },
- &error_msg),
- "Error reading public native library list from \"%s\": %s", config_file_path.c_str(),
- error_msg.c_str());
+ auto ret = ReadConfig(
+ config_file_path, [&company_name](const std::string& soname) -> Result<void> {
+ if (android::base::StartsWith(soname, "lib") &&
+ android::base::EndsWith(soname, "." + company_name + ".so")) {
+ return {};
+ } else {
+ return Errorf("Library name \"{}\" does not end with the company name {}.", soname,
+ company_name);
+ }
+ });
+ if (ret) {
+ sonames->insert(sonames->end(), ret->begin(), ret->end());
+ } else {
+ LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
+ config_file_path.c_str(), ret.error().message().c_str());
+ }
}
}
}
@@ -187,16 +187,17 @@
static std::string InitDefaultPublicLibraries() {
std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
- std::vector<std::string> sonames;
- std::string error_msg;
- LOG_ALWAYS_FATAL_IF(!ReadConfig(config_file, &sonames, always_true, &error_msg),
- "Error reading public native library list from \"%s\": %s",
- config_file.c_str(), error_msg.c_str());
+ auto sonames = ReadConfig(config_file, always_true);
+ if (!sonames) {
+ LOG_ALWAYS_FATAL("Error reading public native library list from \"%s\": %s",
+ config_file.c_str(), sonames.error().message().c_str());
+ return "";
+ }
std::string additional_libs = additional_public_libraries();
if (!additional_libs.empty()) {
auto vec = base::Split(additional_libs, ":");
- std::copy(vec.begin(), vec.end(), std::back_inserter(sonames));
+ std::copy(vec.begin(), vec.end(), std::back_inserter(*sonames));
}
// Remove the public libs in the runtime namespace.
@@ -216,18 +217,18 @@
continue;
}
- auto it = std::find(sonames.begin(), sonames.end(), lib_name);
- if (it != sonames.end()) {
- sonames.erase(it);
+ auto it = std::find(sonames->begin(), sonames->end(), lib_name);
+ if (it != sonames->end()) {
+ sonames->erase(it);
}
}
// Remove the public libs in the nnapi namespace.
- auto it = std::find(sonames.begin(), sonames.end(), kNeuralNetworksApexPublicLibrary);
- if (it != sonames.end()) {
- sonames.erase(it);
+ auto it = std::find(sonames->begin(), sonames->end(), kNeuralNetworksApexPublicLibrary);
+ if (it != sonames->end()) {
+ sonames->erase(it);
}
- return android::base::Join(sonames, ':');
+ return android::base::Join(*sonames, ':');
}
static std::string InitRuntimePublicLibraries() {
@@ -243,9 +244,11 @@
static std::string InitVendorPublicLibraries() {
// This file is optional, quietly ignore if the file does not exist.
- std::vector<std::string> sonames;
- ReadConfig(kVendorPublicLibrariesFile, &sonames, always_true, nullptr);
- return android::base::Join(sonames, ':');
+ auto sonames = ReadConfig(kVendorPublicLibrariesFile, always_true);
+ if (!sonames) {
+ return "";
+ }
+ return android::base::Join(*sonames, ':');
}
// read /system/etc/public.libraries-<companyname>.txt and
@@ -262,17 +265,23 @@
static std::string InitLlndkLibraries() {
std::string config_file = kLlndkLibrariesFile;
InsertVndkVersionStr(&config_file);
- std::vector<std::string> sonames;
- ReadConfig(config_file, &sonames, always_true, nullptr);
- return android::base::Join(sonames, ':');
+ auto sonames = ReadConfig(config_file, always_true);
+ if (!sonames) {
+ LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
+ return "";
+ }
+ return android::base::Join(*sonames, ':');
}
static std::string InitVndkspLibraries() {
std::string config_file = kVndkLibrariesFile;
InsertVndkVersionStr(&config_file);
- std::vector<std::string> sonames;
- ReadConfig(config_file, &sonames, always_true, nullptr);
- return android::base::Join(sonames, ':');
+ auto sonames = ReadConfig(config_file, always_true);
+ if (!sonames) {
+ LOG_ALWAYS_FATAL("%s", sonames.error().message().c_str());
+ return "";
+ }
+ return android::base::Join(*sonames, ':');
}
static std::string InitNeuralNetworksPublicLibraries() {