Loading core/java/android/webkit/WebViewFactory.java +0 −13 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.Application; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; Loading Loading @@ -561,18 +560,6 @@ public final class WebViewFactory { return result; } /** * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather * than just one of its components). * @hide */ public static boolean entirePackageChanged(Intent intent) { String[] componentList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); return Arrays.asList(componentList).contains( intent.getDataString().substring("package:".length())); } private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate"; /** @hide */ Loading services/core/java/com/android/server/webkit/WebViewUtilityImpl.java→services/core/java/com/android/server/webkit/SystemImpl.java +73 −3 Original line number Diff line number Diff line Loading @@ -19,15 +19,22 @@ package com.android.server.webkit; import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.content.Context; 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.UserInfo; import android.content.res.XmlResourceParser; import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings.Global; import android.provider.Settings; import android.util.AndroidRuntimeException; import android.util.Log; import android.webkit.WebViewFactory; import android.webkit.WebViewFactory.MissingWebViewPackageException; import android.webkit.WebViewFactory; import android.webkit.WebViewProviderInfo; import com.android.internal.util.XmlUtils; Loading @@ -42,8 +49,8 @@ import org.xmlpull.v1.XmlPullParserException; * Default implementation for the WebView preparation Utility interface. * @hide */ public class WebViewUtilityImpl implements WebViewUtilityInterface { private static final String TAG = WebViewUtilityImpl.class.getSimpleName(); public class SystemImpl implements SystemInterface { private static final String TAG = SystemImpl.class.getSimpleName(); private static final String TAG_START = "webviewproviders"; private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider"; private static final String TAG_PACKAGE_NAME = "packageName"; Loading Loading @@ -158,4 +165,67 @@ public class WebViewUtilityImpl implements WebViewUtilityInterface { } catch (RemoteException e) { } } @Override public boolean isFallbackLogicEnabled() { // Note that this is enabled by default (i.e. if the setting hasn't been set). return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1; } @Override public void enableFallbackLogic(boolean enable) { Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0); } @Override public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) { context.getPackageManager().deletePackage(packageName, new IPackageDeleteObserver.Stub() { public void packageDeleted(String packageName, int returnCode) { // Ignore returnCode since the deletion could fail, e.g. we might be trying // to delete a non-updated system-package (and we should still disable the // package) enablePackageForAllUsers(context, packageName, false); } }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS); } @Override public void enablePackageForAllUsers(Context context, String packageName, boolean enable) { UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE); for(UserInfo userInfo : userManager.getUsers()) { enablePackageForUser(packageName, enable, userInfo.id); } } @Override public void enablePackageForUser(String packageName, boolean enable, int userId) { try { AppGlobals.getPackageManager().setApplicationEnabledSetting( packageName, enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT : PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0, userId, null); } catch (RemoteException e) { Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e); } } @Override public boolean systemIsDebuggable() { return Build.IS_DEBUGGABLE; } @Override public 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; } services/core/java/com/android/server/webkit/WebViewUtilityInterface.java→services/core/java/com/android/server/webkit/SystemInterface.java +16 −3 Original line number Diff line number Diff line Loading @@ -16,22 +16,35 @@ package com.android.server.webkit; import android.webkit.WebViewProviderInfo; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.webkit.WebViewProviderInfo; /** * Utility interface for the WebViewUpdateService. * System interface for the WebViewUpdateService. * This interface provides a way to test the WebView preparation mechanism - during normal use this * interface is implemented using calls to the Android framework, but by providing an alternative * implementation we can test the WebView preparation logic without reaching other framework code. * * @hide */ public interface WebViewUtilityInterface { public interface SystemInterface { public WebViewProviderInfo[] getWebViewPackages(); public int onWebViewProviderChanged(PackageInfo packageInfo); public String getUserChosenWebViewProvider(Context context); public void updateUserSetting(Context context, String newProviderName); public void killPackageDependents(String packageName); public boolean isFallbackLogicEnabled(); public void enableFallbackLogic(boolean enable); public void uninstallAndDisablePackageForAllUsers(Context context, String packageName); public void enablePackageForAllUsers(Context context, String packageName, boolean enable); public void enablePackageForUser(String packageName, boolean enable, int userId); public boolean systemIsDebuggable(); public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo) throws NameNotFoundException; } services/core/java/com/android/server/webkit/WebViewUpdateService.java +46 −92 Original line number Diff line number Diff line Loading @@ -16,30 +16,19 @@ package com.android.server.webkit; import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; 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; import android.os.ResultReceiver; import android.os.UserHandle; 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; Loading @@ -52,7 +41,6 @@ import com.android.server.SystemService; import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** Loading @@ -77,11 +65,11 @@ public class WebViewUpdateService extends SystemService { private PackageInfo mCurrentWebViewPackage = null; private BroadcastReceiver mWebViewUpdatedReceiver; private WebViewUtilityInterface mWebViewUtility; private SystemInterface mSystemInterface; public WebViewUpdateService(Context context) { super(context); mWebViewUtility = new WebViewUtilityImpl(); mSystemInterface = new SystemImpl(); } @Override Loading @@ -103,7 +91,7 @@ public class WebViewUpdateService extends SystemService { // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire // package, not just a component if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) { if (!WebViewFactory.entirePackageChanged(intent)) { if (!entirePackageChanged(intent)) { return; } } Loading @@ -117,7 +105,7 @@ public class WebViewUpdateService extends SystemService { updateFallbackState(context, intent); for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) { for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) { String webviewPackage = "package:" + provider.packageName; if (webviewPackage.equals(intent.getDataString())) { Loading Loading @@ -155,7 +143,7 @@ public class WebViewUpdateService extends SystemService { // package that was not the previous provider then we must kill // packages dependent on the old package ourselves. The framework // only kills dependents of packages that are being removed. mWebViewUtility.killPackageDependents(oldProviderName); mSystemInterface.killPackageDependents(oldProviderName); } return; } Loading @@ -168,7 +156,7 @@ public class WebViewUpdateService extends SystemService { filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); // Make sure we only receive intents for WebView packages from our config file. for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) { for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) { filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL); } getContext().registerReceiver(mWebViewUpdatedReceiver, filter); Loading @@ -184,7 +172,7 @@ public class WebViewUpdateService extends SystemService { for (WebViewProviderInfo provider : providers) { if (provider.availableByDefault && !provider.isFallback) { try { PackageInfo packageInfo = getPackageInfoForProvider(provider); PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider); if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) { return true; } Loading @@ -196,29 +184,17 @@ public class WebViewUpdateService extends SystemService { return false; } private static void enablePackageForUser(String packageName, boolean enable, int userId) { try { AppGlobals.getPackageManager().setApplicationEnabledSetting( packageName, enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT : PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0, userId, null); } catch (RemoteException e) { Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e); } } /** * Called when a new user has been added to update the state of its fallback package. */ void handleNewUser(int userId) { if (!isFallbackLogicEnabled()) return; if (!mSystemInterface.isFallbackLogicEnabled()) return; WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages(); WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders); if (fallbackProvider == null) return; enablePackageForUser(fallbackProvider.packageName, mSystemInterface.enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider(webviewProviders), userId); } Loading @@ -228,9 +204,9 @@ public class WebViewUpdateService extends SystemService { * otherwise, enable the fallback package. */ void updateFallbackState(final Context context, final Intent intent) { if (!isFallbackLogicEnabled()) return; if (!mSystemInterface.isFallbackLogicEnabled()) return; WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages(); if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED) || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) { Loading @@ -257,7 +233,8 @@ public class WebViewUpdateService extends SystemService { boolean isFallbackEnabled = false; try { isFallbackEnabled = isEnabledPackage(getPackageInfoForProvider(fallbackProvider)); isFallbackEnabled = isEnabledPackage(mSystemInterface.getPackageInfoForProvider(fallbackProvider)); } catch (NameNotFoundException e) { } Loading @@ -265,44 +242,16 @@ public class WebViewUpdateService extends SystemService { // During an OTA the primary user's WebView state might differ from other users', so // ignore the state of that user during boot. && (isFallbackEnabled || intent == null)) { // Uninstall and disable fallback package for all users. context.getPackageManager().deletePackage(fallbackProvider.packageName, new IPackageDeleteObserver.Stub() { public void packageDeleted(String packageName, int returnCode) { // Ignore returnCode since the deletion could fail, e.g. we might be trying // to delete a non-updated system-package (and we should still disable the // package) UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE); // Disable the fallback package for all users. for(UserInfo userInfo : userManager.getUsers()) { enablePackageForUser(packageName, false, userInfo.id); } } }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS); mSystemInterface.uninstallAndDisablePackageForAllUsers(context, fallbackProvider.packageName); } 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. && (!isFallbackEnabled || intent==null)) { // Enable the fallback package for all users. UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE); for(UserInfo userInfo : userManager.getUsers()) { enablePackageForUser(fallbackProvider.packageName, true, userInfo.id); mSystemInterface.enablePackageForAllUsers(context, fallbackProvider.packageName, true); } } } private static boolean isFallbackLogicEnabled() { // Note that this is enabled by default (i.e. if the setting hasn't been set). return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1; } private static void enableFallbackLogic(boolean enable) { Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0); } /** * Returns the only fallback provider, or null if there is none. Loading @@ -317,9 +266,9 @@ public class WebViewUpdateService extends SystemService { } private boolean isFallbackPackage(String packageName) { if (packageName == null || !isFallbackLogicEnabled()) return false; if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false; WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages(); WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages); return (fallbackProvider != null && packageName.equals(fallbackProvider.packageName)); Loading Loading @@ -355,13 +304,13 @@ public class WebViewUpdateService extends SystemService { PackageInfo newPackage = null; synchronized(this) { oldPackage = mCurrentWebViewPackage; mWebViewUtility.updateUserSetting(getContext(), newProviderName); mSystemInterface.updateUserSetting(getContext(), newProviderName); try { newPackage = findPreferredWebViewPackage(); if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) { // If we don't perform the user change, revert the settings change. mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName); mSystemInterface.updateUserSetting(getContext(), newPackage.packageName); return newPackage.packageName; } } catch (WebViewFactory.MissingWebViewPackageException e) { Loading @@ -375,7 +324,7 @@ public class WebViewUpdateService extends SystemService { } // Kill apps using the old provider if (oldPackage != null) { mWebViewUtility.killPackageDependents(oldPackage.packageName); mSystemInterface.killPackageDependents(oldPackage.packageName); } return newPackage.packageName; } Loading @@ -389,14 +338,14 @@ public class WebViewUpdateService extends SystemService { mAnyWebViewInstalled = true; if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) { mCurrentWebViewPackage = newPackage; mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName); mSystemInterface.updateUserSetting(getContext(), newPackage.packageName); // The relro creations might 'finish' (not start at all) before // WebViewFactory.onWebViewProviderChanged which means we might not know the number // of started creations before they finish. mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN; mNumRelroCreationsFinished = 0; mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage); mNumRelroCreationsStarted = mSystemInterface.onWebViewProviderChanged(newPackage); // If the relro creations finish before we know the number of started creations we // will have to do any cleanup/notifying here. checkIfRelrosDoneLocked(); Loading @@ -407,11 +356,12 @@ public class WebViewUpdateService extends SystemService { } private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() { WebViewProviderInfo[] allProviders = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages(); List<ProviderAndPackageInfo> providers = new ArrayList<>(); for(int n = 0; n < allProviders.length; n++) { try { PackageInfo packageInfo = getPackageInfoForProvider(allProviders[n]); PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(allProviders[n]); if (isValidProvider(allProviders[n], packageInfo)) { providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo)); } Loading Loading @@ -454,7 +404,7 @@ public class WebViewUpdateService extends SystemService { private PackageInfo findPreferredWebViewPackage() { ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos(); String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext()); String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(getContext()); // If the user has chosen provider, use that for (ProviderAndPackageInfo providerAndPackage : providers) { Loading Loading @@ -483,10 +433,11 @@ 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, public boolean isValidProvider(WebViewProviderInfo configInfo, PackageInfo packageInfo) { if (providerHasValidSignature(configInfo, packageInfo) && WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) { Loading @@ -495,10 +446,11 @@ public class WebViewUpdateService extends SystemService { return false; } private static boolean providerHasValidSignature(WebViewProviderInfo provider, private boolean providerHasValidSignature(WebViewProviderInfo provider, PackageInfo packageInfo) { if (Build.IS_DEBUGGABLE) if (mSystemInterface.systemIsDebuggable()) { return true; } Signature[] packageSignatures; // If no signature is declared, instead check whether the package is included in the // system. Loading @@ -523,20 +475,22 @@ public class WebViewUpdateService extends SystemService { * Returns whether the given package is enabled. * This state can be changed by the user from Settings->Apps */ private static boolean isEnabledPackage(PackageInfo packageInfo) { public 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); /** * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather * than just one of its components). * @hide */ public static boolean entirePackageChanged(Intent intent) { String[] componentList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); return Arrays.asList(componentList).contains( intent.getDataString().substring("package:".length())); } // 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. Loading Loading @@ -669,7 +623,7 @@ public class WebViewUpdateService extends SystemService { @Override // Binder call public WebViewProviderInfo[] getAllWebViewPackages() { return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages(); return WebViewUpdateService.this.mSystemInterface.getWebViewPackages(); } @Override // Binder call Loading Loading @@ -699,7 +653,7 @@ public class WebViewUpdateService extends SystemService { throw new SecurityException(msg); } WebViewUpdateService.enableFallbackLogic(enable); WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable); } } } Loading
core/java/android/webkit/WebViewFactory.java +0 −13 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.Application; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; Loading Loading @@ -561,18 +560,6 @@ public final class WebViewFactory { return result; } /** * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather * than just one of its components). * @hide */ public static boolean entirePackageChanged(Intent intent) { String[] componentList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); return Arrays.asList(componentList).contains( intent.getDataString().substring("package:".length())); } private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate"; /** @hide */ Loading
services/core/java/com/android/server/webkit/WebViewUtilityImpl.java→services/core/java/com/android/server/webkit/SystemImpl.java +73 −3 Original line number Diff line number Diff line Loading @@ -19,15 +19,22 @@ package com.android.server.webkit; import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.content.Context; 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.UserInfo; import android.content.res.XmlResourceParser; import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings.Global; import android.provider.Settings; import android.util.AndroidRuntimeException; import android.util.Log; import android.webkit.WebViewFactory; import android.webkit.WebViewFactory.MissingWebViewPackageException; import android.webkit.WebViewFactory; import android.webkit.WebViewProviderInfo; import com.android.internal.util.XmlUtils; Loading @@ -42,8 +49,8 @@ import org.xmlpull.v1.XmlPullParserException; * Default implementation for the WebView preparation Utility interface. * @hide */ public class WebViewUtilityImpl implements WebViewUtilityInterface { private static final String TAG = WebViewUtilityImpl.class.getSimpleName(); public class SystemImpl implements SystemInterface { private static final String TAG = SystemImpl.class.getSimpleName(); private static final String TAG_START = "webviewproviders"; private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider"; private static final String TAG_PACKAGE_NAME = "packageName"; Loading Loading @@ -158,4 +165,67 @@ public class WebViewUtilityImpl implements WebViewUtilityInterface { } catch (RemoteException e) { } } @Override public boolean isFallbackLogicEnabled() { // Note that this is enabled by default (i.e. if the setting hasn't been set). return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1; } @Override public void enableFallbackLogic(boolean enable) { Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0); } @Override public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) { context.getPackageManager().deletePackage(packageName, new IPackageDeleteObserver.Stub() { public void packageDeleted(String packageName, int returnCode) { // Ignore returnCode since the deletion could fail, e.g. we might be trying // to delete a non-updated system-package (and we should still disable the // package) enablePackageForAllUsers(context, packageName, false); } }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS); } @Override public void enablePackageForAllUsers(Context context, String packageName, boolean enable) { UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE); for(UserInfo userInfo : userManager.getUsers()) { enablePackageForUser(packageName, enable, userInfo.id); } } @Override public void enablePackageForUser(String packageName, boolean enable, int userId) { try { AppGlobals.getPackageManager().setApplicationEnabledSetting( packageName, enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT : PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0, userId, null); } catch (RemoteException e) { Log.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e); } } @Override public boolean systemIsDebuggable() { return Build.IS_DEBUGGABLE; } @Override public 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; }
services/core/java/com/android/server/webkit/WebViewUtilityInterface.java→services/core/java/com/android/server/webkit/SystemInterface.java +16 −3 Original line number Diff line number Diff line Loading @@ -16,22 +16,35 @@ package com.android.server.webkit; import android.webkit.WebViewProviderInfo; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.webkit.WebViewProviderInfo; /** * Utility interface for the WebViewUpdateService. * System interface for the WebViewUpdateService. * This interface provides a way to test the WebView preparation mechanism - during normal use this * interface is implemented using calls to the Android framework, but by providing an alternative * implementation we can test the WebView preparation logic without reaching other framework code. * * @hide */ public interface WebViewUtilityInterface { public interface SystemInterface { public WebViewProviderInfo[] getWebViewPackages(); public int onWebViewProviderChanged(PackageInfo packageInfo); public String getUserChosenWebViewProvider(Context context); public void updateUserSetting(Context context, String newProviderName); public void killPackageDependents(String packageName); public boolean isFallbackLogicEnabled(); public void enableFallbackLogic(boolean enable); public void uninstallAndDisablePackageForAllUsers(Context context, String packageName); public void enablePackageForAllUsers(Context context, String packageName, boolean enable); public void enablePackageForUser(String packageName, boolean enable, int userId); public boolean systemIsDebuggable(); public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo) throws NameNotFoundException; }
services/core/java/com/android/server/webkit/WebViewUpdateService.java +46 −92 Original line number Diff line number Diff line Loading @@ -16,30 +16,19 @@ package com.android.server.webkit; import android.app.ActivityManagerNative; import android.app.AppGlobals; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; 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; import android.os.ResultReceiver; import android.os.UserHandle; 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; Loading @@ -52,7 +41,6 @@ import com.android.server.SystemService; import java.io.FileDescriptor; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** Loading @@ -77,11 +65,11 @@ public class WebViewUpdateService extends SystemService { private PackageInfo mCurrentWebViewPackage = null; private BroadcastReceiver mWebViewUpdatedReceiver; private WebViewUtilityInterface mWebViewUtility; private SystemInterface mSystemInterface; public WebViewUpdateService(Context context) { super(context); mWebViewUtility = new WebViewUtilityImpl(); mSystemInterface = new SystemImpl(); } @Override Loading @@ -103,7 +91,7 @@ public class WebViewUpdateService extends SystemService { // Ensure that we only heed PACKAGE_CHANGED intents if they change an entire // package, not just a component if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) { if (!WebViewFactory.entirePackageChanged(intent)) { if (!entirePackageChanged(intent)) { return; } } Loading @@ -117,7 +105,7 @@ public class WebViewUpdateService extends SystemService { updateFallbackState(context, intent); for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) { for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) { String webviewPackage = "package:" + provider.packageName; if (webviewPackage.equals(intent.getDataString())) { Loading Loading @@ -155,7 +143,7 @@ public class WebViewUpdateService extends SystemService { // package that was not the previous provider then we must kill // packages dependent on the old package ourselves. The framework // only kills dependents of packages that are being removed. mWebViewUtility.killPackageDependents(oldProviderName); mSystemInterface.killPackageDependents(oldProviderName); } return; } Loading @@ -168,7 +156,7 @@ public class WebViewUpdateService extends SystemService { filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); // Make sure we only receive intents for WebView packages from our config file. for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) { for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) { filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL); } getContext().registerReceiver(mWebViewUpdatedReceiver, filter); Loading @@ -184,7 +172,7 @@ public class WebViewUpdateService extends SystemService { for (WebViewProviderInfo provider : providers) { if (provider.availableByDefault && !provider.isFallback) { try { PackageInfo packageInfo = getPackageInfoForProvider(provider); PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(provider); if (isEnabledPackage(packageInfo) && isValidProvider(provider, packageInfo)) { return true; } Loading @@ -196,29 +184,17 @@ public class WebViewUpdateService extends SystemService { return false; } private static void enablePackageForUser(String packageName, boolean enable, int userId) { try { AppGlobals.getPackageManager().setApplicationEnabledSetting( packageName, enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT : PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0, userId, null); } catch (RemoteException e) { Slog.w(TAG, "Tried to disable " + packageName + " for user " + userId + ": " + e); } } /** * Called when a new user has been added to update the state of its fallback package. */ void handleNewUser(int userId) { if (!isFallbackLogicEnabled()) return; if (!mSystemInterface.isFallbackLogicEnabled()) return; WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages(); WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders); if (fallbackProvider == null) return; enablePackageForUser(fallbackProvider.packageName, mSystemInterface.enablePackageForUser(fallbackProvider.packageName, !existsValidNonFallbackProvider(webviewProviders), userId); } Loading @@ -228,9 +204,9 @@ public class WebViewUpdateService extends SystemService { * otherwise, enable the fallback package. */ void updateFallbackState(final Context context, final Intent intent) { if (!isFallbackLogicEnabled()) return; if (!mSystemInterface.isFallbackLogicEnabled()) return; WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages(); if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED) || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) { Loading @@ -257,7 +233,8 @@ public class WebViewUpdateService extends SystemService { boolean isFallbackEnabled = false; try { isFallbackEnabled = isEnabledPackage(getPackageInfoForProvider(fallbackProvider)); isFallbackEnabled = isEnabledPackage(mSystemInterface.getPackageInfoForProvider(fallbackProvider)); } catch (NameNotFoundException e) { } Loading @@ -265,44 +242,16 @@ public class WebViewUpdateService extends SystemService { // During an OTA the primary user's WebView state might differ from other users', so // ignore the state of that user during boot. && (isFallbackEnabled || intent == null)) { // Uninstall and disable fallback package for all users. context.getPackageManager().deletePackage(fallbackProvider.packageName, new IPackageDeleteObserver.Stub() { public void packageDeleted(String packageName, int returnCode) { // Ignore returnCode since the deletion could fail, e.g. we might be trying // to delete a non-updated system-package (and we should still disable the // package) UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE); // Disable the fallback package for all users. for(UserInfo userInfo : userManager.getUsers()) { enablePackageForUser(packageName, false, userInfo.id); } } }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS); mSystemInterface.uninstallAndDisablePackageForAllUsers(context, fallbackProvider.packageName); } 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. && (!isFallbackEnabled || intent==null)) { // Enable the fallback package for all users. UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE); for(UserInfo userInfo : userManager.getUsers()) { enablePackageForUser(fallbackProvider.packageName, true, userInfo.id); mSystemInterface.enablePackageForAllUsers(context, fallbackProvider.packageName, true); } } } private static boolean isFallbackLogicEnabled() { // Note that this is enabled by default (i.e. if the setting hasn't been set). return Settings.Global.getInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, 1) == 1; } private static void enableFallbackLogic(boolean enable) { Settings.Global.putInt(AppGlobals.getInitialApplication().getContentResolver(), Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0); } /** * Returns the only fallback provider, or null if there is none. Loading @@ -317,9 +266,9 @@ public class WebViewUpdateService extends SystemService { } private boolean isFallbackPackage(String packageName) { if (packageName == null || !isFallbackLogicEnabled()) return false; if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false; WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages(); WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages); return (fallbackProvider != null && packageName.equals(fallbackProvider.packageName)); Loading Loading @@ -355,13 +304,13 @@ public class WebViewUpdateService extends SystemService { PackageInfo newPackage = null; synchronized(this) { oldPackage = mCurrentWebViewPackage; mWebViewUtility.updateUserSetting(getContext(), newProviderName); mSystemInterface.updateUserSetting(getContext(), newProviderName); try { newPackage = findPreferredWebViewPackage(); if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) { // If we don't perform the user change, revert the settings change. mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName); mSystemInterface.updateUserSetting(getContext(), newPackage.packageName); return newPackage.packageName; } } catch (WebViewFactory.MissingWebViewPackageException e) { Loading @@ -375,7 +324,7 @@ public class WebViewUpdateService extends SystemService { } // Kill apps using the old provider if (oldPackage != null) { mWebViewUtility.killPackageDependents(oldPackage.packageName); mSystemInterface.killPackageDependents(oldPackage.packageName); } return newPackage.packageName; } Loading @@ -389,14 +338,14 @@ public class WebViewUpdateService extends SystemService { mAnyWebViewInstalled = true; if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) { mCurrentWebViewPackage = newPackage; mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName); mSystemInterface.updateUserSetting(getContext(), newPackage.packageName); // The relro creations might 'finish' (not start at all) before // WebViewFactory.onWebViewProviderChanged which means we might not know the number // of started creations before they finish. mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN; mNumRelroCreationsFinished = 0; mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage); mNumRelroCreationsStarted = mSystemInterface.onWebViewProviderChanged(newPackage); // If the relro creations finish before we know the number of started creations we // will have to do any cleanup/notifying here. checkIfRelrosDoneLocked(); Loading @@ -407,11 +356,12 @@ public class WebViewUpdateService extends SystemService { } private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos() { WebViewProviderInfo[] allProviders = mWebViewUtility.getWebViewPackages(); WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages(); List<ProviderAndPackageInfo> providers = new ArrayList<>(); for(int n = 0; n < allProviders.length; n++) { try { PackageInfo packageInfo = getPackageInfoForProvider(allProviders[n]); PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(allProviders[n]); if (isValidProvider(allProviders[n], packageInfo)) { providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo)); } Loading Loading @@ -454,7 +404,7 @@ public class WebViewUpdateService extends SystemService { private PackageInfo findPreferredWebViewPackage() { ProviderAndPackageInfo[] providers = getValidWebViewPackagesAndInfos(); String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext()); String userChosenProvider = mSystemInterface.getUserChosenWebViewProvider(getContext()); // If the user has chosen provider, use that for (ProviderAndPackageInfo providerAndPackage : providers) { Loading Loading @@ -483,10 +433,11 @@ 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, public boolean isValidProvider(WebViewProviderInfo configInfo, PackageInfo packageInfo) { if (providerHasValidSignature(configInfo, packageInfo) && WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo) != null) { Loading @@ -495,10 +446,11 @@ public class WebViewUpdateService extends SystemService { return false; } private static boolean providerHasValidSignature(WebViewProviderInfo provider, private boolean providerHasValidSignature(WebViewProviderInfo provider, PackageInfo packageInfo) { if (Build.IS_DEBUGGABLE) if (mSystemInterface.systemIsDebuggable()) { return true; } Signature[] packageSignatures; // If no signature is declared, instead check whether the package is included in the // system. Loading @@ -523,20 +475,22 @@ public class WebViewUpdateService extends SystemService { * Returns whether the given package is enabled. * This state can be changed by the user from Settings->Apps */ private static boolean isEnabledPackage(PackageInfo packageInfo) { public 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); /** * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather * than just one of its components). * @hide */ public static boolean entirePackageChanged(Intent intent) { String[] componentList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); return Arrays.asList(componentList).contains( intent.getDataString().substring("package:".length())); } // 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. Loading Loading @@ -669,7 +623,7 @@ public class WebViewUpdateService extends SystemService { @Override // Binder call public WebViewProviderInfo[] getAllWebViewPackages() { return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages(); return WebViewUpdateService.this.mSystemInterface.getWebViewPackages(); } @Override // Binder call Loading Loading @@ -699,7 +653,7 @@ public class WebViewUpdateService extends SystemService { throw new SecurityException(msg); } WebViewUpdateService.enableFallbackLogic(enable); WebViewUpdateService.this.mSystemInterface.enableFallbackLogic(enable); } } }