PluginManager.java revision c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bf
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; 32658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobaimport android.util.Log; 33658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 34658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba/** 35658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * Class for managing the relationship between the {@link WebView} and installed 36658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * plugins in the system. You can find this class through 37658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * {@link PluginManager#getInstance}. 38658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * 39658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * @hide pending API solidification 40658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba */ 41658ab7d787f64987d7c45aae08e5a12a073afe78Grace Klobapublic class PluginManager { 42658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 43658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba /** 44658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * Service Action: A plugin wishes to be loaded in the WebView must provide 45658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * {@link android.content.IntentFilter IntentFilter} that accepts this 46658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * action in their AndroidManifest.xml. 47658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * <p> 48658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * TODO: we may change this to a new PLUGIN_ACTION if this is going to be 49658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * public. 50658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba */ 51658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba @SdkConstant(SdkConstantType.SERVICE_ACTION) 52658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba public static final String PLUGIN_ACTION = "android.webkit.PLUGIN"; 53658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 54658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba /** 55658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * A plugin wishes to be loaded in the WebView must provide this permission 56658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * in their AndroidManifest.xml. 57658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba */ 58658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN"; 59658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 60658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba private static final String LOGTAG = "webkit"; 61658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 62658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba private static PluginManager mInstance = null; 63658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 64658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba private final Context mContext; 65658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 66c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger private ArrayList<PackageInfo> mPackageInfoCache; 67c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 68658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba private PluginManager(Context context) { 69658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba mContext = context; 70c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger mPackageInfoCache = new ArrayList<PackageInfo>(); 71658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 72658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 73658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba public static synchronized PluginManager getInstance(Context context) { 74658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba if (mInstance == null) { 75658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba if (context == null) { 76658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba throw new IllegalStateException( 77658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba "First call to PluginManager need a valid context."); 78658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 79658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba mInstance = new PluginManager(context); 80658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 81658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba return mInstance; 82658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 83658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 84658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba /** 85658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * Signal the WebCore thread to refresh its list of plugins. Use this if the 86658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * directory contents of one of the plugin directories has been modified and 87658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * needs its changes reflecting. May cause plugin load and/or unload. 88658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * 89658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba * @param reloadOpenPages Set to true to reload all open pages. 90658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba */ 91658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba public void refreshPlugins(boolean reloadOpenPages) { 92658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba BrowserFrame.sJavaBridge.obtainMessage( 93658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba JWebCoreJavaBridge.REFRESH_PLUGINS, reloadOpenPages) 94658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba .sendToTarget(); 95658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 96658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba 9737eb3c35152fadc2541ebe6af3e39b246ca87fb7Derek Sollenberger String[] getPluginDirectories() { 98c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 99658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba ArrayList<String> directories = new ArrayList<String>(); 100658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba PackageManager pm = mContext.getPackageManager(); 101658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba List<ResolveInfo> plugins = pm.queryIntentServices(new Intent( 102658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba PLUGIN_ACTION), PackageManager.GET_SERVICES); 103c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 104c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger synchronized(mPackageInfoCache) { 105c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 106c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger // clear the list of existing packageInfo objects 107c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger mPackageInfoCache.clear(); 108c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 109c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger for (ResolveInfo info : plugins) { 110c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger ServiceInfo serviceInfo = info.serviceInfo; 111c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (serviceInfo == null) { 112c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger Log.w(LOGTAG, "Ignore bad plugin"); 113c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 114c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 115c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger PackageInfo pkgInfo; 116c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger try { 117c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger pkgInfo = pm.getPackageInfo(serviceInfo.packageName, 118c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger PackageManager.GET_PERMISSIONS 119c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger | PackageManager.GET_SIGNATURES); 120c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } catch (NameNotFoundException e) { 121c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName); 122c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 123c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 124c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (pkgInfo == null) { 125c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 126c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 127c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger String directory = pkgInfo.applicationInfo.dataDir + "/lib"; 128c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (directories.contains(directory)) { 129c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 130c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 131c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger String permissions[] = pkgInfo.requestedPermissions; 132c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (permissions == null) { 133c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 134c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 135c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger boolean permissionOk = false; 136c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger for (String permit : permissions) { 137c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (PLUGIN_PERMISSION.equals(permit)) { 138c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger permissionOk = true; 139c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger break; 140c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 141c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 142c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (!permissionOk) { 143c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 144c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 145c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger Signature signatures[] = pkgInfo.signatures; 146c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (signatures == null) { 147c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 148c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 149c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger boolean signatureMatch = false; 150c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger for (Signature signature : signatures) { 151c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger // TODO: check signature against Google provided one 152c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger signatureMatch = true; 153658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba break; 154658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 155c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (!signatureMatch) { 156c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger continue; 157c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 158c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger mPackageInfoCache.add(pkgInfo); 159c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger directories.add(directory); 160658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 161658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 16237eb3c35152fadc2541ebe6af3e39b246ca87fb7Derek Sollenberger 163658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba return directories.toArray(new String[directories.size()]); 164658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba } 165fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba 166c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger String getPluginsAPKName(String pluginLib) { 167c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 168c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger // basic error checking on input params 169c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (pluginLib == null || pluginLib.length() == 0) { 170c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger return null; 171c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 172c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 173c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger // must be synchronized to ensure the consistency of the cache 174c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger synchronized(mPackageInfoCache) { 175c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger for (PackageInfo pkgInfo : mPackageInfoCache) { 176c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) { 177c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger return pkgInfo.packageName; 178c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 179c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 180c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 181c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 182c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger // if no apk was found then return null 183c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger return null; 184c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger } 185c0b8a96d28c55cb51e4f9e1f85c8d3ecf1ff13bfDerek Sollenberger 186fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba String getPluginSharedDataDirectory() { 187fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba return mContext.getDir("plugins", 0).getPath(); 188fd055b2d7cebd6693925a30adad6c66a697af407Grace Kloba } 189658ab7d787f64987d7c45aae08e5a12a073afe78Grace Kloba} 190