blob: 85944b98b385d5fa134735b34ceb5df783a21c57 [file] [log] [blame]
// Copyright 2015 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;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.SQLException;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import org.chromium.base.CommandLine;
import java.lang.reflect.Field;
/**
* Controls data reduction proxy.
*/
public final class AwDataReductionProxyManager {
// The setting Uri. Used when querying GoogleSettings.
// TODO: This GoogleSettings Uri does not exist yet!
private static final Uri CONTENT_URI = Uri.parse("content://com.google.settings/partner");
// Setting name for allowing data reduction proxy. Used when querying GoogleSettings.
// Setting type: int ( 0 = disallow, 1 = allow )
private static final String WEBVIEW_DATA_REDUCTION_PROXY = "use_webview_data_reduction_proxy";
private static final String DRP_CLASS = "com.android.webview.chromium.Drp";
private static final String TAG = "DataReductionProxySettingListener";
// This is the same as Chromium data_reduction_proxy::switches::kEnableDataReductionProxy.
private static final String ENABLE_DATA_REDUCTION_PROXY = "enable-spdy-proxy-auth";
// This is the same as Chromium data_reduction_proxy::switches::kDataReductionProxyKey.
private static final String DATA_REDUCTION_PROXY_KEY = "spdy-proxy-auth-value";
private ContentObserver mProxySettingObserver;
public AwDataReductionProxyManager() {}
public void start(final Context context) {
// This is the DRP key embedded in WebView apk.
final String embeddedKey = readKey();
// Developers could test DRP by passing ENABLE_DATA_REDUCTION_PROXY and (optionally)
// DATA_REDUCTION_PROXY_KEY to the commandline switches. In this case, we will try to
// initialize DRP from commandline. And ignore user's preference. If
// DATA_REDUCTION_PROXY_KEY is specified in commandline, use it. Otherwise, use the key
// embedded in WebView apk.
CommandLine cl = CommandLine.getInstance();
if (cl.hasSwitch(ENABLE_DATA_REDUCTION_PROXY)) {
String key = cl.getSwitchValue(DATA_REDUCTION_PROXY_KEY, embeddedKey);
if (key == null || key.isEmpty()) {
return;
}
// Now we will enable DRP because we've got a commandline switch to enable it.
// We won't listen to Google Settings preference change because commandline switches
// trump that.
AwContentsStatics.setDataReductionProxyKey(key);
AwContentsStatics.setDataReductionProxyEnabled(true);
return;
}
// Now, there is no commandline switches to enable DRP, and reading the
// DRP key from WebView apk failed. Just return and leave DRP disabled.
if (embeddedKey == null || embeddedKey.isEmpty()) {
return;
}
applyDataReductionProxySettingsAsync(context, embeddedKey);
ContentResolver resolver = context.getContentResolver();
mProxySettingObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
applyDataReductionProxySettingsAsync(context, embeddedKey);
}
};
resolver.registerContentObserver(
Uri.withAppendedPath(CONTENT_URI, WEBVIEW_DATA_REDUCTION_PROXY), false,
mProxySettingObserver);
}
private String readKey() {
try {
Class<?> cls = Class.forName(DRP_CLASS);
Field f = cls.getField("KEY");
return (String) f.get(null);
} catch (ClassNotFoundException ex) {
Log.e(TAG, "No DRP key due to exception:" + ex);
} catch (NoSuchFieldException ex) {
Log.e(TAG, "No DRP key due to exception:" + ex);
} catch (SecurityException ex) {
Log.e(TAG, "No DRP key due to exception:" + ex);
} catch (IllegalArgumentException ex) {
Log.e(TAG, "No DRP key due to exception:" + ex);
} catch (IllegalAccessException ex) {
Log.e(TAG, "No DRP key due to exception:" + ex);
} catch (NullPointerException ex) {
Log.e(TAG, "No DRP key due to exception:" + ex);
}
return null;
}
private static void applyDataReductionProxySettingsAsync(
final Context context, final String key) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... params) {
return isDataReductionProxyEnabled(context);
}
@Override
protected void onPostExecute(Boolean enabled) {
if (enabled) {
// Set the data reduction proxy key.
AwContentsStatics.setDataReductionProxyKey(key);
}
AwContentsStatics.setDataReductionProxyEnabled(enabled);
}
};
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private static boolean isDataReductionProxyEnabled(Context context) {
return getProxySetting(context.getContentResolver(), WEBVIEW_DATA_REDUCTION_PROXY) != 0;
}
// Read query setting from GoogleSettings.
private static int getProxySetting(ContentResolver resolver, String name) {
String value = null;
Cursor c = null;
try {
c = resolver.query(
CONTENT_URI, new String[] {"value"}, "name=?", new String[] {name}, null);
if (c != null && c.moveToNext()) value = c.getString(0);
} catch (SQLException e) {
// SQL error: return null, but don't cache it.
Log.e(TAG, "Can't get key " + name + " from " + CONTENT_URI, e);
} finally {
if (c != null) c.close();
}
int enabled = 0;
try {
if (value != null) {
enabled = Integer.parseInt(value);
}
} catch (NumberFormatException e) {
Log.e(TAG, "cannot parse" + value, e);
}
return enabled;
}
}