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

Commit fdd84fef authored by Gustav Sennton's avatar Gustav Sennton Committed by android-build-merger
Browse files

Merge "Add utility interface for WebView preparation logic." into nyc-dev

am: 79a23a09

* commit '79a23a09':
  Add utility interface for WebView preparation logic.
parents b1fb2061 79a23a09
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -53,6 +53,11 @@ interface IWebViewUpdateService {
     */
    WebViewProviderInfo[] getValidWebViewPackages();

    /**
     * Fetch all packages that could potentially implement WebView.
     */
    WebViewProviderInfo[] getAllWebViewPackages();

    /**
     * Used by DevelopmentSetting to get the name of the WebView provider currently in use.
     */
+1 −90
Original line number Diff line number Diff line
@@ -128,98 +128,9 @@ public final class WebViewFactory {
        public MissingWebViewPackageException(Exception e) { super(e); }
    }

    private static String TAG_START = "webviewproviders";
    private static String TAG_WEBVIEW_PROVIDER = "webviewprovider";
    private static String TAG_PACKAGE_NAME = "packageName";
    private static String TAG_DESCRIPTION = "description";
    // Whether or not the provider must be explicitly chosen by the user to be used.
    private static String TAG_AVAILABILITY = "availableByDefault";
    private static String TAG_SIGNATURE = "signature";
    private static String TAG_FALLBACK = "isFallback";

    /**
     * Reads all signatures at the current depth (within the current provider) from the XML parser.
     */
    private static String[] readSignatures(XmlResourceParser parser) throws IOException,
            XmlPullParserException {
        List<String> signatures = new ArrayList<String>();
        int outerDepth = parser.getDepth();
        while(XmlUtils.nextElementWithin(parser, outerDepth)) {
            if (parser.getName().equals(TAG_SIGNATURE)) {
                // Parse the value within the signature tag
                String signature = parser.nextText();
                signatures.add(signature);
            } else {
                Log.e(LOGTAG, "Found an element in a webview provider that is not a signature");
            }
        }
        return signatures.toArray(new String[signatures.size()]);
    }

    /**
     * Returns all packages declared in the framework resources as potential WebView providers.
     * @hide
     * */
    public static WebViewProviderInfo[] getWebViewPackages() {
        int numFallbackPackages = 0;
        XmlResourceParser parser = null;
        List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
        try {
            parser = AppGlobals.getInitialApplication().getResources().getXml(
                    com.android.internal.R.xml.config_webview_packages);
            XmlUtils.beginDocument(parser, TAG_START);
            while(true) {
                XmlUtils.nextElement(parser);
                String element = parser.getName();
                if (element == null) {
                    break;
                }
                if (element.equals(TAG_WEBVIEW_PROVIDER)) {
                    String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
                    if (packageName == null) {
                        throw new MissingWebViewPackageException(
                                "WebView provider in framework resources missing package name");
                    }
                    String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
                    if (description == null) {
                        throw new MissingWebViewPackageException(
                                "WebView provider in framework resources missing description");
                    }
                    boolean availableByDefault = "true".equals(
                            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()) {
                        numFallbackPackages++;
                        if (numFallbackPackages > 1) {
                            throw new AndroidRuntimeException(
                                    "There can be at most one webview fallback package.");
                        }
                    }
                    webViewProviders.add(currentProvider);
                }
                else {
                    Log.e(LOGTAG, "Found an element that is not a webview provider");
                }
            }
        } catch(XmlPullParserException e) {
            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
        } catch(IOException e) {
            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
        } finally {
            if (parser != null) parser.close();
        }
        return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
    }


    // TODO (gsennton) remove when committing webview xts test change
    public static String getWebViewPackageName() {
        WebViewProviderInfo[] providers = getWebViewPackages();
        return providers[0].packageName;
        return null;
    }

    /**
+4 −0
Original line number Diff line number Diff line
@@ -150,6 +150,8 @@ public class WebViewProviderInfo implements Parcelable {
    private WebViewProviderInfo(Parcel in) {
        packageName = in.readString();
        description = in.readString();
        availableByDefault = (in.readInt() > 0);
        isFallback = (in.readInt() > 0);
        signatures = in.createStringArray();
        packageInfo = null;
    }
@@ -163,6 +165,8 @@ public class WebViewProviderInfo implements Parcelable {
    public void writeToParcel(Parcel out, int flags) {
        out.writeString(packageName);
        out.writeString(description);
        out.writeInt(availableByDefault ? 1 : 0);
        out.writeInt(isFallback ? 1 : 0);
        out.writeStringArray(signatures);
    }

+25 −37
Original line number Diff line number Diff line
@@ -35,14 +35,14 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;
import android.webkit.WebViewFactory;

import com.android.server.SystemService;

@@ -76,9 +76,11 @@ public class WebViewUpdateService extends SystemService {
    private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;

    private BroadcastReceiver mWebViewUpdatedReceiver;
    private WebViewUtilityInterface mWebViewUtility;

    public WebViewUpdateService(Context context) {
        super(context);
        mWebViewUtility = new WebViewUtilityImpl();
    }

    @Override
@@ -114,7 +116,7 @@ public class WebViewUpdateService extends SystemService {

                    updateFallbackState(context, intent);

                    for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
                    for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
                        String webviewPackage = "package:" + provider.packageName;

                        if (webviewPackage.equals(intent.getDataString())) {
@@ -153,11 +155,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.
                                try {
                                    ActivityManagerNative.getDefault().killPackageDependents(
                                        oldProviderName, UserHandle.USER_ALL);
                                } catch (RemoteException e) {
                                }
                                mWebViewUtility.killPackageDependents(oldProviderName);
                            }
                            return;
                        }
@@ -170,7 +168,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 : WebViewFactory.getWebViewPackages()) {
        for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
            filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
        }
        getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
@@ -210,7 +208,7 @@ public class WebViewUpdateService extends SystemService {
    void handleNewUser(int userId) {
        if (!isFallbackLogicEnabled()) return;

        WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
        WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
        if (fallbackProvider == null) return;
        boolean existsValidNonFallbackProvider =
@@ -228,7 +226,7 @@ public class WebViewUpdateService extends SystemService {
    void updateFallbackState(final Context context, final Intent intent) {
        if (!isFallbackLogicEnabled()) return;

        WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
        WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();

        if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
                    || intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
@@ -319,10 +317,10 @@ public class WebViewUpdateService extends SystemService {
        return false;
    }

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

        WebViewProviderInfo[] webviewPackages = WebViewFactory.getWebViewPackages();
        WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
        WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
        return (fallbackProvider != null
                && packageName.equals(fallbackProvider.packageName));
@@ -359,13 +357,13 @@ public class WebViewUpdateService extends SystemService {
        PackageInfo newPackage = null;
        synchronized(this) {
            oldPackage = mCurrentWebViewPackage;
            updateUserSetting(newProviderName);
            mWebViewUtility.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.
                    updateUserSetting(newPackage.packageName);
                    mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
                    return newPackage.packageName;
                }
            } catch (WebViewFactory.MissingWebViewPackageException e) {
@@ -378,12 +376,8 @@ public class WebViewUpdateService extends SystemService {
            onWebViewProviderChanged(newPackage);
        }
        // Kill apps using the old provider
        try {
        if (oldPackage != null) {
                ActivityManagerNative.getDefault().killPackageDependents(
                        oldPackage.packageName, UserHandle.USER_ALL);
            }
        } catch (RemoteException e) {
            mWebViewUtility.killPackageDependents(oldPackage.packageName);
        }
        return newPackage.packageName;
    }
@@ -397,14 +391,14 @@ public class WebViewUpdateService extends SystemService {
            mAnyWebViewInstalled = true;
            if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
                mCurrentWebViewPackage = newPackage;
                updateUserSetting(newPackage.packageName);
                mWebViewUtility.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 = WebViewFactory.onWebViewProviderChanged(newPackage);
                mNumRelroCreationsStarted = mWebViewUtility.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();
@@ -421,7 +415,7 @@ public class WebViewUpdateService extends SystemService {
     * */
    private void updateValidWebViewPackages() {
        List<WebViewProviderInfo> webViewProviders  =
            new ArrayList<WebViewProviderInfo>(Arrays.asList(WebViewFactory.getWebViewPackages()));
            new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
        Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
        // remove non-valid packages
        while(it.hasNext()) {
@@ -435,17 +429,6 @@ public class WebViewUpdateService extends SystemService {
        }
    }

    private static String getUserChosenWebViewProvider() {
        return Settings.Global.getString(AppGlobals.getInitialApplication().getContentResolver(),
                Settings.Global.WEBVIEW_PROVIDER);
    }

    private void updateUserSetting(String newProviderName) {
        Settings.Global.putString(getContext().getContentResolver(),
                Settings.Global.WEBVIEW_PROVIDER,
                newProviderName == null ? "" : newProviderName);
    }

    /**
     * Returns either the package info of the WebView provider determined in the following way:
     * If the user has chosen a provider then use that if it is valid,
@@ -456,7 +439,7 @@ public class WebViewUpdateService extends SystemService {
    private PackageInfo findPreferredWebViewPackage() {
        WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;

        String userChosenProvider = getUserChosenWebViewProvider();
        String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());

        // If the user has chosen provider, use that
        for (WebViewProviderInfo provider : providers) {
@@ -615,6 +598,11 @@ public class WebViewUpdateService extends SystemService {
            }
        }

        @Override // Binder call
        public WebViewProviderInfo[] getAllWebViewPackages() {
            return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
        }

        @Override // Binder call
        public String getCurrentWebViewPackageName() {
            synchronized(WebViewUpdateService.this) {
@@ -626,7 +614,7 @@ public class WebViewUpdateService extends SystemService {

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

        @Override // Binder call
+161 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.webkit;

import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.res.XmlResourceParser;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactory.MissingWebViewPackageException;
import android.webkit.WebViewProviderInfo;

import com.android.internal.util.XmlUtils;

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
 */
public class WebViewUtilityImpl implements WebViewUtilityInterface {
    private static final String TAG = WebViewUtilityImpl.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";
    private static final String TAG_DESCRIPTION = "description";
    // Whether or not the provider must be explicitly chosen by the user to be used.
    private static final String TAG_AVAILABILITY = "availableByDefault";
    private static final String TAG_SIGNATURE = "signature";
    private static final String TAG_FALLBACK = "isFallback";

    /**
     * Returns all packages declared in the framework resources as potential WebView providers.
     * @hide
     * */
    @Override
    public WebViewProviderInfo[] getWebViewPackages() {
        int numFallbackPackages = 0;
        XmlResourceParser parser = null;
        List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
        try {
            parser = AppGlobals.getInitialApplication().getResources().getXml(
                    com.android.internal.R.xml.config_webview_packages);
            XmlUtils.beginDocument(parser, TAG_START);
            while(true) {
                XmlUtils.nextElement(parser);
                String element = parser.getName();
                if (element == null) {
                    break;
                }
                if (element.equals(TAG_WEBVIEW_PROVIDER)) {
                    String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
                    if (packageName == null) {
                        throw new MissingWebViewPackageException(
                                "WebView provider in framework resources missing package name");
                    }
                    String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
                    if (description == null) {
                        throw new MissingWebViewPackageException(
                                "WebView provider in framework resources missing description");
                    }
                    boolean availableByDefault = "true".equals(
                            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()) {
                        numFallbackPackages++;
                        if (numFallbackPackages > 1) {
                            throw new AndroidRuntimeException(
                                    "There can be at most one webview fallback package.");
                        }
                    }
                    webViewProviders.add(currentProvider);
                }
                else {
                    Log.e(TAG, "Found an element that is not a webview provider");
                }
            }
        } catch(XmlPullParserException e) {
            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
        } catch(IOException e) {
            throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
        } finally {
            if (parser != null) parser.close();
        }
        return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
    }

    /**
     * Reads all signatures at the current depth (within the current provider) from the XML parser.
     */
    private static String[] readSignatures(XmlResourceParser parser) throws IOException,
            XmlPullParserException {
        List<String> signatures = new ArrayList<String>();
        int outerDepth = parser.getDepth();
        while(XmlUtils.nextElementWithin(parser, outerDepth)) {
            if (parser.getName().equals(TAG_SIGNATURE)) {
                // Parse the value within the signature tag
                String signature = parser.nextText();
                signatures.add(signature);
            } else {
                Log.e(TAG, "Found an element in a webview provider that is not a signature");
            }
        }
        return signatures.toArray(new String[signatures.size()]);
    }

    @Override
    public int onWebViewProviderChanged(PackageInfo packageInfo) {
        return WebViewFactory.onWebViewProviderChanged(packageInfo);
    }

    @Override
    public String getUserChosenWebViewProvider(Context context) {
        return Settings.Global.getString(context.getContentResolver(),
                Settings.Global.WEBVIEW_PROVIDER);
    }

    @Override
    public void updateUserSetting(Context context, String newProviderName) {
        Settings.Global.putString(context.getContentResolver(),
                Settings.Global.WEBVIEW_PROVIDER,
                newProviderName == null ? "" : newProviderName);
    }

    @Override
    public void killPackageDependents(String packageName) {
        try {
            ActivityManagerNative.getDefault().killPackageDependents(packageName,
                    UserHandle.USER_ALL);
        } catch (RemoteException e) {
        }
    }
}
Loading