• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.webkit;
18 
19 import java.util.ArrayList;
20 import java.util.List;
21 
22 import android.annotation.SdkConstant;
23 import android.annotation.SdkConstant.SdkConstantType;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.PackageInfo;
27 import android.content.pm.PackageManager;
28 import android.content.pm.ResolveInfo;
29 import android.content.pm.ServiceInfo;
30 import android.content.pm.Signature;
31 import android.content.pm.PackageManager.NameNotFoundException;
32 import android.os.SystemProperties;
33 import android.util.Log;
34 
35 /**
36  * Class for managing the relationship between the {@link WebView} and installed
37  * plugins in the system. You can find this class through
38  * {@link PluginManager#getInstance}.
39  *
40  * @hide pending API solidification
41  */
42 public class PluginManager {
43 
44     /**
45      * Service Action: A plugin wishes to be loaded in the WebView must provide
46      * {@link android.content.IntentFilter IntentFilter} that accepts this
47      * action in their AndroidManifest.xml.
48      * <p>
49      * TODO: we may change this to a new PLUGIN_ACTION if this is going to be
50      * public.
51      */
52     @SdkConstant(SdkConstantType.SERVICE_ACTION)
53     public static final String PLUGIN_ACTION = "android.webkit.PLUGIN";
54 
55     /**
56      * A plugin wishes to be loaded in the WebView must provide this permission
57      * in their AndroidManifest.xml.
58      */
59     public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
60 
61     private static final String LOGTAG = "webkit";
62 
63     private static PluginManager mInstance = null;
64 
65     private final Context mContext;
66 
67     private ArrayList<PackageInfo> mPackageInfoCache;
68 
69     // Only plugin matches one of the signatures in the list can be loaded
70     // inside the WebView process
71     private static final String SIGNATURE_1 = "308204c5308203ada003020102020900d7cb412f75f4887e300d06092a864886f70d010105050030819d310b3009060355040613025553311330110603550408130a43616c69666f726e69613111300f0603550407130853616e204a6f736531233021060355040a131a41646f62652053797374656d7320496e636f72706f7261746564311c301a060355040b1313496e666f726d6174696f6e2053797374656d73312330210603550403131a41646f62652053797374656d7320496e636f72706f7261746564301e170d3039313030313030323331345a170d3337303231363030323331345a30819d310b3009060355040613025553311330110603550408130a43616c69666f726e69613111300f0603550407130853616e204a6f736531233021060355040a131a41646f62652053797374656d7320496e636f72706f7261746564311c301a060355040b1313496e666f726d6174696f6e2053797374656d73312330210603550403131a41646f62652053797374656d7320496e636f72706f726174656430820120300d06092a864886f70d01010105000382010d0030820108028201010099724f3e05bbd78843794f357776e04b340e13cb1c9ccb3044865180d7d8fec8166c5bbd876da8b80aa71eb6ba3d4d3455c9a8de162d24a25c4c1cd04c9523affd06a279fc8f0d018f242486bdbb2dbfbf6fcb21ed567879091928b876f7ccebc7bccef157366ebe74e33ae1d7e9373091adab8327482154afc0693a549522f8c796dd84d16e24bb221f5dbb809ca56dd2b6e799c5fa06b6d9c5c09ada54ea4c5db1523a9794ed22a3889e5e05b29f8ee0a8d61efe07ae28f65dece2ff7edc5b1416d7c7aad7f0d35e8f4a4b964dbf50ae9aa6d620157770d974131b3e7e3abd6d163d65758e2f0822db9c88598b9db6263d963d13942c91fc5efe34fc1e06e3020103a382010630820102301d0603551d0e041604145af418e419a639e1657db960996364a37ef20d403081d20603551d230481ca3081c780145af418e419a639e1657db960996364a37ef20d40a181a3a481a030819d310b3009060355040613025553311330110603550408130a43616c69666f726e69613111300f0603550407130853616e204a6f736531233021060355040a131a41646f62652053797374656d7320496e636f72706f7261746564311c301a060355040b1313496e666f726d6174696f6e2053797374656d73312330210603550403131a41646f62652053797374656d7320496e636f72706f7261746564820900d7cb412f75f4887e300c0603551d13040530030101ff300d06092a864886f70d0101050500038201010076c2a11fe303359689c2ebc7b2c398eff8c3f9ad545cdbac75df63bf7b5395b6988d1842d6aa1556d595b5692e08224d667a4c9c438f05e74906c53dd8016dde7004068866f01846365efd146e9bfaa48c9ecf657f87b97c757da11f225c4a24177bf2d7188e6cce2a70a1e8a841a14471eb51457398b8a0addd8b6c8c1538ca8f1e40b4d8b960009ea22c188d28924813d2c0b4a4d334b7cf05507e1fcf0a06fe946c7ffc435e173af6fc3e3400643710acc806f830a14788291d46f2feed9fb5c70423ca747ed1572d752894ac1f19f93989766308579393fabb43649aa8806a313b1ab9a50922a44c2467b9062037f2da0d484d9ffd8fe628eeea629ba637";
72 
73     private static final Signature[] SIGNATURES = new Signature[] {
74         new Signature(SIGNATURE_1)
75     };
76 
PluginManager(Context context)77     private PluginManager(Context context) {
78         mContext = context;
79         mPackageInfoCache = new ArrayList<PackageInfo>();
80     }
81 
getInstance(Context context)82     public static synchronized PluginManager getInstance(Context context) {
83         if (mInstance == null) {
84             if (context == null) {
85                 throw new IllegalStateException(
86                         "First call to PluginManager need a valid context.");
87             }
88             mInstance = new PluginManager(context);
89         }
90         return mInstance;
91     }
92 
93     /**
94      * Signal the WebCore thread to refresh its list of plugins. Use this if the
95      * directory contents of one of the plugin directories has been modified and
96      * needs its changes reflecting. May cause plugin load and/or unload.
97      *
98      * @param reloadOpenPages Set to true to reload all open pages.
99      */
refreshPlugins(boolean reloadOpenPages)100     public void refreshPlugins(boolean reloadOpenPages) {
101         BrowserFrame.sJavaBridge.obtainMessage(
102                 JWebCoreJavaBridge.REFRESH_PLUGINS, reloadOpenPages)
103                 .sendToTarget();
104     }
105 
getPluginDirectories()106     String[] getPluginDirectories() {
107 
108         ArrayList<String> directories = new ArrayList<String>();
109         PackageManager pm = mContext.getPackageManager();
110         List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
111                 PLUGIN_ACTION), PackageManager.GET_SERVICES);
112 
113         synchronized(mPackageInfoCache) {
114 
115             // clear the list of existing packageInfo objects
116             mPackageInfoCache.clear();
117 
118             for (ResolveInfo info : plugins) {
119                 ServiceInfo serviceInfo = info.serviceInfo;
120                 if (serviceInfo == null) {
121                     Log.w(LOGTAG, "Ignore bad plugin");
122                     continue;
123                 }
124                 PackageInfo pkgInfo;
125                 try {
126                     pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
127                                     PackageManager.GET_PERMISSIONS
128                                     | PackageManager.GET_SIGNATURES);
129                 } catch (NameNotFoundException e) {
130                     Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName);
131                     continue;
132                 }
133                 if (pkgInfo == null) {
134                     continue;
135                 }
136                 String directory = pkgInfo.applicationInfo.dataDir + "/lib";
137                 if (directories.contains(directory)) {
138                     continue;
139                 }
140                 String permissions[] = pkgInfo.requestedPermissions;
141                 if (permissions == null) {
142                     continue;
143                 }
144                 boolean permissionOk = false;
145                 for (String permit : permissions) {
146                     if (PLUGIN_PERMISSION.equals(permit)) {
147                         permissionOk = true;
148                         break;
149                     }
150                 }
151                 if (!permissionOk) {
152                     continue;
153                 }
154                 Signature signatures[] = pkgInfo.signatures;
155                 if (signatures == null) {
156                     continue;
157                 }
158                 if (SystemProperties.getBoolean("ro.secure", false)) {
159                     boolean signatureMatch = false;
160                     for (Signature signature : signatures) {
161                         for (int i = 0; i < SIGNATURES.length; i++) {
162                             if (SIGNATURES[i].equals(signature)) {
163                                 signatureMatch = true;
164                                 break;
165                             }
166                         }
167                     }
168                     if (!signatureMatch) {
169                         continue;
170                     }
171                 }
172                 mPackageInfoCache.add(pkgInfo);
173                 directories.add(directory);
174             }
175         }
176 
177         return directories.toArray(new String[directories.size()]);
178     }
179 
getPluginsAPKName(String pluginLib)180     String getPluginsAPKName(String pluginLib) {
181 
182         // basic error checking on input params
183         if (pluginLib == null || pluginLib.length() == 0) {
184             return null;
185         }
186 
187         // must be synchronized to ensure the consistency of the cache
188         synchronized(mPackageInfoCache) {
189             for (PackageInfo pkgInfo : mPackageInfoCache) {
190                 if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) {
191                     return pkgInfo.packageName;
192                 }
193             }
194         }
195 
196         // if no apk was found then return null
197         return null;
198     }
199 
getPluginSharedDataDirectory()200     String getPluginSharedDataDirectory() {
201         return mContext.getDir("plugins", 0).getPath();
202     }
203 }
204