Commit 9e6f2f40 authored by Tibor Goldschwendt's avatar Tibor Goldschwendt Committed by Commit Bot

Reland "Add native resource to dummy module and test loading in smoke test"

This is a reland of d205c616

Original change's description:
> Add native resource to dummy module and test loading in smoke test
>
> * Adds a new PAK file with a dummy resources.
> * Refactors the TestDummyModuleProvider to to synchronously load the
>   module PAK file when retrieving the impl.
> * Adds a friend to ScopedAllowBlocking in order to be able to memory
>   map the module PAK file on the main thread.
>
> Change-Id: I0a3b949b83b37a7089aa410a691de6ae28f9a36a
> Bug: 989646
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1822847
> Auto-Submit: Tibor Goldschwendt <tiborg@chromium.org>
> Reviewed-by: Theresa  <twellington@chromium.org>
> Reviewed-by: Christopher Grant <cjgrant@chromium.org>
> Reviewed-by: Daniel Cheng <dcheng@chromium.org>
> Reviewed-by: Andrew Grieve <agrieve@chromium.org>
> Reviewed-by: Samuel Huang <huangs@chromium.org>
> Reviewed-by: Fred Mello <fredmello@chromium.org>
> Commit-Queue: Tibor Goldschwendt <tiborg@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#702423}

TBR=twellington@chromium.org,cjgrant@chromium.org,dcheng@chromium.org,agrieve@chromium.org,huangs@chromium.org,fredmello@chromium.org

Bug: 989646
Change-Id: Ifab13d56aead63532ab57000e7253d0ce89f75b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1837485Reviewed-by: default avatarTibor Goldschwendt <tiborg@chromium.org>
Commit-Queue: Tibor Goldschwendt <tiborg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702497}
parent 598b7fb9
...@@ -194,6 +194,9 @@ class OSMetrics; ...@@ -194,6 +194,9 @@ class OSMetrics;
namespace midi { namespace midi {
class TaskService; // https://crbug.com/796830 class TaskService; // https://crbug.com/796830
} }
namespace module_installer {
class ScopedAllowModulePakLoad;
}
namespace mojo { namespace mojo {
class CoreLibraryInitializer; class CoreLibraryInitializer;
class SyncCallRestrictions; class SyncCallRestrictions;
...@@ -347,6 +350,7 @@ class BASE_EXPORT ScopedAllowBlocking { ...@@ -347,6 +350,7 @@ class BASE_EXPORT ScopedAllowBlocking {
friend class cronet::CronetPrefsManager; friend class cronet::CronetPrefsManager;
friend class cronet::CronetURLRequestContext; friend class cronet::CronetURLRequestContext;
friend class memory_instrumentation::OSMetrics; friend class memory_instrumentation::OSMetrics;
friend class module_installer::ScopedAllowModulePakLoad;
friend class mojo::CoreLibraryInitializer; friend class mojo::CoreLibraryInitializer;
friend class resource_coordinator::TabManagerDelegate; // crbug.com/778703 friend class resource_coordinator::TabManagerDelegate; // crbug.com/778703
friend class ui::MaterialDesignController; friend class ui::MaterialDesignController;
......
...@@ -1745,6 +1745,7 @@ if (is_android) { ...@@ -1745,6 +1745,7 @@ if (is_android) {
] ]
deps = [ deps = [
"//chrome/android/modules/test_dummy/provider:native",
"//chrome/browser/ui", "//chrome/browser/ui",
"//chrome/child", "//chrome/child",
"//chrome/common", "//chrome/common",
......
include_rules = [
"+chrome/grit",
]
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import("//build/buildflag_header.gni") import("//build/buildflag_header.gni")
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
import("//chrome/android/modules/buildflags.gni") import("//chrome/android/modules/buildflags.gni")
import("//tools/grit/grit_rule.gni")
android_resources("java_resources") { android_resources("java_resources") {
resource_dirs = [ "java/res" ] resource_dirs = [ "java/res" ]
...@@ -34,7 +35,9 @@ source_set("native") { ...@@ -34,7 +35,9 @@ source_set("native") {
deps = [ deps = [
":jni_headers", ":jni_headers",
":resources_native",
"//base", "//base",
"//ui/base",
] ]
} }
...@@ -46,7 +49,9 @@ source_set("native") { ...@@ -46,7 +49,9 @@ source_set("native") {
android_library("base_module_java") { android_library("base_module_java") {
deps = [ deps = [
"//base:base_java", "//base:base_java",
"//chrome/android/features/test_dummy/public:java",
"//chrome/android/modules/test_dummy/provider:java", "//chrome/android/modules/test_dummy/provider:java",
"//chrome/android/modules/test_dummy/public:java",
"//third_party/android_deps:android_support_v7_appcompat_java", "//third_party/android_deps:android_support_v7_appcompat_java",
] ]
java_files = [ java_files = [
...@@ -59,3 +64,15 @@ generate_jni("jni_headers") { ...@@ -59,3 +64,15 @@ generate_jni("jni_headers") {
"java/src/org/chromium/chrome/features/test_dummy/TestDummyImpl.java", "java/src/org/chromium/chrome/features/test_dummy/TestDummyImpl.java",
] ]
} }
# Cannot call this just "resources" since all targets with that name in
# //chrome/android need a build_config, which grit targets don't have.
grit("resources_native") {
source = "resources/resources.grd"
outputs = [
"grit/test_dummy_resources.h",
"test_dummy_resources.pak",
]
output_dir = "$root_gen_dir/chrome"
depfile_dir = target_gen_dir
}
...@@ -20,6 +20,15 @@ public class TestDummyActivity extends AppCompatActivity { ...@@ -20,6 +20,15 @@ public class TestDummyActivity extends AppCompatActivity {
finish(); finish();
return; return;
} }
TestDummyModuleProvider.launchTestDummy(getIntent(), this); if (!TestDummyModuleProvider.isModuleInstalled()) {
TestDummyModuleProvider.installModule(this::onModuleInstalled);
return;
}
onModuleInstalled(true);
}
private void onModuleInstalled(boolean success) {
if (!success) throw new RuntimeException("Failed to install module");
TestDummyModuleProvider.getTestDummyProvider().getTestDummy().launch(getIntent(), this);
} }
} }
...@@ -29,6 +29,7 @@ public class TestDummyImpl implements TestDummy { ...@@ -29,6 +29,7 @@ public class TestDummyImpl implements TestDummy {
int EXECUTE_JAVA = 0; int EXECUTE_JAVA = 0;
int EXECUTE_NATIVE = 1; int EXECUTE_NATIVE = 1;
int LOAD_JAVA_RESOURCE = 2; int LOAD_JAVA_RESOURCE = 2;
int LOAD_NATIVE_RESOURCE = 3;
} }
@Override @Override
...@@ -45,6 +46,9 @@ public class TestDummyImpl implements TestDummy { ...@@ -45,6 +46,9 @@ public class TestDummyImpl implements TestDummy {
case TestCase.LOAD_JAVA_RESOURCE: case TestCase.LOAD_JAVA_RESOURCE:
loadJavaResource(activity); loadJavaResource(activity);
break; break;
case TestCase.LOAD_NATIVE_RESOURCE:
loadNativeResource(activity);
break;
default: default:
throw new RuntimeException("Unknown test case " + testCase); throw new RuntimeException("Unknown test case " + testCase);
} }
...@@ -53,6 +57,7 @@ public class TestDummyImpl implements TestDummy { ...@@ -53,6 +57,7 @@ public class TestDummyImpl implements TestDummy {
@NativeMethods @NativeMethods
interface Natives { interface Natives {
int execute(); int execute();
String loadResource();
} }
private void showDoneDialog(Activity activity, @TestCase int testCase, boolean pass) { private void showDoneDialog(Activity activity, @TestCase int testCase, boolean pass) {
...@@ -94,4 +99,9 @@ public class TestDummyImpl implements TestDummy { ...@@ -94,4 +99,9 @@ public class TestDummyImpl implements TestDummy {
} }
showDoneDialog(activity, TestCase.LOAD_JAVA_RESOURCE, result); showDoneDialog(activity, TestCase.LOAD_JAVA_RESOURCE, result);
} }
private void loadNativeResource(Activity activity) {
boolean result = TestDummyImplJni.get().loadResource().equals("Hello, World!");
showDoneDialog(activity, TestCase.LOAD_NATIVE_RESOURCE, result);
}
} }
<?xml version="1.0" encoding="UTF-8"?>
<grit latest_public_release="0"
current_release="1"
output_all_resource_defines="false">
<outputs>
<output filename="grit/test_dummy_resources.h"
type="rc_header">
<emit emit_type='prepend'></emit>
</output>
<output filename="test_dummy_resources.pak"
type="data_package" />
</outputs>
<release seq="1">
<includes>
<include name="IDR_TEST_DUMMY_TEST_RESOURCE"
file="test_resource.txt"
type="BINDATA" />
</includes>
</release>
</grit>
...@@ -2,10 +2,21 @@ ...@@ -2,10 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/android/jni_string.h"
#include "base/logging.h" #include "base/logging.h"
#include "chrome/android/features/test_dummy/internal/jni_headers/TestDummyImpl_jni.h" #include "chrome/android/features/test_dummy/internal/jni_headers/TestDummyImpl_jni.h"
#include "chrome/grit/test_dummy_resources.h"
#include "ui/base/resource/resource_bundle.h"
static int JNI_TestDummyImpl_Execute(JNIEnv* env) { static int JNI_TestDummyImpl_Execute(JNIEnv* env) {
LOG(INFO) << "Running test dummy native library"; LOG(INFO) << "Running test dummy native library";
return 123; return 123;
} }
static base::android::ScopedJavaLocalRef<jstring>
JNI_TestDummyImpl_LoadResource(JNIEnv* env) {
auto resource = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
IDR_TEST_DUMMY_TEST_RESOURCE);
LOG(INFO) << "Loading dummy native resource: " << resource;
return base::android::ConvertUTF8ToJavaString(env, resource);
}
...@@ -83,4 +83,9 @@ public class ChromeBundleSmokeTest { ...@@ -83,4 +83,9 @@ public class ChromeBundleSmokeTest {
public void testModuleJavaResourceLoading() { public void testModuleJavaResourceLoading() {
runTestActivity(2); // Test case LOAD_JAVA_RESOURCE. runTestActivity(2); // Test case LOAD_JAVA_RESOURCE.
} }
@Test
public void testModuleNativeResourceLoading() {
runTestActivity(3); // Test case LOAD_NATIVE_RESOURCE.
}
} }
...@@ -56,3 +56,13 @@ generate_jni_registration("jni_registration") { ...@@ -56,3 +56,13 @@ generate_jni_registration("jni_registration") {
header_output = "$target_gen_dir/jni_registration.h" header_output = "$target_gen_dir/jni_registration.h"
namespace = "test_dummy" namespace = "test_dummy"
} }
android_assets("pak_assets") {
sources = [
"$root_gen_dir/chrome/test_dummy_resources.pak",
]
deps = [
"//chrome/android/features/test_dummy/internal:resources_native",
]
disable_compression = true
}
...@@ -2,12 +2,34 @@ ...@@ -2,12 +2,34 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import("//build/buildflag_header.gni")
import("//build/config/android/rules.gni") import("//build/config/android/rules.gni")
import("//chrome/android/modules/buildflags.gni")
android_library("java") { android_library("java") {
deps = [ deps = [
"//base:base_java",
"//base:jni_java",
"//chrome/android/features/test_dummy/public:java", "//chrome/android/features/test_dummy/public:java",
"//chrome/android/modules/test_dummy/public:java", "//chrome/android/modules/test_dummy/public:java",
] ]
java_files = [ "java/src/org/chromium/chrome/modules/test_dummy/TestDummyModuleProvider.java" ] java_files = [ "java/src/org/chromium/chrome/modules/test_dummy/TestDummyModuleProvider.java" ]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
generate_jni("jni_headers") {
sources = [
"java/src/org/chromium/chrome/modules/test_dummy/TestDummyModuleProvider.java",
]
}
source_set("native") {
deps = [
":jni_headers",
"//base",
"//ui/base",
]
sources = [
"test_dummy_module_provider.cc",
]
} }
...@@ -4,31 +4,52 @@ ...@@ -4,31 +4,52 @@
package org.chromium.chrome.modules.test_dummy; package org.chromium.chrome.modules.test_dummy;
import android.app.Activity; import org.chromium.base.ThreadUtils;
import android.content.Intent; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.components.module_installer.engine.InstallListener;
/** Installs the test dummy module and launches the test dummy implementation. */ /** Installs and loads the test dummy module. */
@JNINamespace("test_dummy")
public class TestDummyModuleProvider { public class TestDummyModuleProvider {
private static boolean sIsModuleLoaded;
/** Returns true if the module is installed. */
public static boolean isModuleInstalled() {
ThreadUtils.assertOnUiThread();
return TestDummyModule.isInstalled();
}
/**
* Installs the module.
*
* Can only be called if the module is not installed.
*
* @param onFinished Called when the install has finished.
*/
public static void installModule(InstallListener onFinished) {
ThreadUtils.assertOnUiThread();
TestDummyModule.install(onFinished);
}
/** /**
* Launches test dummy. Installs test dummy module if necessary. * Returns the test dummy provider from inside the module.
* *
* @param intent A test dummy intent encoding the desired test scenario. * Can only be called if the module is installed. Maps native resources into memory on first
* @param activity The activity the test dummy will run in. * call.
*/ */
public static void launchTestDummy(Intent intent, Activity activity) { public static TestDummyProvider getTestDummyProvider() {
if (!TestDummyModule.isInstalled()) { ThreadUtils.assertOnUiThread();
installAndLaunchTestDummy(intent, activity); assert isModuleInstalled();
return; if (!sIsModuleLoaded) {
TestDummyModuleProviderJni.get().loadNative();
sIsModuleLoaded = true;
} }
TestDummyModule.getImpl().getTestDummy().launch(intent, activity); return TestDummyModule.getImpl();
} }
private static void installAndLaunchTestDummy(Intent intent, Activity activity) { @NativeMethods
TestDummyModule.install((success) -> { interface Natives {
if (!success) { void loadNative();
throw new RuntimeException("Failed to install module.");
}
TestDummyModule.getImpl().getTestDummy().launch(intent, activity);
});
} }
} }
// 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/apk_assets.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/android/modules/test_dummy/provider/jni_headers/TestDummyModuleProvider_jni.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/resource/scale_factor.h"
// Native partner of the Java TestDummyModuleProvider. Used to load native
// resources of the test dummy module into memory.
// TODO(tiborg): Move to //components/module_installer so that it can be used by
// other modules.
namespace module_installer {
// Allows memory mapping module PAK files on the main thread.
//
// We expect the memory mapping step to be quick. All it does is retrieveing a
// region from the APK file that should already be memory mapped and reading the
// PAK file header. Most of the disk IO is happening when accessing a resource.
// And this traditionally happens synchronously on the main thread.
class ScopedAllowModulePakLoad {
public:
ScopedAllowModulePakLoad() {}
~ScopedAllowModulePakLoad() {}
private:
base::ScopedAllowBlocking allow_blocking_;
};
} // namespace module_installer
namespace test_dummy {
static void JNI_TestDummyModuleProvider_LoadNative(JNIEnv* env) {
module_installer::ScopedAllowModulePakLoad resource_loader;
std::string path = "assets/test_dummy_resources.pak";
base::MemoryMappedFile::Region region;
int fd = base::android::OpenApkAsset(path, &region);
if (fd < 0) {
NOTREACHED() << "Cannot find " << path << " in APK.";
}
ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
base::File(fd), region, ui::SCALE_FACTOR_NONE);
}
} // namespace test_dummy
...@@ -11,6 +11,7 @@ test_dummy_module_desc = { ...@@ -11,6 +11,7 @@ test_dummy_module_desc = {
java_deps = [ java_deps = [
"//chrome/android/features/test_dummy/internal:java", "//chrome/android/features/test_dummy/internal:java",
"//chrome/android/modules/test_dummy/internal:java", "//chrome/android/modules/test_dummy/internal:java",
"//chrome/android/modules/test_dummy/internal:pak_assets",
] ]
native_deps = [ native_deps = [
......
...@@ -172,6 +172,9 @@ ...@@ -172,6 +172,9 @@
# END chrome/ WebUI resources section # END chrome/ WebUI resources section
# START chrome/ miscellaneous section. # START chrome/ miscellaneous section.
"chrome/android/features/test_dummy/internal/resources/resources.grd": {
"includes": [14070],
},
"chrome/common/common_resources.grd": { "chrome/common/common_resources.grd": {
"includes": [14160], "includes": [14160],
}, },
......
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