Commit 06c7b1cd authored by Tibor Goldschwendt's avatar Tibor Goldschwendt Committed by Commit Bot

Auto-load native libraries of a module

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.

Change-Id: I5bd30c2e8a6cfa3afeb4b69c348cdab0e304d597
Bug: 870055
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1877250Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarChristopher Grant <cjgrant@chromium.org>
Commit-Queue: Tibor Goldschwendt <tiborg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709277}
parent d40b01f4
...@@ -45,8 +45,8 @@ template("chrome_common_shared_library") { ...@@ -45,8 +45,8 @@ template("chrome_common_shared_library") {
generate_linker_version_script(_linker_script_target) { generate_linker_version_script(_linker_script_target) {
linker_script = _linker_script linker_script = _linker_script
export_java_symbols = _export_java_symbols export_java_symbols = _export_java_symbols
export_feature_registrations = true
if (_generate_partitions) { if (_generate_partitions) {
export_feature_registrations = true
export_symbol_whitelist_files = [] export_symbol_whitelist_files = []
foreach(_module_desc, invoker.module_descs) { foreach(_module_desc, invoker.module_descs) {
if (defined(_module_desc.native_entrypoints)) { if (defined(_module_desc.native_entrypoints)) {
......
...@@ -11,8 +11,6 @@ vr_module_desc = { ...@@ -11,8 +11,6 @@ vr_module_desc = {
name = "vr" name = "vr"
java_deps = [ "//chrome/android/features/vr:java" ] java_deps = [ "//chrome/android/features/vr:java" ]
android_manifest = "//chrome/android/features/vr/java/AndroidManifest.xml" android_manifest = "//chrome/android/features/vr/java/AndroidManifest.xml"
if (use_native_partitions) { native_deps = [ "//chrome/browser/vr:vr_ui" ]
native_deps = [ "//chrome/browser/vr:vr_ui" ] native_entrypoints = "//chrome/browser/vr/module_exports.lst"
native_entrypoints = "//chrome/browser/vr/module_exports.lst"
}
} }
...@@ -201,6 +201,10 @@ component("vr_ui") { ...@@ -201,6 +201,10 @@ component("vr_ui") {
cflags = [ "-fsymbol-partition=libvr.so" ] cflags = [ "-fsymbol-partition=libvr.so" ]
} }
if (is_android) {
sources += [ "jni_onload.cc" ]
}
defines = [ "VR_UI_IMPLEMENTATION" ] defines = [ "VR_UI_IMPLEMENTATION" ]
if (use_command_buffer) { if (use_command_buffer) {
......
// 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;
}
...@@ -132,22 +132,18 @@ public class Module<T> { ...@@ -132,22 +132,18 @@ public class Module<T> {
private static void loadNative(String name) { private static void loadNative(String name) {
// Can only initialize native once per lifetime of Chrome. // Can only initialize native once per lifetime of Chrome.
if (sInitializedModules.contains(name)) return; if (sInitializedModules.contains(name)) return;
// TODO(crbug.com/870055): Use |libraries| instead of whitelist to load
// native libraries.
String[] libraries = loadModuleDescriptor(name).getLibraries(); String[] libraries = loadModuleDescriptor(name).getLibraries();
// TODO(crbug.com/986960): Automatically determine if module has native // TODO(crbug.com/986960): Automatically determine if module has native
// resources instead of whitelisting. // resources instead of whitelisting.
boolean loadLibrary = false;
boolean loadResources = false; boolean loadResources = false;
if ("test_dummy".equals(name)) { if ("test_dummy".equals(name)) {
loadLibrary = true;
loadResources = true; loadResources = true;
} }
if ("dev_ui".equals(name)) { if ("dev_ui".equals(name)) {
loadResources = true; loadResources = true;
} }
if (loadLibrary || loadResources) { if (libraries.length > 0 || loadResources) {
ModuleJni.get().loadNative(name, loadLibrary, loadResources); ModuleJni.get().loadNative(name, libraries, loadResources);
} }
sInitializedModules.add(name); sInitializedModules.add(name);
} }
...@@ -195,6 +191,6 @@ public class Module<T> { ...@@ -195,6 +191,6 @@ public class Module<T> {
@NativeMethods @NativeMethods
interface Natives { interface Natives {
void loadNative(String name, boolean loadLibrary, boolean loadResources); void loadNative(String name, String[] libraries, boolean loadResources);
} }
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/android/bundle_utils.h" #include "base/android/bundle_utils.h"
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
...@@ -40,8 +41,8 @@ namespace { ...@@ -40,8 +41,8 @@ namespace {
typedef bool JniRegistrationFunction(JNIEnv* env); typedef bool JniRegistrationFunction(JNIEnv* env);
void LoadLibrary(JNIEnv* env, const std::string& library_name) { void* LoadLibrary(const std::string& library_name) {
JniRegistrationFunction* registration_function = nullptr; void* library_handle = nullptr;
#if defined(LOAD_FROM_PARTITIONS) #if defined(LOAD_FROM_PARTITIONS)
// The partition library must be opened via native code (using // The partition library must be opened via native code (using
...@@ -49,25 +50,28 @@ void LoadLibrary(JNIEnv* env, const std::string& library_name) { ...@@ -49,25 +50,28 @@ void LoadLibrary(JNIEnv* env, const std::string& library_name) {
// operation on the Java side, because JNI registration is done explicitly // 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 // (hence there is no reason for the Java ClassLoader to be aware of the
// library, for lazy JNI registration). // library, for lazy JNI registration).
void* library_handle = library_handle = BundleUtils::DlOpenModuleLibraryPartition(library_name);
BundleUtils::DlOpenModuleLibraryPartition(library_name);
#elif defined(COMPONENT_BUILD) #elif defined(COMPONENT_BUILD)
const std::string lib_name = "lib" + library_name + ".cr.so"; const std::string lib_name = "lib" + library_name + ".so";
void* library_handle = dlopen(lib_name.c_str(), RTLD_LOCAL); library_handle = dlopen(lib_name.c_str(), RTLD_LOCAL);
#else #else
#error "Unsupported configuration." #error "Unsupported configuration."
#endif // defined(COMPONENT_BUILD) #endif // defined(COMPONENT_BUILD)
CHECK(library_handle != nullptr) 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. // Find the module's JNI registration method from the feature library.
void* symbol = dlsym(library_handle, registration_name.c_str()); void* symbol = dlsym(library_handle, registration_name.c_str());
CHECK(symbol != nullptr) << "Could not find JNI registration method: " CHECK(symbol) << "Could not find JNI registration method '"
<< dlerror(); << registration_name << "' for '" << name << "': " << dlerror();
registration_function = reinterpret_cast<JniRegistrationFunction*>(symbol); auto* registration_function =
CHECK(registration_function(env)) reinterpret_cast<JniRegistrationFunction*>(symbol);
<< "JNI registration failed: " << library_name; CHECK(registration_function(env)) << "JNI registration failed: " << name;
} }
void LoadResources(const std::string& name) { void LoadResources(const std::string& name) {
...@@ -80,12 +84,22 @@ void LoadResources(const std::string& name) { ...@@ -80,12 +84,22 @@ void LoadResources(const std::string& name) {
static void JNI_Module_LoadNative( static void JNI_Module_LoadNative(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jstring>& jname, const base::android::JavaParamRef<jstring>& jname,
jboolean load_library, const base::android::JavaParamRef<jobjectArray>& jlibraries,
jboolean load_resources) { jboolean load_resources) {
std::string name; std::string name;
base::android::ConvertJavaStringToUTF8(env, jname, &name); base::android::ConvertJavaStringToUTF8(env, jname, &name);
if (load_library) { std::vector<std::string> libraries;
LoadLibrary(env, name); 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) { if (load_resources) {
LoadResources(name); LoadResources(name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment