PepperPluginManager.java revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.content.browser;
6
7import android.content.Context;
8import android.content.Intent;
9import android.content.pm.ApplicationInfo;
10import android.content.pm.PackageInfo;
11import android.content.pm.PackageManager;
12import android.content.pm.PackageManager.NameNotFoundException;
13import android.content.pm.ResolveInfo;
14import android.content.pm.ServiceInfo;
15import android.os.Bundle;
16import android.util.Log;
17
18import org.chromium.base.ContextTypes;
19
20import java.util.List;
21
22/**
23 * {@link PepperPluginManager} collects meta data about plugins from preloaded android apps
24 * that reply to PEPPERPLUGIN intent query.
25 */
26public class PepperPluginManager {
27
28    private static final String LOGTAG = "PepperPluginManager";
29
30    /**
31     * Service Action: A plugin wishes to be loaded in the ContentView must
32     * provide {@link android.content.IntentFilter IntentFilter} that accepts
33     * this action in its AndroidManifest.xml.
34     */
35    public static final String PEPPER_PLUGIN_ACTION = "org.chromium.intent.PEPPERPLUGIN";
36    public static final String PEPPER_PLUGIN_ROOT = "/system/lib/pepperplugin/";
37
38    // A plugin will specify the following fields in its AndroidManifest.xml.
39    private static final String FILENAME = "filename";
40    private static final String MIMETYPE = "mimetype";
41    private static final String NAME = "name";
42    private static final String DESCRIPTION = "description";
43    private static final String VERSION = "version";
44
45    private static String getPluginDescription(Bundle metaData) {
46        // Find the name of the plugin's shared library.
47        String filename = metaData.getString(FILENAME);
48        if (filename == null || filename.isEmpty()) {
49            return null;
50        }
51        // Find the mimetype of the plugin. Flash is handled in getFlashPath.
52        String mimetype = metaData.getString(MIMETYPE);
53        if (mimetype == null || mimetype.isEmpty()) {
54            return null;
55        }
56        // Assemble the plugin info, according to the format described in
57        // pepper_plugin_list.cc.
58        // (eg. path<#name><#description><#version>;mimetype)
59        StringBuffer plugin = new StringBuffer(PEPPER_PLUGIN_ROOT);
60        plugin.append(filename);
61
62        // Find the (optional) name/description/version of the plugin.
63        String name = metaData.getString(NAME);
64        String description = metaData.getString(DESCRIPTION);
65        String version = metaData.getString(VERSION);
66
67        if (name != null && !name.isEmpty()) {
68            plugin.append("#");
69            plugin.append(name);
70            if (description != null && !description.isEmpty()) {
71                plugin.append("#");
72                plugin.append(description);
73                if (version != null && !version.isEmpty()) {
74                    plugin.append("#");
75                    plugin.append(version);
76                }
77            }
78        }
79        plugin.append(';');
80        plugin.append(mimetype);
81
82        return plugin.toString();
83    }
84
85    /**
86     * Collects information about installed plugins and returns a plugin description
87     * string, which will be appended to for command line to load plugins.
88     *
89     * @param context Android context
90     * @return        Description string for plugins
91     */
92    public static String getPlugins(final Context context) {
93        if (DeviceUtils.isTv(context) &&
94                !ContextTypes.isRunningInWebapp(context)) {
95            // Chrome-for-tv enables plugins only on webapp mode.
96            return null;
97        }
98        StringBuffer ret = new StringBuffer();
99        PackageManager pm = context.getPackageManager();
100        List<ResolveInfo> plugins = pm.queryIntentServices(
101                new Intent(PEPPER_PLUGIN_ACTION),
102                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
103        for (ResolveInfo info : plugins) {
104            // Retrieve the plugin's service information.
105            ServiceInfo serviceInfo = info.serviceInfo;
106            if (serviceInfo == null || serviceInfo.metaData == null ||
107                    serviceInfo.packageName == null) {
108                Log.e(LOGTAG, "Can't get service information from " + info);
109                continue;
110            }
111
112            // Retrieve the plugin's package information.
113            PackageInfo pkgInfo;
114            try {
115                pkgInfo = pm.getPackageInfo(serviceInfo.packageName, 0);
116            } catch (NameNotFoundException e) {
117                Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
118                continue;
119            }
120            if (pkgInfo == null ||
121                    (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
122                continue;
123            }
124            Log.i(LOGTAG, "The given plugin package is preloaded: " + serviceInfo.packageName);
125
126            String plugin = getPluginDescription(serviceInfo.metaData);
127            if (plugin == null) {
128                continue;
129            }
130            if (ret.length() > 0) {
131                ret.append(',');
132            }
133            ret.append(plugin);
134        }
135        return ret.toString();
136    }
137}
138