PluginManager.java revision 01d0fbfa683012623f030ec75a63e1a9fabcb916
1658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba/*
2658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * Copyright (C) 2009 The Android Open Source Project
3658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba *
4658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * Licensed under the Apache License, Version 2.0 (the "License");
5658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * you may not use this file except in compliance with the License.
6658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * You may obtain a copy of the License at
7658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba *
8658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba *      http://www.apache.org/licenses/LICENSE-2.0
9658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba *
10658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * Unless required by applicable law or agreed to in writing, software
11658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * distributed under the License is distributed on an "AS IS" BASIS,
12658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * See the License for the specific language governing permissions and
14658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * limitations under the License.
15658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba */
16658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
17658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobapackage android.webkit;
18658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
19658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport java.util.ArrayList;
20658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport java.util.List;
21658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
22658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.annotation.SdkConstant;
23658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.annotation.SdkConstant.SdkConstantType;
24658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.Context;
25658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.Intent;
26658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.pm.PackageInfo;
27658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.pm.PackageManager;
28658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.pm.ResolveInfo;
29658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.pm.ServiceInfo;
30658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.pm.Signature;
31658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.content.pm.PackageManager.NameNotFoundException;
322919f49273ee5a6669dc4689c88759b3cc6a083fGrace Klobaimport android.os.SystemProperties;
33658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.util.Log;
34cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenbergerimport android.webkit.plugin.NativePlugin;
35cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenbergerimport android.webkit.plugin.WebkitPlugin;
36658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
37658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba/**
38658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * Class for managing the relationship between the {@link WebView} and installed
39658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * plugins in the system. You can find this class through
40658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * {@link PluginManager#getInstance}.
41658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba *
42658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * @hide pending API solidification
43658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba */
44658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobapublic class PluginManager {
45658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
46cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    private class PluginInfo {
47cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        public PackageInfo packageInfo;
48cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        public boolean isNative;
49cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        public Class<? extends WebkitPlugin> pluginClass;
50cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    }
51cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
52658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    /**
53658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * Service Action: A plugin wishes to be loaded in the WebView must provide
54658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * {@link android.content.IntentFilter IntentFilter} that accepts this
55658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * action in their AndroidManifest.xml.
56658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * <p>
57658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * TODO: we may change this to a new PLUGIN_ACTION if this is going to be
58658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * public.
59658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     */
60658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    @SdkConstant(SdkConstantType.SERVICE_ACTION)
61658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
62658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
63658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    /**
64658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * A plugin wishes to be loaded in the WebView must provide this permission
65658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * in their AndroidManifest.xml.
66658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     */
67658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
68658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
69658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    private static final String LOGTAG = "webkit";
70658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
71cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    private static final String PLUGIN_TYPE = "type";
72cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    private static final String TYPE_NATIVE = "native";
73cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
74658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    private static PluginManager mInstance = null;
75658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
76658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    private final Context mContext;
77658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
78cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    private ArrayList<PluginInfo> mPluginInfoCache;
79c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
8073477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba    // Only plugin matches one of the signatures in the list can be loaded
8173477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba    // inside the WebView process
822919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba    private static final String SIGNATURE_1 = "308204c5308203ada003020102020900d7cb412f75f4887e300d06092a864886f70d010105050030819d310b3009060355040613025553311330110603550408130a43616c69666f726e69613111300f0603550407130853616e204a6f736531233021060355040a131a41646f62652053797374656d7320496e636f72706f7261746564311c301a060355040b1313496e666f726d6174696f6e2053797374656d73312330210603550403131a41646f62652053797374656d7320496e636f72706f7261746564301e170d3039313030313030323331345a170d3337303231363030323331345a30819d310b3009060355040613025553311330110603550408130a43616c69666f726e69613111300f0603550407130853616e204a6f736531233021060355040a131a41646f62652053797374656d7320496e636f72706f7261746564311c301a060355040b1313496e666f726d6174696f6e2053797374656d73312330210603550403131a41646f62652053797374656d7320496e636f72706f726174656430820120300d06092a864886f70d01010105000382010d0030820108028201010099724f3e05bbd78843794f357776e04b340e13cb1c9ccb3044865180d7d8fec8166c5bbd876da8b80aa71eb6ba3d4d3455c9a8de162d24a25c4c1cd04c9523affd06a279fc8f0d018f242486bdbb2dbfbf6fcb21ed567879091928b876f7ccebc7bccef157366ebe74e33ae1d7e9373091adab8327482154afc0693a549522f8c796dd84d16e24bb221f5dbb809ca56dd2b6e799c5fa06b6d9c5c09ada54ea4c5db1523a9794ed22a3889e5e05b29f8ee0a8d61efe07ae28f65dece2ff7edc5b1416d7c7aad7f0d35e8f4a4b964dbf50ae9aa6d620157770d974131b3e7e3abd6d163d65758e2f0822db9c88598b9db6263d963d13942c91fc5efe34fc1e06e3020103a382010630820102301d0603551d0e041604145af418e419a639e1657db960996364a37ef20d403081d20603551d230481ca3081c780145af418e419a639e1657db960996364a37ef20d40a181a3a481a030819d310b3009060355040613025553311330110603550408130a43616c69666f726e69613111300f0603550407130853616e204a6f736531233021060355040a131a41646f62652053797374656d7320496e636f72706f7261746564311c301a060355040b1313496e666f726d6174696f6e2053797374656d73312330210603550403131a41646f62652053797374656d7320496e636f72706f7261746564820900d7cb412f75f4887e300c0603551d13040530030101ff300d06092a864886f70d0101050500038201010076c2a11fe303359689c2ebc7b2c398eff8c3f9ad545cdbac75df63bf7b5395b6988d1842d6aa1556d595b5692e08224d667a4c9c438f05e74906c53dd8016dde7004068866f01846365efd146e9bfaa48c9ecf657f87b97c757da11f225c4a24177bf2d7188e6cce2a70a1e8a841a14471eb51457398b8a0addd8b6c8c1538ca8f1e40b4d8b960009ea22c188d28924813d2c0b4a4d334b7cf05507e1fcf0a06fe946c7ffc435e173af6fc3e3400643710acc806f830a14788291d46f2feed9fb5c70423ca747ed1572d752894ac1f19f93989766308579393fabb43649aa8806a313b1ab9a50922a44c2467b9062037f2da0d484d9ffd8fe628eeea629ba637";
8373477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba
8473477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba    private static final Signature[] SIGNATURES = new Signature[] {
852919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba        new Signature(SIGNATURE_1)
8673477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba    };
8773477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba
88658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    private PluginManager(Context context) {
89658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        mContext = context;
90cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        mPluginInfoCache = new ArrayList<PluginInfo>();
91658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    }
92658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
93658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    public static synchronized PluginManager getInstance(Context context) {
94658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        if (mInstance == null) {
95658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba            if (context == null) {
96658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba                throw new IllegalStateException(
97658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba                        "First call to PluginManager need a valid context.");
98658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba            }
9901d0fbfa683012623f030ec75a63e1a9fabcb916Romain Guy            mInstance = new PluginManager(context.getApplicationContext());
100658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        }
101658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        return mInstance;
102658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    }
103658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
104658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    /**
105658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * Signal the WebCore thread to refresh its list of plugins. Use this if the
106658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * directory contents of one of the plugin directories has been modified and
107658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * needs its changes reflecting. May cause plugin load and/or unload.
108658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     *
109658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     * @param reloadOpenPages Set to true to reload all open pages.
110658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba     */
111658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    public void refreshPlugins(boolean reloadOpenPages) {
112658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        BrowserFrame.sJavaBridge.obtainMessage(
113658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba                JWebCoreJavaBridge.REFRESH_PLUGINS, reloadOpenPages)
114658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba                .sendToTarget();
115658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    }
116658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba
11737eb3c35152fadc2541ebe6af3e39b246ca87fb7Derek Sollenberger    String[] getPluginDirectories() {
118c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
119658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        ArrayList<String> directories = new ArrayList<String>();
120658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        PackageManager pm = mContext.getPackageManager();
121658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
122cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                PLUGIN_ACTION), PackageManager.GET_SERVICES
123cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                | PackageManager.GET_META_DATA);
124c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
125cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        synchronized(mPluginInfoCache) {
126c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
127c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger            // clear the list of existing packageInfo objects
128cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger            mPluginInfoCache.clear();
129c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
130c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger            for (ResolveInfo info : plugins) {
131cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
132cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                // retrieve the plugin's service information
133c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                ServiceInfo serviceInfo = info.serviceInfo;
134c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                if (serviceInfo == null) {
135c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    Log.w(LOGTAG, "Ignore bad plugin");
136c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    continue;
137c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
138cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
139cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                // retrieve information from the plugin's manifest
140c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                PackageInfo pkgInfo;
141c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                try {
142c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
143c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                                    PackageManager.GET_PERMISSIONS
144c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                                    | PackageManager.GET_SIGNATURES);
145c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                } catch (NameNotFoundException e) {
146cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    Log.w(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
147c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    continue;
148c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
149c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                if (pkgInfo == null) {
150c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    continue;
151c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
152cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
153cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                // check if their is a conflict in the lib directory names
154c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                String directory = pkgInfo.applicationInfo.dataDir + "/lib";
155c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                if (directories.contains(directory)) {
156c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    continue;
157c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
158cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
159cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                // check if the plugin has the required permissions
160c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                String permissions[] = pkgInfo.requestedPermissions;
161c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                if (permissions == null) {
162c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    continue;
163c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
164c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                boolean permissionOk = false;
165c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                for (String permit : permissions) {
166c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    if (PLUGIN_PERMISSION.equals(permit)) {
167c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                        permissionOk = true;
168c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                        break;
169c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    }
170c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
171c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                if (!permissionOk) {
172c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    continue;
173c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
174cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
175cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                // check to ensure the plugin is properly signed
176c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                Signature signatures[] = pkgInfo.signatures;
177c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                if (signatures == null) {
178c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    continue;
179c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
1802919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                if (SystemProperties.getBoolean("ro.secure", false)) {
1812919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                    boolean signatureMatch = false;
1822919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                    for (Signature signature : signatures) {
1832919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                        for (int i = 0; i < SIGNATURES.length; i++) {
1842919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                            if (SIGNATURES[i].equals(signature)) {
1852919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                                signatureMatch = true;
1862919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                                break;
1872919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                            }
18873477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba                        }
18973477e7336cd1bdd67984a0f6374c79108a8f098Grace Kloba                    }
1902919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                    if (!signatureMatch) {
1912919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                        continue;
1922919f49273ee5a6669dc4689c88759b3cc6a083fGrace Kloba                    }
193c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
194cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
195cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                PluginInfo pluginInfo = new PluginInfo();
196cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                pluginInfo.packageInfo = pkgInfo;
197cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
198cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                // determine the type of plugin from the manifest
199cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                if (serviceInfo.metaData == null) {
200cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no type defined");
201cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    continue;
202cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                }
203cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
204cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                String pluginType = serviceInfo.metaData.getString(PLUGIN_TYPE);
205cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                if (TYPE_NATIVE.equals(pluginType)) {
206cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    pluginInfo.isNative = true;
207cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                } else {
208cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    Log.e(LOGTAG, "Unrecognized plugin type: " + pluginType);
209cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    continue;
210cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                }
211cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
212cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                try {
213cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    Class<?> cls = getPluginClass(serviceInfo.packageName, serviceInfo.name);
214cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
215cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    boolean classFound = false;
216cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    for(Class<?> implemented : cls.getInterfaces()) {
217cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        if (pluginInfo.isNative && implemented.equals(NativePlugin.class)) {
218cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                            pluginInfo.pluginClass = cls.asSubclass(WebkitPlugin.class);
219cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                            classFound = true;
220cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                            break;
221cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        }
222cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    }
223cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
224cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    if (!classFound) {
225cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        Log.e(LOGTAG, "The plugin's class'" + serviceInfo.name + "' does not extend the appropriate interface.");
226cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        continue;
227cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    }
228cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
229cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                } catch (NameNotFoundException e) {
230cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
231cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    continue;
232cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                } catch (ClassNotFoundException e) {
233cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    Log.e(LOGTAG, "Can't find plugin's class: " + serviceInfo.name);
234cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    continue;
235cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                }
236cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
237cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                // if all checks have passed then make the plugin available
238cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                mPluginInfoCache.add(pluginInfo);
239c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                directories.add(directory);
240658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba            }
241658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        }
24237eb3c35152fadc2541ebe6af3e39b246ca87fb7Derek Sollenberger
243658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba        return directories.toArray(new String[directories.size()]);
244658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba    }
245fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba
246cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    /* package */
247c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger    String getPluginsAPKName(String pluginLib) {
248c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
249c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger        // basic error checking on input params
250c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger        if (pluginLib == null || pluginLib.length() == 0) {
251c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger            return null;
252c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger        }
253c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
254c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger        // must be synchronized to ensure the consistency of the cache
255cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        synchronized(mPluginInfoCache) {
256cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger            for (PluginInfo pluginInfo : mPluginInfoCache) {
257cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                PackageInfo pkgInfo = pluginInfo.packageInfo;
258c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) {
259c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                    return pkgInfo.packageName;
260c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger                }
261c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger            }
262c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger        }
263c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
264c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger        // if no apk was found then return null
265c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger        return null;
266c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger    }
267c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger
268fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba    String getPluginSharedDataDirectory() {
269fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba        return mContext.getDir("plugins", 0).getPath();
270fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba    }
271cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
272cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    /* package */
273cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    WebkitPlugin getPluginInstance(String pkgName, int npp) {
274cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
275cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        // must be synchronized to ensure the consistency of the cache
276cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        synchronized(mPluginInfoCache) {
277cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
278cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger            // lookup plugin based on pkgName and instantiate if possible.
279cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger            for (PluginInfo pluginInfo : mPluginInfoCache) {
280cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
281cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                if (pluginInfo.packageInfo.packageName.equals(pkgName)) {
282cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
283cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    try {
284cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        WebkitPlugin webkitPlugin = pluginInfo.pluginClass.newInstance();
285cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
286cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        if (pluginInfo.isNative) {
287cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                            NativePlugin nativePlugin = (NativePlugin) webkitPlugin;
288cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                            nativePlugin.initializePlugin(npp, mContext);
289cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        }
290cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
291cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        return webkitPlugin;
292cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    } catch (Exception e) {
293cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        // Any number of things could have happened. Log the exception and
294cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        // return null. Careful not to use Log.e(LOGTAG, "String", e)
295cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        // because that reports the exception to the checkin service.
296cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                        Log.e(LOGTAG, Log.getStackTraceString(e));
297cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    }
298cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                    break;
299cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                }
300cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger            }
301cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        }
302cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        return null;
303cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    }
304cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger
305cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    /* package */
306cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    Class<?> getPluginClass(String packageName, String className)
307cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger            throws NameNotFoundException, ClassNotFoundException {
308cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        Context pluginContext = mContext.createPackageContext(packageName,
309cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                Context.CONTEXT_INCLUDE_CODE |
310cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger                Context.CONTEXT_IGNORE_SECURITY);
311cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        ClassLoader pluginCL = pluginContext.getClassLoader();
312cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger        return pluginCL.loadClass(className);
313cb37e71509da43e0d8d809591b09e8f5a582b5cdDerek Sollenberger    }
314658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba}
315