Commit 3e6d7e14 authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

[WebLayer] Load WebLayerImpl from another APK

With this change, WebLayerShell now only depends on the weblayer/public
dir, and has no other dependencies on chrome code. A new APK
WebLayerSupport has all the implementation and must be installed
alongside WebLayerShell for it to work.

Change-Id: Iab3b346831c8d8737a0b3ca509455b7499b31ac9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1779428Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#693775}
parent eafc9468
......@@ -23,8 +23,8 @@ JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return -1;
weblayer::MainParams params;
params.delegate = new weblayer::MainDelegateImpl;
params.pak_name = "weblayer_shell.pak";
params.brand = "weblayer_shell";
params.pak_name = "weblayer_support.pak";
params.brand = "WebLayer";
content::SetContentMainDelegate(
new weblayer::ContentMainDelegateImpl(params));
......
......@@ -4,23 +4,37 @@
package org.chromium.weblayer_private;
import android.app.Application;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.os.IBinder;
import android.util.AndroidRuntimeException;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.PathUtils;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.content_public.browser.BrowserStartupController;
import org.chromium.content_public.browser.ChildProcessCreationParams;
import org.chromium.content_public.browser.DeviceUtils;
import org.chromium.ui.base.ResourceBundle;
import org.chromium.weblayer_private.aidl.IProfile;
import org.chromium.weblayer_private.aidl.IWebLayer;
public final class WebLayerImpl extends IWebLayer.Stub {
// TODO: should there be one tag for all this code?
private static final String TAG = "WebLayer";
private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "weblayer";
// TODO: Configure this from the client.
private static final String COMMAND_LINE_FILE = "/data/local/tmp/weblayer-command-line";
public static IBinder create() {
return new WebLayerImpl();
public static IBinder create(Application application, Context implContext) {
return new WebLayerImpl(application, implContext);
}
@Override
......@@ -28,17 +42,33 @@ public final class WebLayerImpl extends IWebLayer.Stub {
return new ProfileImpl(path);
}
public WebLayerImpl() {
private WebLayerImpl(Application application, Context implContext) {
ContextUtils.initApplicationContext(new ContextWrapper(application) {
@Override
public Resources getResources() {
// Always use resources from the implementation APK.
return implContext.getResources();
}
});
ResourceBundle.setNoAvailableLocalePaks();
PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
ApplicationStatus.initialize(application);
ChildProcessCreationParams.set(implContext.getPackageName(), true /* isExternalService */,
LibraryProcessType.PROCESS_CHILD, true /* bindToCaller */,
false /* ignoreVisibilityForImportance */);
if (!CommandLine.isInitialized()) {
CommandLine.initFromFile(COMMAND_LINE_FILE);
}
DeviceUtils.addDeviceSpecificUserAgentSwitch();
try {
LibraryLoader.getInstance().ensureInitialized(LibraryProcessType.PROCESS_BROWSER);
} catch (ProcessInitException e) {
Log.e(TAG, "ContentView initialization failed.", e);
// Since the library failed to initialize nothing in the application
// can work, so kill the whole application not just the activity
System.exit(-1);
return;
throw new AndroidRuntimeException(e);
}
try {
......@@ -47,7 +77,7 @@ public final class WebLayerImpl extends IWebLayer.Stub {
/* singleProcess*/ false);
} catch (ProcessInitException e) {
Log.e(TAG, "Unable to load native library.", e);
System.exit(-1);
throw new AndroidRuntimeException(e);
}
}
}
......@@ -19,4 +19,8 @@ android_library("java") {
deps = [
"//weblayer/browser/java:client_java",
]
# Needed for android.webkit.WebViewDelegate.
alternative_android_sdk_dep =
"//third_party/android_sdk:public_framework_system_java"
}
......@@ -4,20 +4,29 @@
package org.chromium.weblayer;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.webkit.WebViewDelegate;
import android.webkit.WebViewFactory;
import org.chromium.weblayer_private.aidl.IWebLayer;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* WebLayer is responsible for initializing state necessary to use* any of the classes in web layer.
*/
public final class WebLayer {
private static final String TAG = "WebLayer";
private static final String PACKAGE_NAME = "org.chromium.weblayer.support";
private static WebLayer sInstance;
private IWebLayer mImpl;
......@@ -29,12 +38,33 @@ public final class WebLayer {
return sInstance;
}
WebLayer() {
WebLayer() {}
public void init(Application application) {
try {
// TODO: Make asset loading work on L, where WebViewDelegate doesn't exist.
// WebViewDelegate.addWebViewAssetPath() accesses the currently loaded package info from
// WebViewFactory, so we have to fake it.
PackageInfo implPackageInfo = application.getPackageManager().getPackageInfo(
PACKAGE_NAME, PackageManager.GET_META_DATA);
Field packageInfo = WebViewFactory.class.getDeclaredField("sPackageInfo");
packageInfo.setAccessible(true);
packageInfo.set(null, implPackageInfo);
// TODO(torne): Figure out how to load assets for production.
// Load assets using the WebViewDelegate.
Constructor constructor = WebViewDelegate.class.getDeclaredConstructor();
constructor.setAccessible(true);
WebViewDelegate delegate = (WebViewDelegate) constructor.newInstance();
delegate.addWebViewAssetPath(application);
Context remoteContext = application.createPackageContext(
PACKAGE_NAME, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
mImpl = IWebLayer.Stub.asInterface(
(IBinder) Class.forName("org.chromium.weblayer_private.WebLayerImpl")
.getMethod("create")
.invoke(null));
(IBinder) remoteContext.getClassLoader()
.loadClass("org.chromium.weblayer_private.WebLayerImpl")
.getMethod("create", Application.class, Context.class)
.invoke(null, application, remoteContext));
} catch (Exception e) {
Log.e(TAG, "Failed to get WebLayerImpl.", e);
throw new AndroidRuntimeException(e);
......@@ -43,7 +73,7 @@ public final class WebLayer {
@Override
protected void finalize() {
// TODO(sky): figure out right assertion here if mProfile is non-null.
// TODO(sky): figure out right assertion here if mImpl is non-null.
}
public void destroy() {
......
......@@ -144,7 +144,20 @@ group("resources") {
]
}
repack("pak") {
repack("shell_pak") {
testonly = true
sources = [
"$root_gen_dir/weblayer/shell/weblayer_shell_resources.pak",
]
deps = [
":resources",
]
output = "$root_out_dir/weblayer_shell.pak"
}
repack("support_pak") {
testonly = true
sources = [
......@@ -160,11 +173,9 @@ repack("pak") {
"$root_gen_dir/ui/resources/webui_resources.pak",
"$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
"$root_gen_dir/ui/strings/ui_strings_en-US.pak",
"$root_gen_dir/weblayer/shell/weblayer_shell_resources.pak",
]
deps = [
":resources",
"//content:resources",
"//content/app/resources",
"//content/app/strings",
......@@ -182,7 +193,22 @@ repack("pak") {
sources +=
[ "$root_gen_dir/ui/views/resources/views_resources_100_percent.pak" ]
}
output = "$root_out_dir/weblayer_shell.pak"
output = "$root_out_dir/weblayer_support.pak"
}
repack("pak") {
testonly = true
sources = [
"$root_out_dir/weblayer_shell.pak",
"$root_out_dir/weblayer_support.pak",
]
deps = [
":shell_pak",
":support_pak",
]
output = "$root_out_dir/weblayer.pak"
}
if (is_android) {
......@@ -192,6 +218,12 @@ if (is_android) {
"//weblayer/shell/android:weblayer_shell_apk",
]
}
group("weblayer_support") {
testonly = true
deps = [
"//weblayer/shell/android:weblayer_support_apk",
]
}
} else {
executable("weblayer_shell") {
testonly = true
......
......@@ -11,7 +11,7 @@ weblayer_shell_manifest =
"$target_gen_dir/weblayer_shell_manifest/AndroidManifest.xml"
jinja_template("weblayer_shell_manifest") {
input = "AndroidManifest.xml"
input = "shell_apk/AndroidManifest.xml"
output = weblayer_shell_manifest
}
......@@ -23,14 +23,8 @@ android_assets("weblayer_shell_assets") {
]
disable_compression = true
deps = [
"//third_party/icu:icu_assets",
"//weblayer/shell:pak",
"//weblayer/shell:shell_pak",
]
if (use_v8_context_snapshot) {
deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_assets" ]
} else {
deps += [ "//v8:v8_external_startup_data_assets" ]
}
}
android_library("weblayer_shell_java") {
......@@ -38,24 +32,11 @@ android_library("weblayer_shell_java") {
deps = [
":weblayer_shell_manifest",
"//base:base_java",
"//ui/android:ui_java",
"//weblayer/public/java",
]
# Transitive dependencies
deps += [
"//components/viz/service:service_java",
"//media/base/android:media_java",
"//media/capture/video/android:capture_java",
"//mojo/public/java:system_java",
"//net/android:net_java",
"//third_party/android_deps:android_support_v4_java",
"//weblayer/public/java",
]
java_files = [
"src/org/chromium/weblayer/shell/WebLayerShellActivity.java",
"src/org/chromium/weblayer/shell/WebLayerShellApplication.java",
]
java_files =
[ "shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java" ]
android_manifest_for_lint = weblayer_shell_manifest
}
......@@ -67,13 +48,62 @@ android_apk("weblayer_shell_apk") {
":weblayer_shell_assets",
":weblayer_shell_java",
":weblayer_shell_manifest",
"//base:base_java",
"//weblayer/browser/java",
]
apk_name = "WebLayerShell"
android_manifest = weblayer_shell_manifest
min_sdk_version = 21
target_sdk_version = 28
android_manifest_dep = ":weblayer_shell_manifest"
}
weblayer_support_manifest =
"$target_gen_dir/weblayer_support_manifest/AndroidManifest.xml"
jinja_template("weblayer_support_manifest") {
input = "support_apk/AndroidManifest.xml"
output = weblayer_support_manifest
}
android_assets("weblayer_support_assets") {
testonly = true
sources = [
"$root_out_dir/weblayer_support.pak",
]
disable_compression = true
deps = [
"//third_party/icu:icu_assets",
"//weblayer/shell:support_pak",
]
if (use_v8_context_snapshot) {
deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_assets" ]
} else {
deps += [ "//v8:v8_external_startup_data_assets" ]
}
}
android_apk("weblayer_support_apk") {
testonly = true
deps = [
":weblayer_support_assets",
":weblayer_support_manifest",
"//base:base_java",
"//weblayer/browser/java",
]
# Transitive dependencies
deps += [
"//components/viz/service:service_java",
"//media/base/android:media_java",
"//media/capture/video/android:capture_java",
"//mojo/public/java:system_java",
"//net/android:net_java",
]
apk_name = "WebLayerSupport"
android_manifest = weblayer_support_manifest
min_sdk_version = 21
target_sdk_version = 28
android_manifest_dep = ":weblayer_support_manifest"
shared_libraries = [ "//weblayer:libweblayer" ]
}
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.chromium.weblayer.shell">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:label="WebLayer shell">
<activity android:name="WebLayerShellActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Holo.Light.NoActionBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
noparent = True
include_rules = [
"+weblayer/public/java",
]
......@@ -20,7 +20,6 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import org.chromium.base.CommandLine;
import org.chromium.weblayer.BrowserController;
import org.chromium.weblayer.BrowserObserver;
import org.chromium.weblayer.Profile;
......@@ -54,13 +53,10 @@ public class WebLayerShellActivity extends FragmentActivity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Only call init for main process.
WebLayer.getInstance().init(getApplication());
// TODO: move this to WebLayer.
// Initializing the command line must occur before loading the library.
if (!CommandLine.isInitialized()) {
((WebLayerShellApplication) getApplication()).initCommandLine();
}
super.onCreate(savedInstanceState);
LinearLayout mainView = new LinearLayout(this);
int viewId = View.generateViewId();
......
// 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.
package org.chromium.weblayer.shell;
import android.app.Application;
import android.content.Context;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.BuildConfig;
import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.PathUtils;
import org.chromium.base.multidex.ChromiumMultiDexInstaller;
import org.chromium.ui.base.ResourceBundle;
/**
* Entry point for the demo shell application.
*/
public class WebLayerShellApplication extends Application {
public static final String COMMAND_LINE_FILE = "/data/local/tmp/weblayer-shell-command-line";
private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "weblayer_shell";
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":");
ContextUtils.initApplicationContext(this);
ResourceBundle.setNoAvailableLocalePaks();
if (isBrowserProcess) {
if (BuildConfig.IS_MULTIDEX_ENABLED) {
ChromiumMultiDexInstaller.install(this);
}
PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
}
ApplicationStatus.initialize(this);
}
public void initCommandLine() {
if (!CommandLine.isInitialized()) {
CommandLine.initFromFile(COMMAND_LINE_FILE);
}
}
}
......@@ -7,7 +7,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.chromium.weblayer.shell">
package="org.chromium.weblayer.support">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
......@@ -19,18 +19,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:name="WebLayerShellApplication"
android:label="WebLayer shell">
<activity android:name="WebLayerShellActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Holo.Light.NoActionBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<application android:label="WebLayer support">
<!-- The following service entries exist in order to allow us to
start more than one sandboxed process. -->
......@@ -43,7 +32,8 @@
<service android:name="org.chromium.content.app.SandboxedProcessService{{ i }}"
android:process=":sandboxed_process{{ i }}"
android:isolatedProcess="true"
android:exported="false" />
android:externalService="true"
android:exported="true" />
{% endfor %}
{% set num_privileged_services = 5 %}
......@@ -53,7 +43,7 @@
<service android:name="org.chromium.content.app.PrivilegedProcessService{{ i }}"
android:process=":privileged_process{{ i }}"
android:isolatedProcess="false"
android:exported="false" />
android:exported="true" />
{% endfor %}
</application>
</manifest>
......@@ -96,7 +96,7 @@ weblayer::MainParams CreateMainParams() {
base::PathService::Get(base::DIR_EXE, &params.log_filename);
params.log_filename = params.log_filename.AppendASCII("weblayer_shell.log");
params.pak_name = "weblayer_shell.pak";
params.pak_name = "weblayer.pak";
params.brand = "weblayer_shell";
params.full_version = WEBLAYER_SHELL_VERSION;
......
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