Merge "Simplify WebViewProviderInfo - move its logic into WebViewUpdateService." into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ef40c9acd5
@@ -16,32 +16,16 @@
|
||||
|
||||
package android.webkit;
|
||||
|
||||
import android.app.AppGlobals;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.Base64;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/** @hide */
|
||||
public class WebViewProviderInfo implements Parcelable {
|
||||
public final class WebViewProviderInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static class WebViewPackageNotFoundException extends AndroidRuntimeException {
|
||||
public WebViewPackageNotFoundException(String message) { super(message); }
|
||||
public WebViewPackageNotFoundException(Exception e) { super(e); }
|
||||
}
|
||||
|
||||
public WebViewProviderInfo(String packageName, String description, boolean availableByDefault,
|
||||
boolean isFallback, String[] signatures) {
|
||||
public WebViewProviderInfo(String packageName, String description,
|
||||
boolean availableByDefault, boolean isFallback, String[] signatures) {
|
||||
this.packageName = packageName;
|
||||
this.description = description;
|
||||
this.availableByDefault = availableByDefault;
|
||||
@@ -49,92 +33,6 @@ public class WebViewProviderInfo implements Parcelable {
|
||||
this.signatures = signatures;
|
||||
}
|
||||
|
||||
private boolean hasValidSignature() {
|
||||
if (Build.IS_DEBUGGABLE)
|
||||
return true;
|
||||
Signature[] packageSignatures;
|
||||
try {
|
||||
// If no signature is declared, instead check whether the package is included in the
|
||||
// system.
|
||||
if (signatures == null || signatures.length == 0)
|
||||
return getPackageInfo().applicationInfo.isSystemApp();
|
||||
|
||||
packageSignatures = getPackageInfo().signatures;
|
||||
} catch (WebViewPackageNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
if (packageSignatures.length != 1)
|
||||
return false;
|
||||
|
||||
final byte[] packageSignature = packageSignatures[0].toByteArray();
|
||||
// Return whether the package signature matches any of the valid signatures
|
||||
for (String signature : signatures) {
|
||||
final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
|
||||
if (Arrays.equals(packageSignature, validSignature))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this provider is valid for use as a WebView provider.
|
||||
*/
|
||||
public boolean isValidProvider() {
|
||||
ApplicationInfo applicationInfo;
|
||||
try {
|
||||
applicationInfo = getPackageInfo().applicationInfo;
|
||||
} catch (WebViewPackageNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
if (hasValidSignature() && WebViewFactory.getWebViewLibrary(applicationInfo) != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this package is enabled.
|
||||
* This state can be changed by the user from Settings->Apps
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
try {
|
||||
// Explicitly fetch up-to-date package info here since the enabled-state of the package
|
||||
// might have changed since we last fetched its package info.
|
||||
updatePackageInfo();
|
||||
return getPackageInfo().applicationInfo.enabled;
|
||||
} catch (WebViewPackageNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the provider is always available as long as it is valid.
|
||||
* If this returns false, the provider will only be used if the user chose this provider.
|
||||
*/
|
||||
public boolean isAvailableByDefault() {
|
||||
return availableByDefault;
|
||||
}
|
||||
|
||||
public boolean isFallbackPackage() {
|
||||
return isFallback;
|
||||
}
|
||||
|
||||
private void updatePackageInfo() {
|
||||
try {
|
||||
PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
|
||||
packageInfo = pm.getPackageInfo(packageName, PACKAGE_FLAGS);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new WebViewPackageNotFoundException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public PackageInfo getPackageInfo() {
|
||||
if (packageInfo == null) {
|
||||
updatePackageInfo();
|
||||
}
|
||||
return packageInfo;
|
||||
}
|
||||
|
||||
// aidl stuff
|
||||
public static final Parcelable.Creator<WebViewProviderInfo> CREATOR =
|
||||
new Parcelable.Creator<WebViewProviderInfo>() {
|
||||
@@ -153,7 +51,6 @@ public class WebViewProviderInfo implements Parcelable {
|
||||
availableByDefault = (in.readInt() > 0);
|
||||
isFallback = (in.readInt() > 0);
|
||||
signatures = in.createStringArray();
|
||||
packageInfo = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,16 +68,9 @@ public class WebViewProviderInfo implements Parcelable {
|
||||
}
|
||||
|
||||
// fields read from framework resource
|
||||
public String packageName;
|
||||
public String description;
|
||||
private boolean availableByDefault;
|
||||
private boolean isFallback;
|
||||
|
||||
private String[] signatures;
|
||||
|
||||
private PackageInfo packageInfo;
|
||||
|
||||
// flags declaring we want extra info from the package manager
|
||||
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
|
||||
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
|
||||
public final String packageName;
|
||||
public final String description;
|
||||
public final boolean availableByDefault;
|
||||
public final boolean isFallback;
|
||||
public final String[] signatures;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,11 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageDeleteObserver;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.PatternMatcher;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
@@ -38,6 +40,7 @@ import android.os.UserManager;
|
||||
import android.provider.Settings.Global;
|
||||
import android.provider.Settings;
|
||||
import android.util.AndroidRuntimeException;
|
||||
import android.util.Base64;
|
||||
import android.util.Slog;
|
||||
import android.webkit.IWebViewUpdateService;
|
||||
import android.webkit.WebViewFactory;
|
||||
@@ -72,8 +75,6 @@ public class WebViewUpdateService extends SystemService {
|
||||
|
||||
// The WebView package currently in use (or the one we are preparing).
|
||||
private PackageInfo mCurrentWebViewPackage = null;
|
||||
// The WebView providers that are currently available.
|
||||
private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
|
||||
|
||||
private BroadcastReceiver mWebViewUpdatedReceiver;
|
||||
private WebViewUtilityInterface mWebViewUtility;
|
||||
@@ -126,7 +127,6 @@ public class WebViewUpdateService extends SystemService {
|
||||
PackageInfo newPackage = null;
|
||||
synchronized(WebViewUpdateService.this) {
|
||||
try {
|
||||
updateValidWebViewPackages();
|
||||
newPackage = findPreferredWebViewPackage();
|
||||
if (mCurrentWebViewPackage != null)
|
||||
oldProviderName = mCurrentWebViewPackage.packageName;
|
||||
@@ -180,11 +180,17 @@ public class WebViewUpdateService extends SystemService {
|
||||
publishBinderService("webviewupdate", new BinderService(), true /*allowIsolated*/);
|
||||
}
|
||||
|
||||
private static boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
|
||||
private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
|
||||
for (WebViewProviderInfo provider : providers) {
|
||||
if (provider.isAvailableByDefault() && provider.isEnabled()
|
||||
&& provider.isValidProvider() && !provider.isFallbackPackage()) {
|
||||
return true;
|
||||
if (provider.availableByDefault && !provider.isFallback) {
|
||||
try {
|
||||
PackageInfo packageInfo = getPackageInfoForProvider(provider);
|
||||
if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) {
|
||||
return true;
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// A non-existent provider is neither valid nor enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -211,11 +217,9 @@ public class WebViewUpdateService extends SystemService {
|
||||
WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
|
||||
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
|
||||
if (fallbackProvider == null) return;
|
||||
boolean existsValidNonFallbackProvider =
|
||||
existsValidNonFallbackProvider(webviewProviders);
|
||||
|
||||
enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider,
|
||||
userId);
|
||||
enablePackageForUser(fallbackProvider.packageName,
|
||||
!existsValidNonFallbackProvider(webviewProviders), userId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,7 +240,7 @@ public class WebViewUpdateService extends SystemService {
|
||||
for (WebViewProviderInfo provider : webviewProviders) {
|
||||
String webviewPackage = "package:" + provider.packageName;
|
||||
if (webviewPackage.equals(intent.getDataString())) {
|
||||
if (provider.isAvailableByDefault()) {
|
||||
if (provider.availableByDefault) {
|
||||
changedPackage = provider.packageName;
|
||||
}
|
||||
break;
|
||||
@@ -251,10 +255,16 @@ public class WebViewUpdateService extends SystemService {
|
||||
if (fallbackProvider == null) return;
|
||||
boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);
|
||||
|
||||
boolean isFallbackEnabled = false;
|
||||
try {
|
||||
isFallbackEnabled = isEnabledPackage(getPackageInfoForProvider(fallbackProvider));
|
||||
} catch (NameNotFoundException e) {
|
||||
}
|
||||
|
||||
if (existsValidNonFallbackProvider
|
||||
// During an OTA the primary user's WebView state might differ from other users', so
|
||||
// ignore the state of that user during boot.
|
||||
&& (fallbackProvider.isEnabled() || intent == null)) {
|
||||
&& (isFallbackEnabled || intent == null)) {
|
||||
// Uninstall and disable fallback package for all users.
|
||||
context.getPackageManager().deletePackage(fallbackProvider.packageName,
|
||||
new IPackageDeleteObserver.Stub() {
|
||||
@@ -273,7 +283,7 @@ public class WebViewUpdateService extends SystemService {
|
||||
} else if (!existsValidNonFallbackProvider
|
||||
// During an OTA the primary user's WebView state might differ from other users', so
|
||||
// ignore the state of that user during boot.
|
||||
&& (!fallbackProvider.isEnabled() || intent==null)) {
|
||||
&& (!isFallbackEnabled || intent==null)) {
|
||||
// Enable the fallback package for all users.
|
||||
UserManager userManager =
|
||||
(UserManager)context.getSystemService(Context.USER_SERVICE);
|
||||
@@ -299,24 +309,13 @@ public class WebViewUpdateService extends SystemService {
|
||||
*/
|
||||
private static WebViewProviderInfo getFallbackProvider(WebViewProviderInfo[] webviewPackages) {
|
||||
for (WebViewProviderInfo provider : webviewPackages) {
|
||||
if (provider.isFallbackPackage()) {
|
||||
if (provider.isFallback) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean containsAvailableNonFallbackProvider(
|
||||
WebViewProviderInfo[] webviewPackages) {
|
||||
for (WebViewProviderInfo provider : webviewPackages) {
|
||||
if (provider.isAvailableByDefault() && provider.isEnabled()
|
||||
&& provider.isValidProvider() && !provider.isFallbackPackage()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isFallbackPackage(String packageName) {
|
||||
if (packageName == null || !isFallbackLogicEnabled()) return false;
|
||||
|
||||
@@ -336,7 +335,6 @@ public class WebViewUpdateService extends SystemService {
|
||||
updateFallbackState(getContext(), null);
|
||||
try {
|
||||
synchronized(this) {
|
||||
updateValidWebViewPackages();
|
||||
mCurrentWebViewPackage = findPreferredWebViewPackage();
|
||||
onWebViewProviderChanged(mCurrentWebViewPackage);
|
||||
}
|
||||
@@ -408,24 +406,41 @@ public class WebViewUpdateService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the currently valid WebView provider packages.
|
||||
* Should be used when a provider has been installed or removed.
|
||||
* @hide
|
||||
* */
|
||||
private void updateValidWebViewPackages() {
|
||||
List<WebViewProviderInfo> webViewProviders =
|
||||
new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
|
||||
Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
|
||||
// remove non-valid packages
|
||||
while(it.hasNext()) {
|
||||
WebViewProviderInfo current = it.next();
|
||||
if (!current.isValidProvider())
|
||||
it.remove();
|
||||
private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() {
|
||||
WebViewProviderInfo[] allProviders = mWebViewUtility.getWebViewPackages();
|
||||
List<ProviderAndPackageInfo> providers = new ArrayList<>();
|
||||
for(int n = 0; n < allProviders.length; n++) {
|
||||
try {
|
||||
PackageInfo packageInfo = getPackageInfoForProvider(allProviders[n]);
|
||||
if (isValidProvider(allProviders[n], packageInfo)) {
|
||||
providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo));
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
// Don't add non-existent packages
|
||||
}
|
||||
}
|
||||
synchronized(this) {
|
||||
mCurrentValidWebViewPackages =
|
||||
webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
|
||||
return providers.toArray(new ProviderAndPackageInfo[providers.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch only the currently valid WebView packages.
|
||||
**/
|
||||
private WebViewProviderInfo[] getValidWebViewPackages() {
|
||||
ProviderAndPackageInfo[] providersAndPackageInfos = getValidWebViewPackagesAndInfos();
|
||||
WebViewProviderInfo[] providers = new WebViewProviderInfo[providersAndPackageInfos.length];
|
||||
for(int n = 0; n < providersAndPackageInfos.length; n++) {
|
||||
providers[n] = providersAndPackageInfos[n].provider;
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
|
||||
private class ProviderAndPackageInfo {
|
||||
public final WebViewProviderInfo provider;
|
||||
public final PackageInfo packageInfo;
|
||||
|
||||
public ProviderAndPackageInfo(WebViewProviderInfo provider, PackageInfo packageInfo) {
|
||||
this.provider = provider;
|
||||
this.packageInfo = packageInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,28 +452,30 @@ public class WebViewUpdateService extends SystemService {
|
||||
* @hide
|
||||
*/
|
||||
private PackageInfo findPreferredWebViewPackage() {
|
||||
WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
|
||||
ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos();
|
||||
|
||||
String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
|
||||
|
||||
// If the user has chosen provider, use that
|
||||
for (WebViewProviderInfo provider : providers) {
|
||||
if (provider.packageName.equals(userChosenProvider) && provider.isEnabled()) {
|
||||
return provider.getPackageInfo();
|
||||
for (ProviderAndPackageInfo providerAndPackage : providers) {
|
||||
if (providerAndPackage.provider.packageName.equals(userChosenProvider)
|
||||
&& isEnabledPackage(providerAndPackage.packageInfo)) {
|
||||
return providerAndPackage.packageInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// User did not choose, or the choice failed; use the most stable provider that is
|
||||
// enabled and available by default (not through user choice).
|
||||
for (WebViewProviderInfo provider : providers) {
|
||||
if (provider.isAvailableByDefault() && provider.isEnabled()) {
|
||||
return provider.getPackageInfo();
|
||||
for (ProviderAndPackageInfo providerAndPackage : providers) {
|
||||
if (providerAndPackage.provider.availableByDefault
|
||||
&& isEnabledPackage(providerAndPackage.packageInfo)) {
|
||||
return providerAndPackage.packageInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find any enabled package either, use the most stable provider.
|
||||
for (WebViewProviderInfo provider : providers) {
|
||||
return provider.getPackageInfo();
|
||||
for (ProviderAndPackageInfo providerAndPackage : providers) {
|
||||
return providerAndPackage.packageInfo;
|
||||
}
|
||||
|
||||
mAnyWebViewInstalled = false;
|
||||
@@ -466,6 +483,60 @@ public class WebViewUpdateService extends SystemService {
|
||||
"Could not find a loadable WebView package");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this provider is valid for use as a WebView provider.
|
||||
*/
|
||||
private static boolean isValidProvider(WebViewProviderInfo configInfo,
|
||||
PackageInfo packageInfo) {
|
||||
if (providerHasValidSignature(configInfo, packageInfo) &&
|
||||
WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean providerHasValidSignature(WebViewProviderInfo provider,
|
||||
PackageInfo packageInfo) {
|
||||
if (Build.IS_DEBUGGABLE)
|
||||
return true;
|
||||
Signature[] packageSignatures;
|
||||
// If no signature is declared, instead check whether the package is included in the
|
||||
// system.
|
||||
if (provider.signatures == null || provider.signatures.length == 0) {
|
||||
return packageInfo.applicationInfo.isSystemApp();
|
||||
}
|
||||
packageSignatures = packageInfo.signatures;
|
||||
if (packageSignatures.length != 1)
|
||||
return false;
|
||||
|
||||
final byte[] packageSignature = packageSignatures[0].toByteArray();
|
||||
// Return whether the package signature matches any of the valid signatures
|
||||
for (String signature : provider.signatures) {
|
||||
final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
|
||||
if (Arrays.equals(packageSignature, validSignature))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given package is enabled.
|
||||
* This state can be changed by the user from Settings->Apps
|
||||
*/
|
||||
private static boolean isEnabledPackage(PackageInfo packageInfo) {
|
||||
return packageInfo.applicationInfo.enabled;
|
||||
}
|
||||
|
||||
private static PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
|
||||
throws NameNotFoundException {
|
||||
PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
|
||||
return pm.getPackageInfo(configInfo.packageName, PACKAGE_FLAGS);
|
||||
}
|
||||
|
||||
// flags declaring we want extra info from the package manager for webview providers
|
||||
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
|
||||
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
|
||||
|
||||
/**
|
||||
* Returns whether WebView is ready and is not going to go through its preparation phase again
|
||||
* directly.
|
||||
@@ -593,9 +664,7 @@ public class WebViewUpdateService extends SystemService {
|
||||
|
||||
@Override // Binder call
|
||||
public WebViewProviderInfo[] getValidWebViewPackages() {
|
||||
synchronized(WebViewUpdateService.this) {
|
||||
return mCurrentValidWebViewPackages;
|
||||
}
|
||||
return WebViewUpdateService.this.getValidWebViewPackages();
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
|
||||
@@ -87,10 +87,10 @@ public class WebViewUtilityImpl implements WebViewUtilityInterface {
|
||||
parser.getAttributeValue(null, TAG_AVAILABILITY));
|
||||
boolean isFallback = "true".equals(
|
||||
parser.getAttributeValue(null, TAG_FALLBACK));
|
||||
WebViewProviderInfo currentProvider =
|
||||
new WebViewProviderInfo(packageName, description, availableByDefault,
|
||||
isFallback, readSignatures(parser));
|
||||
if (currentProvider.isFallbackPackage()) {
|
||||
WebViewProviderInfo currentProvider = new WebViewProviderInfo(
|
||||
packageName, description, availableByDefault, isFallback,
|
||||
readSignatures(parser));
|
||||
if (currentProvider.isFallback) {
|
||||
numFallbackPackages++;
|
||||
if (numFallbackPackages > 1) {
|
||||
throw new AndroidRuntimeException(
|
||||
|
||||
Reference in New Issue
Block a user