Auto-load native libraries of a module (reland)
This gets rid of the whitelist in Module.java. Going forward DFM authors
simply have to specify native_deps in the module_desc and the native
library will be automatically loaded when first accessing the module
(when using the autogenerated module class).
See go/native-dfm-load-v2 for more context and details.
This is a reland of 06c7b1cdbba6a581ef5f0fbd2712a9d0799d6acc No changes
have been made. 06c7b1cdbba6a581ef5f0fbd2712a9d0799d6acc was reverted
due to the revert of a9dcd64a13a3b0c0522f6fbd26e079e4874869b7 and that
CL has been fixed in c9901c6af04f9ee9e176e4a4b8c130c1998b8a58.
TBR: [email protected],[email protected]
Bug: 870055
Change-Id: Ib7939f43f2e3ca758c8ab039f91d6f78b6d84f22
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1891434
Reviewed-by: Tibor Goldschwendt <[email protected]>
Reviewed-by: Christopher Grant <[email protected]>
Cr-Commit-Position: refs/heads/master@{#711460}
diff --git a/chrome/android/chrome_common_shared_library.gni b/chrome/android/chrome_common_shared_library.gni
index cd407251..0927f56 100644
--- a/chrome/android/chrome_common_shared_library.gni
+++ b/chrome/android/chrome_common_shared_library.gni
@@ -49,8 +49,8 @@
generate_linker_version_script(_linker_script_target) {
linker_script = _linker_script
export_java_symbols = _export_java_symbols
+ export_feature_registrations = true
if (_generate_partitions) {
- export_feature_registrations = true
export_symbol_whitelist_files = []
foreach(_module_desc, invoker.module_descs) {
if (defined(_module_desc.native_entrypoints)) {
diff --git a/chrome/android/features/vr/vr_module.gni b/chrome/android/features/vr/vr_module.gni
index 5548640..87d57532 100644
--- a/chrome/android/features/vr/vr_module.gni
+++ b/chrome/android/features/vr/vr_module.gni
@@ -11,8 +11,6 @@
name = "vr"
java_deps = [ "//chrome/android/features/vr:java" ]
android_manifest = "//chrome/android/features/vr/java/AndroidManifest.xml"
- if (use_native_partitions) {
- native_deps = [ "//chrome/browser/vr:vr_ui" ]
- native_entrypoints = "//chrome/browser/vr/module_exports.lst"
- }
+ native_deps = [ "//chrome/browser/vr:vr_ui" ]
+ native_entrypoints = "//chrome/browser/vr/module_exports.lst"
}
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 387034a0..8192a811 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -201,6 +201,10 @@
cflags = [ "-fsymbol-partition=libvr.so" ]
}
+ if (is_android) {
+ sources += [ "jni_onload.cc" ]
+ }
+
defines = [ "VR_UI_IMPLEMENTATION" ]
if (use_command_buffer) {
diff --git a/chrome/browser/vr/jni_onload.cc b/chrome/browser/vr/jni_onload.cc
new file mode 100644
index 0000000..817645352
--- /dev/null
+++ b/chrome/browser/vr/jni_onload.cc
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+// This method is required by the module loading backend. And it is supposed to
+// register VR's native JNI methods. However, since VR's Android-specific native
+// code still lives in the base module, VR's JNI registration is invoked
+// manually. Therefore, this function does nothing.
+JNI_GENERATOR_EXPORT bool JNI_OnLoad_vr(JNIEnv* env) {
+ return true;
+}
diff --git a/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java b/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
index c27bd09..33ec630 100644
--- a/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
+++ b/components/module_installer/android/java/src/org/chromium/components/module_installer/builder/Module.java
@@ -132,22 +132,18 @@
private static void loadNative(String name) {
// Can only initialize native once per lifetime of Chrome.
if (sInitializedModules.contains(name)) return;
- // TODO(crbug.com/870055): Use |libraries| instead of whitelist to load
- // native libraries.
String[] libraries = loadModuleDescriptor(name).getLibraries();
// TODO(crbug.com/986960): Automatically determine if module has native
// resources instead of whitelisting.
- boolean loadLibrary = false;
boolean loadResources = false;
if ("test_dummy".equals(name)) {
- loadLibrary = true;
loadResources = true;
}
if ("dev_ui".equals(name)) {
loadResources = true;
}
- if (loadLibrary || loadResources) {
- ModuleJni.get().loadNative(name, loadLibrary, loadResources);
+ if (libraries.length > 0 || loadResources) {
+ ModuleJni.get().loadNative(name, libraries, loadResources);
}
sInitializedModules.add(name);
}
@@ -195,6 +191,6 @@
@NativeMethods
interface Natives {
- void loadNative(String name, boolean loadLibrary, boolean loadResources);
+ void loadNative(String name, String[] libraries, boolean loadResources);
}
}
diff --git a/components/module_installer/android/module.cc b/components/module_installer/android/module.cc
index 73be75e..b51e91f 100644
--- a/components/module_installer/android/module.cc
+++ b/components/module_installer/android/module.cc
@@ -7,6 +7,7 @@
#include "base/android/bundle_utils.h"
#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
@@ -40,8 +41,8 @@
typedef bool JniRegistrationFunction(JNIEnv* env);
-void LoadLibrary(JNIEnv* env, const std::string& library_name) {
- JniRegistrationFunction* registration_function = nullptr;
+void* LoadLibrary(const std::string& library_name) {
+ void* library_handle = nullptr;
#if defined(LOAD_FROM_PARTITIONS)
// The partition library must be opened via native code (using
@@ -49,25 +50,28 @@
// operation on the Java side, because JNI registration is done explicitly
// (hence there is no reason for the Java ClassLoader to be aware of the
// library, for lazy JNI registration).
- void* library_handle =
- BundleUtils::DlOpenModuleLibraryPartition(library_name);
+ library_handle = BundleUtils::DlOpenModuleLibraryPartition(library_name);
#elif defined(COMPONENT_BUILD)
- const std::string lib_name = "lib" + library_name + ".cr.so";
- void* library_handle = dlopen(lib_name.c_str(), RTLD_LOCAL);
+ const std::string lib_name = "lib" + library_name + ".so";
+ library_handle = dlopen(lib_name.c_str(), RTLD_LOCAL);
#else
#error "Unsupported configuration."
#endif // defined(COMPONENT_BUILD)
CHECK(library_handle != nullptr)
- << "Could not open feature library:" << dlerror();
+ << "Could not open feature library: " << dlerror();
- const std::string registration_name = "JNI_OnLoad_" + library_name;
+ return library_handle;
+}
+
+void RegisterJni(JNIEnv* env, void* library_handle, const std::string& name) {
+ const std::string registration_name = "JNI_OnLoad_" + name;
// Find the module's JNI registration method from the feature library.
void* symbol = dlsym(library_handle, registration_name.c_str());
- CHECK(symbol != nullptr) << "Could not find JNI registration method: "
- << dlerror();
- registration_function = reinterpret_cast<JniRegistrationFunction*>(symbol);
- CHECK(registration_function(env))
- << "JNI registration failed: " << library_name;
+ CHECK(symbol) << "Could not find JNI registration method '"
+ << registration_name << "' for '" << name << "': " << dlerror();
+ auto* registration_function =
+ reinterpret_cast<JniRegistrationFunction*>(symbol);
+ CHECK(registration_function(env)) << "JNI registration failed: " << name;
}
void LoadResources(const std::string& name) {
@@ -80,12 +84,22 @@
static void JNI_Module_LoadNative(
JNIEnv* env,
const base::android::JavaParamRef<jstring>& jname,
- jboolean load_library,
+ const base::android::JavaParamRef<jobjectArray>& jlibraries,
jboolean load_resources) {
std::string name;
base::android::ConvertJavaStringToUTF8(env, jname, &name);
- if (load_library) {
- LoadLibrary(env, name);
+ std::vector<std::string> libraries;
+ base::android::AppendJavaStringArrayToStringVector(env, jlibraries,
+ &libraries);
+ if (libraries.size() > 0) {
+ void* library_handle = nullptr;
+ for (const auto& library : libraries) {
+ library_handle = LoadLibrary(library);
+ }
+ // module libraries are ordered such that the root library will be the last
+ // item in the list. We expect this library to provide the JNI registration
+ // function.
+ RegisterJni(env, library_handle, name);
}
if (load_resources) {
LoadResources(name);