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

Commit 41d5e93b authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

Move APK monitoring into WebView.

This CL adds the monitoring logic that was removed from the Browser
in a companion CL.  This allows applications other than the Browser
to use special features offered by YouTube and plugins. Additionally,
the pluginManager was refactored to prevent code duplication between
the manager and WebView.

Change-Id: Ie37f248c8edd9d06ae1fd6675dd5f06f04774b09
http://b/2834603
parent f5243556
Loading
Loading
Loading
Loading
+61 −33
Original line number Diff line number Diff line
@@ -149,41 +149,11 @@ public class PluginManager {
                    continue;
                }

                // check if the plugin has the required permissions
                String permissions[] = pkgInfo.requestedPermissions;
                if (permissions == null) {
                    continue;
                }
                boolean permissionOk = false;
                for (String permit : permissions) {
                    if (PLUGIN_PERMISSION.equals(permit)) {
                        permissionOk = true;
                        break;
                    }
                }
                if (!permissionOk) {
                    continue;
                }

                // check to ensure the plugin is properly signed
                Signature signatures[] = pkgInfo.signatures;
                if (signatures == null) {
                    continue;
                }
                if (SystemProperties.getBoolean("ro.secure", false)) {
                    boolean signatureMatch = false;
                    for (Signature signature : signatures) {
                        for (int i = 0; i < SIGNATURES.length; i++) {
                            if (SIGNATURES[i].equals(signature)) {
                                signatureMatch = true;
                                break;
                            }
                        }
                    }
                    if (!signatureMatch) {
                // check if the plugin has the required permissions and
                // signatures
                if (!containsPluginPermissionAndSignatures(pkgInfo)) {
                    continue;
                }
                }

                // determine the type of plugin from the manifest
                if (serviceInfo.metaData == null) {
@@ -225,6 +195,64 @@ public class PluginManager {
        return directories.toArray(new String[directories.size()]);
    }

    /* package */
    boolean containsPluginPermissionAndSignatures(String pluginAPKName) {
        PackageManager pm = mContext.getPackageManager();

        // retrieve information from the plugin's manifest
        try {
            PackageInfo pkgInfo = pm.getPackageInfo(pluginAPKName, PackageManager.GET_PERMISSIONS
                    | PackageManager.GET_SIGNATURES);
            if (pkgInfo != null) {
                return containsPluginPermissionAndSignatures(pkgInfo);
            }
        } catch (NameNotFoundException e) {
            Log.w(LOGTAG, "Can't find plugin: " + pluginAPKName);
        }
        return false;
    }

    private static boolean containsPluginPermissionAndSignatures(PackageInfo pkgInfo) {

        // check if the plugin has the required permissions
        String permissions[] = pkgInfo.requestedPermissions;
        if (permissions == null) {
            return false;
        }
        boolean permissionOk = false;
        for (String permit : permissions) {
            if (PLUGIN_PERMISSION.equals(permit)) {
                permissionOk = true;
                break;
            }
        }
        if (!permissionOk) {
            return false;
        }

        // check to ensure the plugin is properly signed
        Signature signatures[] = pkgInfo.signatures;
        if (signatures == null) {
            return false;
        }
        if (SystemProperties.getBoolean("ro.secure", false)) {
            boolean signatureMatch = false;
            for (Signature signature : signatures) {
                for (int i = 0; i < SIGNATURES.length; i++) {
                    if (SIGNATURES[i].equals(signature)) {
                        signatureMatch = true;
                        break;
                    }
                }
            }
            if (!signatureMatch) {
                return false;
            }
        }

        return true;
    }

    /* package */
    String getPluginsAPKName(String pluginLib) {

+97 −39
Original line number Diff line number Diff line
@@ -18,10 +18,14 @@ package android.webkit;

import android.annotation.Widget;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.IntentFilter;
import android.content.DialogInterface.OnCancelListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.Intent;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
@@ -40,6 +44,7 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.http.SslCertificate;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -92,6 +97,7 @@ import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -877,6 +883,7 @@ public class WebView extends AbsoluteLayout
         * such as the mZoomManager.
         */
        init();
        setupPackageListener(context);
        updateMultiTouchSupport(context);

        if (privateBrowsing) {
@@ -884,6 +891,96 @@ public class WebView extends AbsoluteLayout
        }
    }

    /*
     * The intent receiver that monitors for changes to relevant packages (e.g.,
     * sGoogleApps) and notifies WebViewCore of their existence.
     */
    private static BroadcastReceiver sPackageInstallationReceiver = null;

    /*
     * A set of Google packages we monitor for the
     * navigator.isApplicationInstalled() API. Add additional packages as
     * needed.
     */
    private static Set<String> sGoogleApps;
    static {
        sGoogleApps = new HashSet<String>();
        sGoogleApps.add("com.google.android.youtube");
    }

    private void setupPackageListener(Context context) {

        /*
         * we must synchronize the instance check and the creation of the
         * receiver to ensure that only ONE receiver exists for all WebView
         * instances.
         */
        synchronized (WebView.class) {

            // if the receiver already exists then we do not need to register it
            // again
            if (sPackageInstallationReceiver != null) {
                return;
            }

            IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            filter.addDataScheme("package");
            sPackageInstallationReceiver = new BroadcastReceiver() {

                @Override
                public void onReceive(Context context, Intent intent) {
                    final String action = intent.getAction();
                    final String packageName = intent.getData().getSchemeSpecificPart();
                    final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                    if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) {
                        // if it is replacing, refreshPlugins() when adding
                        return;
                    }

                    if (sGoogleApps.contains(packageName)) {
                        if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                            mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAME, packageName);
                        } else {
                            mWebViewCore.sendMessage(EventHub.REMOVE_PACKAGE_NAME, packageName);
                        }
                    }

                    PluginManager pm = PluginManager.getInstance(context);
                    if (pm.containsPluginPermissionAndSignatures(packageName)) {
                        pm.refreshPlugins(Intent.ACTION_PACKAGE_ADDED.equals(action));
                    }
                }
            };

            context.getApplicationContext().registerReceiver(sPackageInstallationReceiver, filter);
        }

        // check if any of the monitored apps are already installed
        AsyncTask<Void, Void, Set<String>> task = new AsyncTask<Void, Void, Set<String>>() {

            @Override
            protected Set<String> doInBackground(Void... unused) {
                Set<String> installedPackages = new HashSet<String>();
                PackageManager pm = mContext.getPackageManager();
                List<PackageInfo> packages = pm.getInstalledPackages(0);
                for (PackageInfo p : packages) {
                    if (sGoogleApps.contains(p.packageName)) {
                        installedPackages.add(p.packageName);
                    }
                }
                return installedPackages;
            }

            // Executes on the UI thread
            @Override
            protected void onPostExecute(Set<String> installedPackages) {
                mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, installedPackages);
            }
        };
        task.execute();
    }

    void updateMultiTouchSupport(Context context) {
        mZoomManager.updateMultiTouchSupport(context);
    }
@@ -3076,45 +3173,6 @@ public class WebView extends AbsoluteLayout
        return (mWebViewCore != null) ? mWebViewCore.getSettings() : null;
    }

    /**
     * Use this method to inform the webview about packages that are installed
     * in the system. This information will be used by the
     * navigator.isApplicationInstalled() API.
     * @param packageNames is a set of package names that are known to be
     * installed in the system.
     *
     * @hide not a public API
     */
    public void addPackageNames(Set<String> packageNames) {
        mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAMES, packageNames);
    }

    /**
     * Use this method to inform the webview about single packages that are
     * installed in the system. This information will be used by the
     * navigator.isApplicationInstalled() API.
     * @param packageName is the name of a package that is known to be
     * installed in the system.
     *
     * @hide not a public API
     */
    public void addPackageName(String packageName) {
        mWebViewCore.sendMessage(EventHub.ADD_PACKAGE_NAME, packageName);
    }

    /**
     * Use this method to inform the webview about packages that are uninstalled
     * in the system. This information will be used by the
     * navigator.isApplicationInstalled() API.
     * @param packageName is the name of a package that has been uninstalled in
     * the system.
     *
     * @hide not a public API
     */
    public void removePackageName(String packageName) {
        mWebViewCore.sendMessage(EventHub.REMOVE_PACKAGE_NAME, packageName);
    }

   /**
    * Return the list of currently loaded plugins.
    * @return The list of currently loaded plugins.