Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5cfd7f9 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Migrate away from WebView fallback logic."

parents 8ba502e6 ef47890d
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -77,11 +77,6 @@ interface IWebViewUpdateService {
    @UnsupportedAppUsage
    boolean isFallbackPackage(String packageName);

    /**
     * Enable or disable the WebView package fallback mechanism.
     */
    void enableFallbackLogic(boolean enable);

    /**
     * Used by Settings to determine whether multiprocess is enabled.
     */
+3 −33
Original line number Diff line number Diff line
@@ -19,19 +19,15 @@ package com.android.server.webkit;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.Context;
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.UserInfo;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
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;
@@ -42,12 +38,12 @@ import android.webkit.WebViewZygote;

import com.android.internal.util.XmlUtils;

import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParserException;

/**
 * Default implementation for the WebView preparation Utility interface.
 * @hide
@@ -77,7 +73,6 @@ public class SystemImpl implements SystemInterface {
    private SystemImpl() {
        int numFallbackPackages = 0;
        int numAvailableByDefaultPackages = 0;
        int numAvByDefaultAndNotFallback = 0;
        XmlResourceParser parser = null;
        List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
        try {
@@ -121,9 +116,6 @@ public class SystemImpl implements SystemInterface {
                    }
                    if (currentProvider.availableByDefault) {
                        numAvailableByDefaultPackages++;
                        if (!currentProvider.isFallback) {
                            numAvByDefaultAndNotFallback++;
                        }
                    }
                    webViewProviders.add(currentProvider);
                }
@@ -140,10 +132,6 @@ public class SystemImpl implements SystemInterface {
            throw new AndroidRuntimeException("There must be at least one WebView package "
                    + "that is available by default");
        }
        if (numAvByDefaultAndNotFallback == 0) {
            throw new AndroidRuntimeException("There must be at least one WebView package "
                    + "that is available by default and not a fallback");
        }
        mWebViewProviderPackages =
                webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
    }
@@ -221,23 +209,6 @@ public class SystemImpl implements SystemInterface {
                Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED, enable ? 1 : 0);
    }

    @Override
    public void uninstallAndDisablePackageForAllUsers(Context context, String packageName) {
        enablePackageForAllUsers(context, packageName, false);
        try {
            PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
            ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0);
            if (applicationInfo != null && applicationInfo.isUpdatedSystemApp()) {
                pm.deletePackage(packageName, new IPackageDeleteObserver.Stub() {
                        public void packageDeleted(String packageName, int returnCode) {
                            enablePackageForAllUsers(context, packageName, false);
                        }
                    }, PackageManager.DELETE_SYSTEM_APP | PackageManager.DELETE_ALL_USERS);
            }
        } catch (NameNotFoundException e) {
        }
    }

    @Override
    public void enablePackageForAllUsers(Context context, String packageName, boolean enable) {
        UserManager userManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
@@ -246,8 +217,7 @@ public class SystemImpl implements SystemInterface {
        }
    }

    @Override
    public void enablePackageForUser(String packageName, boolean enable, int userId) {
    private void enablePackageForUser(String packageName, boolean enable, int userId) {
        try {
            AppGlobals.getPackageManager().setApplicationEnabledSetting(
                    packageName,
+0 −3
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.server.webkit;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.ContentObserver;
import android.webkit.UserPackage;
import android.webkit.WebViewProviderInfo;

@@ -45,9 +44,7 @@ public interface SystemInterface {
    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)
+1 −22
Original line number Diff line number Diff line
@@ -242,28 +242,7 @@ public class WebViewUpdateService extends SystemService {

        @Override // Binder call
        public boolean isFallbackPackage(String packageName) {
            return WebViewUpdateService.this.mImpl.isFallbackPackage(packageName);
        }

        @Override // Binder call
        public void enableFallbackLogic(boolean enable) {
            if (getContext().checkCallingPermission(
                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
                    != PackageManager.PERMISSION_GRANTED) {
                String msg = "Permission Denial: enableFallbackLogic() from pid="
                        + Binder.getCallingPid()
                        + ", uid=" + Binder.getCallingUid()
                        + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }

            long callingId = Binder.clearCallingIdentity();
            try {
                WebViewUpdateService.this.mImpl.enableFallbackLogic(enable);
            } finally {
                Binder.restoreCallingIdentity(callingId);
            }
            return false;
        }

        @Override // Binder call
+21 −112
Original line number Diff line number Diff line
@@ -16,48 +16,36 @@
package com.android.server.webkit;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.Signature;
import android.os.UserHandle;
import android.util.Slog;
import android.webkit.UserPackage;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;

import java.io.PrintWriter;
import java.lang.Integer;
import java.util.List;

/**
 * Implementation of the WebViewUpdateService.
 * This class doesn't depend on the android system like the actual Service does and can be used
 * directly by tests (as long as they implement a SystemInterface).
 *
 * This class implements two main features - handling WebView fallback packages and keeping track
 * of, and preparing, the current WebView implementation. The fallback mechanism is meant to be
 * uncoupled from the rest of the WebView preparation and does not store any state. The code for
 * choosing and preparing a WebView implementation needs to keep track of a couple of different
 * things such as what package is used as WebView implementation.
 * This class keeps track of and prepares the current WebView implementation, and needs to keep
 * track of a couple of different things such as what package is used as WebView implementation.
 *
 * The public methods in this class are accessed from WebViewUpdateService either on the UI thread
 * or on one of multiple Binder threads. This means that the code in this class needs to be
 * thread-safe. The fallback mechanism shares (almost) no information between threads which makes
 * it easier to argue about thread-safety (in theory, if timed badly, the fallback mechanism can
 * incorrectly enable/disable a fallback package but that fault will be corrected when we later
 * receive an intent for that enabling/disabling). On the other hand, the WebView preparation code
 * shares state between threads meaning that code that chooses a new WebView implementation or
 * checks which implementation is being used needs to hold a lock.
 * or on one of multiple Binder threads. The WebView preparation code shares state between threads
 * meaning that code that chooses a new WebView implementation or checks which implementation is
 * being used needs to hold a lock.
 *
 * The WebViewUpdateService can be accessed in a couple of different ways.
 * 1. It is started from the SystemServer at boot - at that point we just initiate some state such
 * as the WebView preparation class.
 * 2. The SystemServer calls WebViewUpdateService.prepareWebViewInSystemServer. This happens at boot
 * and the WebViewUpdateService should not have been accessed before this call. In this call we
 * enable/disable fallback packages and then choose WebView implementation for the first time.
 * migrate away from the old fallback logic if necessary and then choose WebView implementation for
 * the first time.
 * 3. The update service listens for Intents related to package installs and removals. These intents
 * are received and processed on the UI thread. Each intent can result in enabling/disabling
 * fallback packages and changing WebView implementation.
 * are received and processed on the UI thread. Each intent can result in changing WebView
 * implementation.
 * 4. The update service can be reached through Binder calls which are handled on specific binder
 * threads. These calls can be made from any process. Generally they are used for changing WebView
 * implementation (from Settings), getting information about the current WebView implementation (for
@@ -86,35 +74,15 @@ public class WebViewUpdateServiceImpl {
        // We don't early out here in different cases where we could potentially early-out (e.g. if
        // we receive PACKAGE_CHANGED for another user than the system user) since that would
        // complicate this logic further and open up for more edge cases.
        updateFallbackStateOnPackageChange(packageName, changedState);
        mWebViewUpdater.packageStateChanged(packageName, changedState);
    }

    void prepareWebViewInSystemServer() {
        updateFallbackStateOnBoot();
        migrateFallbackStateOnBoot();
        mWebViewUpdater.prepareWebViewInSystemServer();
        mSystemInterface.notifyZygote(isMultiProcessEnabled());
    }

    private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
        for (WebViewProviderInfo provider : providers) {
            if (provider.availableByDefault && !provider.isFallback) {
                // userPackages can contain null objects.
                List<UserPackage> userPackages =
                        mSystemInterface.getPackageInfoForProviderAllUsers(mContext, provider);
                if (WebViewUpdater.isInstalledAndEnabledForAllUsers(userPackages) &&
                        // Checking validity of the package for the system user (rather than all
                        // users) since package validity depends not on the user but on the package
                        // itself.
                        mWebViewUpdater.isValidProvider(provider,
                                userPackages.get(UserHandle.USER_SYSTEM).getPackageInfo())) {
                    return true;
                }
            }
        }
        return false;
    }

    void handleNewUser(int userId) {
        // The system user is always started at boot, and by that point we have already run one
        // round of the package-changing logic (through prepareWebViewInSystemServer()), so early
@@ -128,14 +96,11 @@ public class WebViewUpdateServiceImpl {
    }

    /**
     * Called when a user was added or removed to ensure fallback logic and WebView preparation are
     * triggered. This has to be done since the WebView package we use depends on the enabled-state
     * Called when a user was added or removed to ensure WebView preparation is triggered.
     * This has to be done since the WebView package we use depends on the enabled-state
     * of packages for all users (so adding or removing a user might cause us to change package).
     */
    private void handleUserChange() {
        if (mSystemInterface.isFallbackLogicEnabled()) {
            updateFallbackState(mSystemInterface.getWebViewPackages());
        }
        // Potentially trigger package-changing logic.
        mWebViewUpdater.updateCurrentWebViewPackage(null);
    }
@@ -164,60 +129,22 @@ public class WebViewUpdateServiceImpl {
        return mWebViewUpdater.getCurrentWebViewPackage();
    }

    void enableFallbackLogic(boolean enable) {
        mSystemInterface.enableFallbackLogic(enable);
    }

    private void updateFallbackStateOnBoot() {
        if (!mSystemInterface.isFallbackLogicEnabled()) return;

        WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();
        updateFallbackState(webviewProviders);
    }

    /**
     * Handle the enabled-state of our fallback package, i.e. if there exists some non-fallback
     * package that is valid (and available by default) then disable the fallback package,
     * otherwise, enable the fallback package.
     * If the fallback logic is enabled, re-enable any fallback package for all users, then
     * disable the fallback logic.
     *
     * This migrates away from the old fallback mechanism to the new state where packages are never
     * automatically enableenableisabled.
     */
    private void updateFallbackStateOnPackageChange(String changedPackage, int changedState) {
    private void migrateFallbackStateOnBoot() {
        if (!mSystemInterface.isFallbackLogicEnabled()) return;

        WebViewProviderInfo[] webviewProviders = mSystemInterface.getWebViewPackages();

        // A package was changed / updated / downgraded, early out if it is not one of the
        // webview packages that are available by default.
        boolean changedPackageAvailableByDefault = false;
        for (WebViewProviderInfo provider : webviewProviders) {
            if (provider.packageName.equals(changedPackage)) {
                if (provider.availableByDefault) {
                    changedPackageAvailableByDefault = true;
                }
                break;
            }
        }
        if (!changedPackageAvailableByDefault) return;
        updateFallbackState(webviewProviders);
    }

    private void updateFallbackState(WebViewProviderInfo[] webviewProviders) {
        // If there exists a valid and enabled non-fallback package - disable the fallback
        // package, otherwise, enable it.
        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
        if (fallbackProvider == null) return;
        boolean existsValidNonFallbackProvider = existsValidNonFallbackProvider(webviewProviders);

        List<UserPackage> userPackages =
                mSystemInterface.getPackageInfoForProviderAllUsers(mContext, fallbackProvider);
        if (existsValidNonFallbackProvider && !isDisabledForAllUsers(userPackages)) {
            mSystemInterface.uninstallAndDisablePackageForAllUsers(mContext,
                    fallbackProvider.packageName);
        } else if (!existsValidNonFallbackProvider
                && !WebViewUpdater.isInstalledAndEnabledForAllUsers(userPackages)) {
            // Enable the fallback package for all users.
            mSystemInterface.enablePackageForAllUsers(mContext,
                    fallbackProvider.packageName, true);
        if (fallbackProvider != null) {
            mSystemInterface.enablePackageForAllUsers(mContext, fallbackProvider.packageName, true);
        }
        mSystemInterface.enableFallbackLogic(false);
    }

    /**
@@ -232,15 +159,6 @@ public class WebViewUpdateServiceImpl {
        return null;
    }

    boolean isFallbackPackage(String packageName) {
        if (packageName == null || !mSystemInterface.isFallbackLogicEnabled()) return false;

        WebViewProviderInfo[] webviewPackages = mSystemInterface.getWebViewPackages();
        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
        return (fallbackProvider != null
                && packageName.equals(fallbackProvider.packageName));
    }

    boolean isMultiProcessEnabled() {
        int settingValue = mSystemInterface.getMultiProcessSetting(mContext);
        if (mSystemInterface.isMultiProcessDefaultEnabled()) {
@@ -262,15 +180,6 @@ public class WebViewUpdateServiceImpl {
        }
    }

    private static boolean isDisabledForAllUsers(List<UserPackage> userPackages) {
        for (UserPackage userPackage : userPackages) {
            if (userPackage.getPackageInfo() != null && userPackage.isEnabledPackage()) {
                return false;
            }
        }
        return true;
    }

    /**
     * Dump the state of this Service.
     */
Loading