mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 17:25:36 +00:00
Bug 1533385 - Make GeckoView read configuration options from filesystem. r=droeh
The configuration file format is YAML and looks like: ``` prefs: foo.bar.boolean: true foo.bar.string: "string" foo.bar.int: 500 env: MOZ_LOG: nsHttp:5 args: [--marionette] ``` By default, if the consuming App is debuggable, GeckoView will read configuration from `/data/local/tmp/$PACKAGE-geckoview-config.yaml` at startup. For consumers (including browsers) that want to allow the underlying GeckoView to be remote controlled in some way, the `GeckoRuntimeSettings.Builder.configFilePath()` method allows to avoid the default behaviour depending on the `android:debuggable` flag. For example, release versions of Firefox for Android will want to allow this configuration when appropriate App-level settings are toggled. The additional configuration is appended after any existing configuration methods, e.g., after anything specified using Intent argument extras or existing `GeckoRuntimeSettings.Builder` methods. Differential Revision: https://phabricator.services.mozilla.com/D25885 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
d302c30583
commit
dfeeb0c3e4
@ -299,6 +299,7 @@ package org.mozilla.geckoview {
|
||||
method @NonNull public String[] getArguments();
|
||||
method public boolean getAutomaticFontSizeAdjustment();
|
||||
method public int getAutoplayDefault();
|
||||
method @Nullable public String getConfigFilePath();
|
||||
method public boolean getConsoleOutputEnabled();
|
||||
method @NonNull public ContentBlocking.Settings getContentBlocking();
|
||||
method @Nullable public Class<?> getCrashHandler();
|
||||
@ -340,6 +341,7 @@ package org.mozilla.geckoview {
|
||||
method @NonNull public GeckoRuntimeSettings.Builder arguments(@NonNull String[]);
|
||||
method @NonNull public GeckoRuntimeSettings.Builder automaticFontSizeAdjustment(boolean);
|
||||
method @NonNull public GeckoRuntimeSettings.Builder autoplayDefault(int);
|
||||
method @NonNull public GeckoRuntimeSettings.Builder configFilePath(@Nullable String);
|
||||
method @NonNull public GeckoRuntimeSettings.Builder consoleOutput(boolean);
|
||||
method @NonNull public GeckoRuntimeSettings.Builder contentBlocking(@NonNull ContentBlocking.Settings);
|
||||
method @NonNull public GeckoRuntimeSettings.Builder crashHandler(@Nullable Class<?>);
|
||||
|
@ -218,6 +218,7 @@ tasks.withType(Javadoc) {
|
||||
dependencies {
|
||||
implementation "com.android.support:support-v4:$support_library_version"
|
||||
implementation "com.android.support:palette-v7:$support_library_version"
|
||||
implementation "org.yaml:snakeyaml:1.24:android"
|
||||
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
testImplementation 'junit:junit:4.12'
|
||||
|
@ -169,3 +169,11 @@
|
||||
-keepclasseswithmembers class * {
|
||||
@org.mozilla.gecko.annotation.ReflectionTarget <fields>;
|
||||
}
|
||||
|
||||
# Avoid "Warning: org.yaml.snakeyaml.scanner.ScannerImpl: can't find
|
||||
# referenced method 'java.nio.ByteBuffer flip()' in library class
|
||||
# java.nio.ByteBuffer".
|
||||
# Between Java 1.8 and 1.9, the signature of `flip()` changed, which
|
||||
# trips up proguard.
|
||||
|
||||
-dontwarn org.yaml.snakeyaml.scanner.ScannerImpl
|
||||
|
@ -0,0 +1,90 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.util;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.gecko.GeckoThread;
|
||||
import org.yaml.snakeyaml.TypeDescription;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DebugConfig {
|
||||
private static final String LOGTAG = "GeckoDebugConfig";
|
||||
|
||||
protected Map<String, Object> prefs;
|
||||
protected Map<String, String> env;
|
||||
protected List<String> args;
|
||||
|
||||
public static @NonNull DebugConfig fromFile(final @NonNull File configFile) throws FileNotFoundException {
|
||||
final Constructor constructor = new Constructor(DebugConfig.class);
|
||||
final TypeDescription description = new TypeDescription(DebugConfig.class);
|
||||
description.putMapPropertyType("prefs", String.class, Object.class);
|
||||
description.putMapPropertyType("env", String.class, String.class);
|
||||
description.putListPropertyType("args", String.class);
|
||||
|
||||
final Yaml yaml = new Yaml(constructor);
|
||||
yaml.addTypeDescription(description);
|
||||
|
||||
final FileInputStream fileInputStream = new FileInputStream(configFile);
|
||||
try {
|
||||
return yaml.load(fileInputStream);
|
||||
} finally {
|
||||
IOUtils.safeStreamClose(fileInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeIntoInitInfo(final @NonNull GeckoThread.InitInfo info) {
|
||||
if (env != null) {
|
||||
Log.d(LOGTAG, "Adding environment variables from debug config: " + env);
|
||||
|
||||
if (info.extras == null) {
|
||||
info.extras = new Bundle();
|
||||
}
|
||||
|
||||
int c = 0;
|
||||
while (info.extras.getString("env" + c) != null) {
|
||||
c += 1;
|
||||
}
|
||||
|
||||
for (final Map.Entry<String, String> entry : env.entrySet()) {
|
||||
info.extras.putString("env" + c, entry.getKey() + "=" + entry.getValue());
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (args != null) {
|
||||
Log.d(LOGTAG, "Adding arguments from debug config: " + args);
|
||||
|
||||
final ArrayList<String> combinedArgs = new ArrayList<>();
|
||||
combinedArgs.addAll(Arrays.asList(info.args));
|
||||
combinedArgs.addAll(args);
|
||||
|
||||
info.args = combinedArgs.toArray(new String[combinedArgs.size()]);
|
||||
}
|
||||
|
||||
if (prefs != null) {
|
||||
Log.d(LOGTAG, "Adding prefs from debug config: " + prefs);
|
||||
|
||||
final Map<String, Object> combinedPrefs = new HashMap<>();
|
||||
combinedPrefs.putAll(info.prefs);
|
||||
combinedPrefs.putAll(prefs);
|
||||
info.prefs = Collections.unmodifiableMap(prefs);
|
||||
}
|
||||
}
|
||||
}
|
@ -8,14 +8,15 @@ package org.mozilla.geckoview;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
import android.support.annotation.AnyThread;
|
||||
import android.support.annotation.NonNull;
|
||||
@ -25,21 +26,26 @@ import android.util.Log;
|
||||
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoSystemStateListener;
|
||||
import org.mozilla.gecko.GeckoScreenOrientation;
|
||||
import org.mozilla.gecko.GeckoSystemStateListener;
|
||||
import org.mozilla.gecko.GeckoThread;
|
||||
import org.mozilla.gecko.PrefsHelper;
|
||||
import org.mozilla.gecko.util.BundleEventListener;
|
||||
import org.mozilla.gecko.util.DebugConfig;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.yaml.snakeyaml.error.YAMLException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
public final class GeckoRuntime implements Parcelable {
|
||||
private static final String LOGTAG = "GeckoRuntime";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final String CONFIG_FILE_PATH_TEMPLATE = "/data/local/tmp/%s-geckoview-config.yaml";
|
||||
|
||||
/**
|
||||
* Intent action sent to the crash handler when a crash is encountered.
|
||||
* @see GeckoRuntimeSettings.Builder#crashHandler(Class)
|
||||
@ -221,6 +227,28 @@ public final class GeckoRuntime implements Parcelable {
|
||||
info.flags = flags;
|
||||
info.prefs = settings.getPrefsMap();
|
||||
|
||||
String configFilePath = settings.getConfigFilePath();
|
||||
if (configFilePath == null) {
|
||||
// Default to /data/local/tmp/$PACKAGE-geckoview-config.yaml if android:debuggable="true"
|
||||
// and to not read configuration from a file if android:debuggable="false".
|
||||
final ApplicationInfo applicationInfo = context.getApplicationInfo();
|
||||
final boolean isPackageDebuggable = (applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
if (isPackageDebuggable) {
|
||||
configFilePath = String.format(CONFIG_FILE_PATH_TEMPLATE, applicationInfo.packageName);
|
||||
}
|
||||
}
|
||||
|
||||
if (configFilePath != null && !configFilePath.isEmpty()) {
|
||||
try {
|
||||
final DebugConfig debugConfig = DebugConfig.fromFile(new File(configFilePath));
|
||||
Log.i(LOGTAG, "Adding debug configuration from: " + configFilePath);
|
||||
debugConfig.mergeIntoInitInfo(info);
|
||||
} catch (YAMLException e) {
|
||||
Log.w(LOGTAG, "Failed to add debug configuration from: " + configFilePath, e);
|
||||
} catch (FileNotFoundException e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!GeckoThread.init(info)) {
|
||||
Log.w(LOGTAG, "init failed (could not initiate GeckoThread)");
|
||||
return false;
|
||||
|
@ -77,6 +77,19 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Path to configuration file from which GeckoView will read configuration options such as
|
||||
* Gecko process arguments, environment variables, and preferences.
|
||||
*
|
||||
* @param configFilePath Configuration file path to read from, or <code>null</code> to use
|
||||
* default location <code>/data/local/tmp/$PACKAGE-geckoview-config.yaml</code>.
|
||||
* @return This Builder instance.
|
||||
*/
|
||||
public @NonNull Builder configFilePath(final @Nullable String configFilePath) {
|
||||
getSettings().mConfigFilePath = configFilePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether JavaScript support should be enabled.
|
||||
*
|
||||
@ -330,6 +343,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
/* package */ boolean mUseContentProcess;
|
||||
/* package */ String[] mArgs;
|
||||
/* package */ Bundle mExtras;
|
||||
/* package */ String mConfigFilePath;
|
||||
|
||||
/* package */ ContentBlocking.Settings mContentBlocking;
|
||||
|
||||
@ -412,6 +426,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
mScreenHeightOverride = settings.mScreenHeightOverride;
|
||||
mCrashHandler = settings.mCrashHandler;
|
||||
mRequestedLocales = settings.mRequestedLocales;
|
||||
mConfigFilePath = settings.mConfigFilePath;
|
||||
}
|
||||
|
||||
/* package */ void commit() {
|
||||
@ -446,6 +461,18 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
return mExtras;
|
||||
}
|
||||
|
||||
/**
|
||||
* Path to configuration file from which GeckoView will read configuration options such as
|
||||
* Gecko process arguments, environment variables, and preferences.
|
||||
*
|
||||
* @return Path to configuration file from which GeckoView will read configuration options,
|
||||
* or <code>null</code> for default location
|
||||
* <code>/data/local/tmp/$PACKAGE-geckoview-config.yaml</code>.
|
||||
*/
|
||||
public @Nullable String getConfigFilePath() {
|
||||
return mConfigFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether JavaScript support is enabled.
|
||||
*
|
||||
@ -822,6 +849,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
out.writeInt(mScreenHeightOverride);
|
||||
out.writeString(mCrashHandler != null ? mCrashHandler.getName() : null);
|
||||
out.writeStringArray(mRequestedLocales);
|
||||
out.writeString(mConfigFilePath);
|
||||
}
|
||||
|
||||
// AIDL code may call readFromParcel even though it's not part of Parcelable.
|
||||
@ -851,6 +879,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
|
||||
}
|
||||
|
||||
mRequestedLocales = source.createStringArray();
|
||||
mConfigFilePath = source.readString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<GeckoRuntimeSettings> CREATOR
|
||||
|
@ -71,6 +71,13 @@ exclude: true
|
||||
[68.14]: ../GeckoSessionSettings.Builder.html#contextId-
|
||||
[68.15]: ../StorageController.html#clearSessionContextData-java.lang.String-
|
||||
|
||||
- Added [`GeckoRuntimeSettings.Builder#configFilePath`][68.16] to set
|
||||
a path to a configuration file from which GeckoView will read
|
||||
configuration options such as Gecko process arguments, environment
|
||||
variables, and preferences.
|
||||
|
||||
[68.16]: ../GeckoRuntimeSettings.Builder.html#configFilePath-java.lang.String-
|
||||
|
||||
## v67
|
||||
- Added [`setAutomaticFontSizeAdjustment`][67.2] to
|
||||
[`GeckoRuntimeSettings`][67.3] for automatically adjusting font size settings
|
||||
@ -277,4 +284,4 @@ exclude: true
|
||||
[65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: ../GeckoResult.html
|
||||
|
||||
[api-version]: fa2863734daac0ec5cb0671b030139de3aac5029
|
||||
[api-version]: 77512ba4107f1bd3330327d8b9c1b91363430783
|
||||
|
Loading…
Reference in New Issue
Block a user