Commit 469ec235 authored by Nate Fischer's avatar Nate Fischer Committed by Commit Bot

AW: refactor developer mode logic and rename provider

This refactors developer mode logic, so the implementation can be shared
by both the developer UI and the embedded WebView code.

This also renames the ContentProvider so it can be used more generally
in the future.

Bug: 1036533
Test: Manual - verify flags Activity continues to work
Change-Id: I6cb4b0dfb751cd04884af3768f051ebe6795ea5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1982232Reviewed-by: default avatarShimi Zhang <ctzsm@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Commit-Queue: Nate Fischer <ntfschr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#728060}
parent ab79932d
......@@ -494,8 +494,8 @@ android_library("common_crash_java") {
android_library("common_java") {
sources = [
"java/src/org/chromium/android_webview/common/AwResource.java",
"java/src/org/chromium/android_webview/common/DeveloperModeUtils.java",
"java/src/org/chromium/android_webview/common/Flag.java",
"java/src/org/chromium/android_webview/common/FlagOverrideConstants.java",
"java/src/org/chromium/android_webview/common/FlagOverrideHelper.java",
"java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java",
"java/src/org/chromium/android_webview/common/services/ServiceNames.java",
......
......@@ -34,6 +34,9 @@ import org.chromium.android_webview.R;
import org.chromium.android_webview.VariationsSeedLoader;
import org.chromium.android_webview.WebViewChromiumRunQueue;
import org.chromium.android_webview.common.AwResource;
import org.chromium.android_webview.common.DeveloperModeUtils;
import org.chromium.android_webview.common.FlagOverrideHelper;
import org.chromium.android_webview.common.ProductionSupportedFlagList;
import org.chromium.android_webview.gfx.AwDrawFnImpl;
import org.chromium.base.BuildConfig;
import org.chromium.base.BuildInfo;
......@@ -168,8 +171,11 @@ public class WebViewChromiumAwInit {
// available when AwFeatureListCreator::SetUpFieldTrials() runs.
finishVariationsInitLocked();
if (AwBrowserProcess.isDeveloperModeEnabled()) {
AwBrowserProcess.getAndApplyFlagOverridesSync();
String webViewPackageName = AwBrowserProcess.getWebViewPackageName();
if (DeveloperModeUtils.isDeveloperModeEnabled(webViewPackageName)) {
FlagOverrideHelper helper =
new FlagOverrideHelper(ProductionSupportedFlagList.sFlagList);
helper.applyFlagOverrides(DeveloperModeUtils.getFlagOverrides(webViewPackageName));
}
AwBrowserProcess.start();
......
......@@ -8,9 +8,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
......@@ -18,10 +15,7 @@ import android.os.RemoteException;
import android.os.StrictMode;
import org.chromium.android_webview.common.CommandLineUtil;
import org.chromium.android_webview.common.FlagOverrideConstants;
import org.chromium.android_webview.common.FlagOverrideHelper;
import org.chromium.android_webview.common.PlatformServiceBridge;
import org.chromium.android_webview.common.ProductionSupportedFlagList;
import org.chromium.android_webview.common.services.ICrashReceiverService;
import org.chromium.android_webview.common.services.ServiceNames;
import org.chromium.android_webview.metrics.AwMetricsServiceClient;
......@@ -52,7 +46,6 @@ import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -371,49 +364,6 @@ public final class AwBrowserProcess {
});
}
// TODO(ntfschr): move this to DeveloperModeUtils in common Java packaage.
// Quickly determine whether developer mode is enabled.
public static boolean isDeveloperModeEnabled() {
final Context context = ContextUtils.getApplicationContext();
ComponentName flagOverrideContentProvider = new ComponentName(
getWebViewPackageName(), ServiceNames.FLAG_OVERRIDE_CONTENT_PROVIDER);
int enabledState =
context.getPackageManager().getComponentEnabledSetting(flagOverrideContentProvider);
return enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
}
public static void getAndApplyFlagOverridesSync() {
FlagOverrideHelper helper = new FlagOverrideHelper(ProductionSupportedFlagList.sFlagList);
helper.applyFlagOverrides(getFlagOverrides());
}
// TODO(ntfschr): move this to DeveloperModeUtils in common Java packaage.
private static Map<String, Boolean> getFlagOverrides() {
Map<String, Boolean> flagOverrides = new HashMap<>();
Uri uri = new Uri.Builder()
.scheme("content")
.authority(getWebViewPackageName()
+ FlagOverrideConstants.URI_AUTHORITY_SUFFIX)
.path(FlagOverrideConstants.URI_PATH)
.build();
final Context appContext = ContextUtils.getApplicationContext();
try (Cursor cursor = appContext.getContentResolver().query(uri, /* projection */ null,
/* selection */ null, /* selectionArgs */ null, /* sortOrder */ null)) {
assert cursor != null : "ContentProvider doesn't support querying '" + uri + "'";
int flagNameColumnIndex =
cursor.getColumnIndexOrThrow(FlagOverrideConstants.FLAG_NAME_COLUMN);
int flagStateColumnIndex =
cursor.getColumnIndexOrThrow(FlagOverrideConstants.FLAG_STATE_COLUMN);
while (cursor.moveToNext()) {
String flagName = cursor.getString(flagNameColumnIndex);
boolean flagState = cursor.getInt(flagStateColumnIndex) != 0;
flagOverrides.put(flagName, flagState);
}
}
return flagOverrides;
}
// Do not instantiate this class.
private AwBrowserProcess() {}
}
// 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.android_webview.common;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import org.chromium.android_webview.common.services.ServiceNames;
import org.chromium.base.ContextUtils;
import java.util.HashMap;
import java.util.Map;
/**
* Utilities for communication with the developer mode ContentProvider.
*
* <p>This should only be called in processes which have called {@link
* ContextUtils.initApplicationContext(Context)}.
*/
public final class DeveloperModeUtils {
// Do not instantiate this class.
private DeveloperModeUtils() {}
public static final String URI_AUTHORITY_SUFFIX = ".DeveloperModeContentProvider";
public static final String FLAG_OVERRIDE_URI_PATH = "/flag-overrides";
public static final String FLAG_OVERRIDE_NAME_COLUMN = "flagName";
public static final String FLAG_OVERRIDE_STATE_COLUMN = "flagState";
/**
* Quickly determine whether developer mode is enabled. Developer mode is off-by-default.
*
* <p>This makes no guarantees about which processes are alive, it only indicates whether the
* user has stepped in or out of "developer mode." Developer mode may be enabled and the
* ContentProvider process may be dead if the user has taken a WebView update since enabling
* developer mode.
*
* @param webViewPackageName the package name of the WebView implementation to fetch the flags
* from (generally this is the current WebView provider).
*/
public static boolean isDeveloperModeEnabled(String webViewPackageName) {
final Context context = ContextUtils.getApplicationContext();
ComponentName developerModeContentProvider =
new ComponentName(webViewPackageName, ServiceNames.DEVELOPER_MODE_CONTENT_PROVIDER);
int enabledState = context.getPackageManager().getComponentEnabledSetting(
developerModeContentProvider);
return enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
}
/**
* Fetch the flag overrides from the developer mode ContentProvider. This should only be called
* if {@link #isDeveloperModeEnabled(String}} returns {@code true}, otherwise this may incur
* unnecessary IPC or start up processes unnecessarily.
*
* @param webViewPackageName the package name of the WebView implementation to fetch the flags
* from (generally this is the current WebView provider).
*/
public static Map<String, Boolean> getFlagOverrides(String webViewPackageName) {
Map<String, Boolean> flagOverrides = new HashMap<>();
Uri uri = new Uri.Builder()
.scheme("content")
.authority(webViewPackageName + URI_AUTHORITY_SUFFIX)
.path(FLAG_OVERRIDE_URI_PATH)
.build();
final Context appContext = ContextUtils.getApplicationContext();
try (Cursor cursor = appContext.getContentResolver().query(uri, /* projection */ null,
/* selection */ null, /* selectionArgs */ null, /* sortOrder */ null)) {
assert cursor != null : "ContentProvider doesn't support querying '" + uri + "'";
int flagNameColumnIndex = cursor.getColumnIndexOrThrow(FLAG_OVERRIDE_NAME_COLUMN);
int flagStateColumnIndex = cursor.getColumnIndexOrThrow(FLAG_OVERRIDE_STATE_COLUMN);
while (cursor.moveToNext()) {
String flagName = cursor.getString(flagNameColumnIndex);
boolean flagState = cursor.getInt(flagStateColumnIndex) != 0;
flagOverrides.put(flagName, flagState);
}
}
return flagOverrides;
}
}
// 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.android_webview.common;
/**
* Constants to facilitate communication with {@code FlagOverrideContentProvider}.
*/
public final class FlagOverrideConstants {
// Do not instantiate this class.
private FlagOverrideConstants() {}
public static final String URI_AUTHORITY_SUFFIX = ".FlagOverrideContentProvider";
public static final String URI_PATH = "/flag-overrides";
public static final String FLAG_NAME_COLUMN = "flagName";
public static final String FLAG_STATE_COLUMN = "flagState";
}
......@@ -15,10 +15,10 @@ public class ServiceNames {
"org.chromium.android_webview.services.AwMinidumpUploadJobService";
public static final String CRASH_RECEIVER_SERVICE =
"org.chromium.android_webview.services.CrashReceiverService";
public static final String DEVELOPER_MODE_CONTENT_PROVIDER =
"org.chromium.android_webview.services.DeveloperModeContentProvider";
public static final String DEVELOPER_UI_SERVICE =
"org.chromium.android_webview.services.DeveloperUiService";
public static final String FLAG_OVERRIDE_CONTENT_PROVIDER =
"org.chromium.android_webview.services.FlagOverrideContentProvider";
public static final String VARIATIONS_SEED_SERVER =
"org.chromium.android_webview.services.VariationsSeedServer";
......
......@@ -14,8 +14,8 @@ import org.robolectric.annotation.Config;
import org.chromium.android_webview.common.services.ServiceNames;
import org.chromium.android_webview.services.AwMinidumpUploadJobService;
import org.chromium.android_webview.services.CrashReceiverService;
import org.chromium.android_webview.services.DeveloperModeContentProvider;
import org.chromium.android_webview.services.DeveloperUiService;
import org.chromium.android_webview.services.FlagOverrideContentProvider;
import org.chromium.android_webview.services.VariationsSeedServer;
import org.chromium.testing.local.LocalRobolectricTestRunner;
......@@ -31,11 +31,11 @@ public class ServiceNamesTest {
ServiceNames.AW_MINIDUMP_UPLOAD_JOB_SERVICE);
Assert.assertEquals("Incorrect class name constant", CrashReceiverService.class.getName(),
ServiceNames.CRASH_RECEIVER_SERVICE);
Assert.assertEquals("Incorrect class name constant",
DeveloperModeContentProvider.class.getName(),
ServiceNames.DEVELOPER_MODE_CONTENT_PROVIDER);
Assert.assertEquals("Incorrect class name constant", DeveloperUiService.class.getName(),
ServiceNames.DEVELOPER_UI_SERVICE);
Assert.assertEquals("Incorrect class name constant",
FlagOverrideContentProvider.class.getName(),
ServiceNames.FLAG_OVERRIDE_CONTENT_PROVIDER);
Assert.assertEquals("Incorrect class name constant", VariationsSeedServer.class.getName(),
ServiceNames.VARIATIONS_SEED_SERVER);
}
......
......@@ -72,8 +72,8 @@ android_library("services_java") {
"java/src/org/chromium/android_webview/services/AwMinidumpUploaderDelegate.java",
"java/src/org/chromium/android_webview/services/AwVariationsSeedFetcher.java",
"java/src/org/chromium/android_webview/services/CrashReceiverService.java",
"java/src/org/chromium/android_webview/services/DeveloperModeContentProvider.java",
"java/src/org/chromium/android_webview/services/DeveloperUiService.java",
"java/src/org/chromium/android_webview/services/FlagOverrideContentProvider.java",
"java/src/org/chromium/android_webview/services/VariationsSeedHolder.java",
"java/src/org/chromium/android_webview/services/VariationsSeedServer.java",
]
......
......@@ -73,10 +73,10 @@
android:authorities="{{ manifest_package }}.LicenseContentProvider"
android:process=":webview_apk" /> {# Explicit process required for monochrome compatibility. #}
<!-- Disabled by default, enabled at runtime by Developer UI. -->
<provider android:name="org.chromium.android_webview.services.FlagOverrideContentProvider"
<provider android:name="org.chromium.android_webview.services.DeveloperModeContentProvider"
android:exported="true"
android:enabled="false"
android:authorities="{{ manifest_package }}.FlagOverrideContentProvider"
android:authorities="{{ manifest_package }}.DeveloperModeContentProvider"
android:process=":webview_service" /> {# Explicit process required for monochrome compatibility. #}
{% if donor_package is not defined %}
<!-- If you change the variations services, also see
......
......@@ -10,9 +10,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
......@@ -27,13 +24,12 @@ import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import org.chromium.android_webview.common.DeveloperModeUtils;
import org.chromium.android_webview.common.Flag;
import org.chromium.android_webview.common.FlagOverrideConstants;
import org.chromium.android_webview.common.ProductionSupportedFlagList;
import org.chromium.android_webview.common.services.IDeveloperUiService;
import org.chromium.android_webview.common.services.ServiceNames;
import org.chromium.android_webview.devui.util.NavigationMenuHelper;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import java.util.HashMap;
......@@ -73,8 +69,8 @@ public class FlagsActivity extends Activity {
// Restore flag overrides from the service process to repopulate the UI, if developer mode
// is enabled.
if (isDeveloperModeEnabled(getPackageName())) {
mOverriddenFlags = getFlagOverrides(getPackageName());
if (DeveloperModeUtils.isDeveloperModeEnabled(getPackageName())) {
mOverriddenFlags = DeveloperModeUtils.getFlagOverrides(getPackageName());
}
mListAdapter = new FlagsListAdapter();
......@@ -237,62 +233,4 @@ public class FlagsActivity extends Activity {
mListAdapter.notifyDataSetChanged();
sendFlagsToService();
}
/**
* Quickly determine whether developer mode is enabled. Developer mode is off-by-default.
*
* <p>This makes no guarantees about which processes are alive, it only indicates whether the
* user has stepped in or out of "developer mode." Developer mode may be enabled and the
* ContentProvider process may be dead if the user has taken a WebView update since enabling
* developer mode.
*
* <p>TODO(ntfschr): move this to DeveloperModeUtils in common Java packaage.
*
* @param webViewPackageName the package name of the WebView implementation to fetch the flags
* from (generally this is the current WebView provider).
*/
public static boolean isDeveloperModeEnabled(String webViewPackageName) {
final Context context = ContextUtils.getApplicationContext();
ComponentName flagOverrideContentProvider =
new ComponentName(webViewPackageName, ServiceNames.FLAG_OVERRIDE_CONTENT_PROVIDER);
int enabledState =
context.getPackageManager().getComponentEnabledSetting(flagOverrideContentProvider);
return enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
}
/**
* Fetch the flag overrides from the developer mode ContentProvider. This should only be called
* if {@link #isDeveloperModeEnabled(String}} returns {@code true}, otherwise this may incur
* unnecessary IPC or start up processes unnecessarily.
*
* <p>TODO(ntfschr): move this to DeveloperModeUtils in common Java packaage.
*
* @param webViewPackageName the package name of the WebView implementation to fetch the flags
* from (generally this is the current WebView provider).
*/
public static Map<String, Boolean> getFlagOverrides(String webViewPackageName) {
Map<String, Boolean> flagOverrides = new HashMap<>();
Uri uri =
new Uri.Builder()
.scheme("content")
.authority(webViewPackageName + FlagOverrideConstants.URI_AUTHORITY_SUFFIX)
.path(FlagOverrideConstants.URI_PATH)
.build();
final Context appContext = ContextUtils.getApplicationContext();
try (Cursor cursor = appContext.getContentResolver().query(uri, /* projection */ null,
/* selection */ null, /* selectionArgs */ null, /* sortOrder */ null)) {
assert cursor != null : "ContentProvider doesn't support querying '" + uri + "'";
int flagNameColumnIndex =
cursor.getColumnIndexOrThrow(FlagOverrideConstants.FLAG_NAME_COLUMN);
int flagStateColumnIndex =
cursor.getColumnIndexOrThrow(FlagOverrideConstants.FLAG_STATE_COLUMN);
while (cursor.moveToNext()) {
String flagName = cursor.getString(flagNameColumnIndex);
boolean flagState = cursor.getInt(flagStateColumnIndex) != 0;
flagOverrides.put(flagName, flagState);
}
}
return flagOverrides;
}
}
......@@ -12,16 +12,16 @@ import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import org.chromium.android_webview.common.FlagOverrideConstants;
import org.chromium.android_webview.common.DeveloperModeUtils;
import java.util.Map;
/**
* A {@link ContentProvider} to fetch the flag overrides, via the {@code query()} method. No special
* A {@link ContentProvider} to fetch debugging data via the {@code query()} method. No special
* permissions are required to access this ContentProvider, and it can be accessed by any context
* (including the embedded WebView implementation).
*/
public final class FlagOverrideContentProvider extends ContentProvider {
public final class DeveloperModeContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return true;
......@@ -45,10 +45,10 @@ public final class FlagOverrideContentProvider extends ContentProvider {
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
if (FlagOverrideConstants.URI_PATH.equals(uri.getPath())) {
if (DeveloperModeUtils.FLAG_OVERRIDE_URI_PATH.equals(uri.getPath())) {
Map<String, Boolean> flagOverrides = DeveloperUiService.getFlagOverrides();
final String[] columns = {FlagOverrideConstants.FLAG_NAME_COLUMN,
FlagOverrideConstants.FLAG_STATE_COLUMN};
final String[] columns = {DeveloperModeUtils.FLAG_OVERRIDE_NAME_COLUMN,
DeveloperModeUtils.FLAG_OVERRIDE_STATE_COLUMN};
MatrixCursor cursor = new MatrixCursor(columns, flagOverrides.size());
for (Map.Entry<String, Boolean> entry : flagOverrides.entrySet()) {
String flagName = entry.getKey();
......@@ -64,9 +64,9 @@ public final class FlagOverrideContentProvider extends ContentProvider {
}
private void disableDeveloperMode() {
ComponentName flagOverrideContentProvider =
new ComponentName(getContext(), FlagOverrideContentProvider.class.getName());
getContext().getPackageManager().setComponentEnabledSetting(flagOverrideContentProvider,
ComponentName developerModeContentProvider =
new ComponentName(getContext(), DeveloperModeContentProvider.class.getName());
getContext().getPackageManager().setComponentEnabledSetting(developerModeContentProvider,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
// Stop the service explicitly, in case it's running. NOOP if the service is not running.
......
......@@ -130,9 +130,9 @@ public final class DeveloperUiService extends Service {
startService(new Intent(this, DeveloperUiService.class));
markAsForegroundService();
ComponentName flagOverrideContentProvider =
new ComponentName(this, FlagOverrideContentProvider.class.getName());
getPackageManager().setComponentEnabledSetting(flagOverrideContentProvider,
ComponentName developerModeContentProvider =
new ComponentName(this, DeveloperModeContentProvider.class.getName());
getPackageManager().setComponentEnabledSetting(developerModeContentProvider,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
mDeveloperModeEnabled = true;
......@@ -144,9 +144,9 @@ public final class DeveloperUiService extends Service {
if (!mDeveloperModeEnabled) return;
mDeveloperModeEnabled = false;
ComponentName flagOverrideContentProvider =
new ComponentName(this, FlagOverrideContentProvider.class.getName());
getPackageManager().setComponentEnabledSetting(flagOverrideContentProvider,
ComponentName developerModeContentProvider =
new ComponentName(this, DeveloperModeContentProvider.class.getName());
getPackageManager().setComponentEnabledSetting(developerModeContentProvider,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
// Finally, stop the service explicitly. Do this last to make sure we do the other
......
......@@ -1305,6 +1305,12 @@
android:path="/bookmarks/search_suggest_query"
android:readPermission="android.permission.GLOBAL_SEARCH"/>
</provider>
<provider
android:authorities="org.chromium.chrome.DeveloperModeContentProvider"
android:enabled="false"
android:exported="true"
android:name="org.chromium.android_webview.services.DeveloperModeContentProvider"
android:process=":webview_service"/>
<provider
android:authorities="org.chromium.chrome.DownloadFileProvider"
android:exported="false"
......@@ -1323,12 +1329,6 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
<provider
android:authorities="org.chromium.chrome.FlagOverrideContentProvider"
android:enabled="false"
android:exported="true"
android:name="org.chromium.android_webview.services.FlagOverrideContentProvider"
android:process=":webview_service"/>
<provider
android:authorities="org.chromium.chrome.LicenseContentProvider"
android:exported="true"
......
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