OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 | |
5 #include "chrome/browser/plugin_updater.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/message_loop.h" | |
11 #include "base/path_service.h" | |
12 #include "base/utf_string_conversions.h" | |
13 #include "base/values.h" | |
14 #include "base/version.h" | |
15 #include "chrome/browser/prefs/pref_service.h" | |
16 #include "chrome/browser/prefs/scoped_user_pref_update.h" | |
17 #include "chrome/browser/profiles/profile.h" | |
18 #include "chrome/common/chrome_content_client.h" | |
19 #include "chrome/common/chrome_notification_types.h" | |
20 #include "chrome/common/chrome_paths.h" | |
21 #include "chrome/common/pref_names.h" | |
22 #include "content/browser/browser_thread.h" | |
23 #include "content/common/notification_service.h" | |
24 #include "webkit/plugins/npapi/plugin_list.h" | |
25 #include "webkit/plugins/npapi/webplugininfo.h" | |
26 | |
27 // How long to wait to save the plugin enabled information, which might need to | |
28 // go to disk. | |
29 #define kPluginUpdateDelayMs (60 * 1000) | |
30 | |
31 PluginUpdater::PluginUpdater() | |
32 : notify_pending_(false) { | |
33 } | |
34 | |
35 DictionaryValue* PluginUpdater::CreatePluginFileSummary( | |
36 const webkit::npapi::WebPluginInfo& plugin) { | |
37 DictionaryValue* data = new DictionaryValue(); | |
38 data->SetString("path", plugin.path.value()); | |
39 data->SetString("name", plugin.name); | |
40 data->SetString("version", plugin.version); | |
41 data->SetBoolean("enabled", webkit::npapi::IsPluginEnabled(plugin)); | |
42 return data; | |
43 } | |
44 | |
45 // static | |
46 ListValue* PluginUpdater::GetPluginGroupsData() { | |
47 std::vector<webkit::npapi::PluginGroup> plugin_groups; | |
48 webkit::npapi::PluginList::Singleton()->GetPluginGroups(true, &plugin_groups); | |
49 | |
50 // Construct DictionaryValues to return to the UI | |
51 ListValue* plugin_groups_data = new ListValue(); | |
52 for (size_t i = 0; i < plugin_groups.size(); ++i) { | |
53 plugin_groups_data->Append(plugin_groups[i].GetDataForUI()); | |
54 } | |
55 return plugin_groups_data; | |
56 } | |
57 | |
58 void PluginUpdater::EnablePluginGroup(bool enable, const string16& group_name) { | |
59 webkit::npapi::PluginList::Singleton()->EnableGroup(enable, group_name); | |
60 NotifyPluginStatusChanged(); | |
61 } | |
62 | |
63 void PluginUpdater::EnablePlugin(bool enable, | |
64 const FilePath::StringType& path) { | |
65 FilePath file_path(path); | |
66 if (enable) | |
67 webkit::npapi::PluginList::Singleton()->EnablePlugin(file_path); | |
68 else | |
69 webkit::npapi::PluginList::Singleton()->DisablePlugin(file_path); | |
70 | |
71 NotifyPluginStatusChanged(); | |
72 } | |
73 | |
74 void PluginUpdater::Observe(int type, | |
75 const NotificationSource& source, | |
76 const NotificationDetails& details) { | |
77 DCHECK_EQ(chrome::NOTIFICATION_PREF_CHANGED, type); | |
78 const std::string* pref_name = Details<std::string>(details).ptr(); | |
79 if (!pref_name) { | |
80 NOTREACHED(); | |
81 return; | |
82 } | |
83 if (*pref_name == prefs::kPluginsDisabledPlugins || | |
84 *pref_name == prefs::kPluginsDisabledPluginsExceptions || | |
85 *pref_name == prefs::kPluginsEnabledPlugins) { | |
86 PrefService* pref_service = Source<PrefService>(source).ptr(); | |
87 const ListValue* disabled_list = | |
88 pref_service->GetList(prefs::kPluginsDisabledPlugins); | |
89 const ListValue* exceptions_list = | |
90 pref_service->GetList(prefs::kPluginsDisabledPluginsExceptions); | |
91 const ListValue* enabled_list = | |
92 pref_service->GetList(prefs::kPluginsEnabledPlugins); | |
93 UpdatePluginsStateFromPolicy(disabled_list, exceptions_list, enabled_list); | |
94 } | |
95 } | |
96 | |
97 void PluginUpdater::UpdatePluginsStateFromPolicy( | |
98 const ListValue* disabled_list, | |
99 const ListValue* exceptions_list, | |
100 const ListValue* enabled_list) { | |
101 std::set<string16> disabled_plugin_patterns; | |
102 std::set<string16> disabled_plugin_exception_patterns; | |
103 std::set<string16> enabled_plugin_patterns; | |
104 | |
105 ListValueToStringSet(disabled_list, &disabled_plugin_patterns); | |
106 ListValueToStringSet(exceptions_list, &disabled_plugin_exception_patterns); | |
107 ListValueToStringSet(enabled_list, &enabled_plugin_patterns); | |
108 | |
109 webkit::npapi::PluginGroup::SetPolicyEnforcedPluginPatterns( | |
110 disabled_plugin_patterns, | |
111 disabled_plugin_exception_patterns, | |
112 enabled_plugin_patterns); | |
113 | |
114 NotifyPluginStatusChanged(); | |
115 } | |
116 | |
117 void PluginUpdater::ListValueToStringSet(const ListValue* src, | |
118 std::set<string16>* dest) { | |
119 DCHECK(src); | |
120 DCHECK(dest); | |
121 ListValue::const_iterator end(src->end()); | |
122 for (ListValue::const_iterator current(src->begin()); | |
123 current != end; ++current) { | |
124 string16 plugin_name; | |
125 if ((*current)->GetAsString(&plugin_name)) { | |
126 dest->insert(plugin_name); | |
127 } | |
128 } | |
129 } | |
130 | |
131 void PluginUpdater::SetProfile(Profile* profile) { | |
132 bool update_internal_dir = false; | |
133 FilePath last_internal_dir = | |
134 profile->GetPrefs()->GetFilePath(prefs::kPluginsLastInternalDirectory); | |
135 FilePath cur_internal_dir; | |
136 if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &cur_internal_dir) && | |
137 cur_internal_dir != last_internal_dir) { | |
138 update_internal_dir = true; | |
139 profile->GetPrefs()->SetFilePath( | |
140 prefs::kPluginsLastInternalDirectory, cur_internal_dir); | |
141 } | |
142 | |
143 bool force_enable_internal_pdf = false; | |
144 bool internal_pdf_enabled = false; | |
145 string16 pdf_group_name = | |
146 ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName); | |
147 FilePath pdf_path; | |
148 PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path); | |
149 FilePath::StringType pdf_path_str = pdf_path.value(); | |
150 if (!profile->GetPrefs()->GetBoolean(prefs::kPluginsEnabledInternalPDF)) { | |
151 // We switched to the internal pdf plugin being on by default, and so we | |
152 // need to force it to be enabled. We only want to do it this once though, | |
153 // i.e. we don't want to enable it again if the user disables it afterwards. | |
154 profile->GetPrefs()->SetBoolean(prefs::kPluginsEnabledInternalPDF, true); | |
155 force_enable_internal_pdf = true; | |
156 } | |
157 | |
158 { // Scoped update of prefs::kPluginsPluginsList. | |
159 ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList); | |
160 ListValue* saved_plugins_list = update.Get(); | |
161 if (saved_plugins_list && !saved_plugins_list->empty()) { | |
162 for (ListValue::const_iterator it = saved_plugins_list->begin(); | |
163 it != saved_plugins_list->end(); | |
164 ++it) { | |
165 if (!(*it)->IsType(Value::TYPE_DICTIONARY)) { | |
166 LOG(WARNING) << "Invalid entry in " << prefs::kPluginsPluginsList; | |
167 continue; // Oops, don't know what to do with this item. | |
168 } | |
169 | |
170 DictionaryValue* plugin = static_cast<DictionaryValue*>(*it); | |
171 string16 group_name; | |
172 bool enabled; | |
173 if (!plugin->GetBoolean("enabled", &enabled)) | |
174 enabled = true; | |
175 | |
176 FilePath::StringType path; | |
177 // The plugin list constains all the plugin files in addition to the | |
178 // plugin groups. | |
179 if (plugin->GetString("path", &path)) { | |
180 // Files have a path attribute, groups don't. | |
181 FilePath plugin_path(path); | |
182 if (update_internal_dir && | |
183 FilePath::CompareIgnoreCase(plugin_path.DirName().value(), | |
184 last_internal_dir.value()) == 0) { | |
185 // If the internal plugin directory has changed and if the plugin | |
186 // looks internal, update its path in the prefs. | |
187 plugin_path = cur_internal_dir.Append(plugin_path.BaseName()); | |
188 path = plugin_path.value(); | |
189 plugin->SetString("path", path); | |
190 } | |
191 | |
192 if (FilePath::CompareIgnoreCase(path, pdf_path_str) == 0) { | |
193 if (!enabled && force_enable_internal_pdf) { | |
194 enabled = true; | |
195 plugin->SetBoolean("enabled", true); | |
196 } | |
197 | |
198 internal_pdf_enabled = enabled; | |
199 } | |
200 | |
201 if (!enabled) | |
202 webkit::npapi::PluginList::Singleton()->DisablePlugin(plugin_path); | |
203 } else if (!enabled && plugin->GetString("name", &group_name)) { | |
204 // Don't disable this group if it's for the pdf plugin and we just | |
205 // forced it on. | |
206 if (force_enable_internal_pdf && pdf_group_name == group_name) | |
207 continue; | |
208 | |
209 // Otherwise this is a list of groups. | |
210 EnablePluginGroup(false, group_name); | |
211 } | |
212 } | |
213 } else { | |
214 // If the saved plugin list is empty, then the call to UpdatePreferences() | |
215 // below failed in an earlier run, possibly because the user closed the | |
216 // browser too quickly. Try to force enable the internal PDF plugin again. | |
217 force_enable_internal_pdf = true; | |
218 } | |
219 } // Scoped update of prefs::kPluginsPluginsList. | |
220 | |
221 // Build the set of policy enabled/disabled plugin patterns once and cache it. | |
222 // Don't do this in the constructor, there's no profile available there. | |
223 const ListValue* disabled_plugins = | |
224 profile->GetPrefs()->GetList(prefs::kPluginsDisabledPlugins); | |
225 const ListValue* disabled_exception_plugins = | |
226 profile->GetPrefs()->GetList(prefs::kPluginsDisabledPluginsExceptions); | |
227 const ListValue* enabled_plugins = | |
228 profile->GetPrefs()->GetList(prefs::kPluginsEnabledPlugins); | |
229 UpdatePluginsStateFromPolicy(disabled_plugins, | |
230 disabled_exception_plugins, | |
231 enabled_plugins); | |
232 | |
233 registrar_.RemoveAll(); | |
234 registrar_.Init(profile->GetPrefs()); | |
235 registrar_.Add(prefs::kPluginsDisabledPlugins, this); | |
236 registrar_.Add(prefs::kPluginsDisabledPluginsExceptions, this); | |
237 registrar_.Add(prefs::kPluginsEnabledPlugins, this); | |
238 | |
239 if (force_enable_internal_pdf || internal_pdf_enabled) { | |
240 // See http://crbug.com/50105 for background. | |
241 EnablePluginGroup(false, ASCIIToUTF16( | |
242 webkit::npapi::PluginGroup::kAdobeReaderGroupName)); | |
243 } | |
244 | |
245 if (force_enable_internal_pdf) { | |
246 // We want to save this, but doing so requires loading the list of plugins, | |
247 // so do it after a minute as to not impact startup performance. Note that | |
248 // plugins are loaded after 30s by the metrics service. | |
249 UpdatePreferences(profile, kPluginUpdateDelayMs); | |
250 } | |
251 } | |
252 | |
253 void PluginUpdater::Shutdown() { | |
254 registrar_.RemoveAll(); | |
255 } | |
256 | |
257 void PluginUpdater::UpdatePreferences(Profile* profile, int delay_ms) { | |
258 BrowserThread::PostDelayedTask( | |
259 BrowserThread::FILE, | |
260 FROM_HERE, | |
261 NewRunnableFunction( | |
262 &PluginUpdater::GetPreferencesDataOnFileThread, profile), delay_ms); | |
263 } | |
264 | |
265 void PluginUpdater::GetPreferencesDataOnFileThread(void* profile) { | |
266 std::vector<webkit::npapi::WebPluginInfo> plugins; | |
267 webkit::npapi::PluginList::Singleton()->GetPlugins(&plugins); | |
268 | |
269 std::vector<webkit::npapi::PluginGroup> groups; | |
270 webkit::npapi::PluginList::Singleton()->GetPluginGroups(false, &groups); | |
271 | |
272 BrowserThread::PostTask( | |
273 BrowserThread::UI, | |
274 FROM_HERE, | |
275 NewRunnableFunction(&PluginUpdater::OnUpdatePreferences, | |
276 static_cast<Profile*>(profile), | |
277 plugins, groups)); | |
278 } | |
279 | |
280 void PluginUpdater::OnUpdatePreferences( | |
281 Profile* profile, | |
282 const std::vector<webkit::npapi::WebPluginInfo>& plugins, | |
283 const std::vector<webkit::npapi::PluginGroup>& groups) { | |
284 ListPrefUpdate update(profile->GetPrefs(), prefs::kPluginsPluginsList); | |
285 ListValue* plugins_list = update.Get(); | |
286 plugins_list->Clear(); | |
287 | |
288 FilePath internal_dir; | |
289 if (PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir)) | |
290 profile->GetPrefs()->SetFilePath(prefs::kPluginsLastInternalDirectory, | |
291 internal_dir); | |
292 | |
293 // Add the plugin files. | |
294 for (size_t i = 0; i < plugins.size(); ++i) { | |
295 DictionaryValue* summary = CreatePluginFileSummary(plugins[i]); | |
296 // If the plugin is managed by policy, store the user preferred state | |
297 // instead. | |
298 if (plugins[i].enabled & webkit::npapi::WebPluginInfo::MANAGED_MASK) { | |
299 bool user_enabled = | |
300 (plugins[i].enabled & webkit::npapi::WebPluginInfo::USER_MASK) == | |
301 webkit::npapi::WebPluginInfo::USER_ENABLED; | |
302 summary->SetBoolean("enabled", user_enabled); | |
303 } | |
304 plugins_list->Append(summary); | |
305 } | |
306 | |
307 // Add the groups as well. | |
308 for (size_t i = 0; i < groups.size(); ++i) { | |
309 DictionaryValue* summary = groups[i].GetSummary(); | |
310 // If the plugin is disabled only by policy don't store this state in the | |
311 // user pref store. | |
312 if (!groups[i].Enabled() && | |
313 webkit::npapi::PluginGroup::IsPluginNameDisabledByPolicy( | |
314 groups[i].GetGroupName())) | |
315 summary->SetBoolean("enabled", true); | |
316 plugins_list->Append(summary); | |
317 } | |
318 } | |
319 | |
320 void PluginUpdater::NotifyPluginStatusChanged() { | |
321 if (notify_pending_) | |
322 return; | |
323 notify_pending_ = true; | |
324 MessageLoop::current()->PostTask( | |
325 FROM_HERE, | |
326 NewRunnableFunction(&PluginUpdater::OnNotifyPluginStatusChanged)); | |
327 } | |
328 | |
329 void PluginUpdater::OnNotifyPluginStatusChanged() { | |
330 GetInstance()->notify_pending_ = false; | |
331 NotificationService::current()->Notify( | |
332 content::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, | |
333 Source<PluginUpdater>(GetInstance()), | |
334 NotificationService::NoDetails()); | |
335 } | |
336 | |
337 /*static*/ | |
338 PluginUpdater* PluginUpdater::GetInstance() { | |
339 return Singleton<PluginUpdater>::get(); | |
340 } | |
341 | |
342 /*static*/ | |
343 void PluginUpdater::RegisterPrefs(PrefService* prefs) { | |
344 FilePath internal_dir; | |
345 PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir); | |
346 prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory, | |
347 internal_dir, | |
348 PrefService::UNSYNCABLE_PREF); | |
349 prefs->RegisterListPref(prefs::kPluginsDisabledPlugins, | |
350 PrefService::UNSYNCABLE_PREF); | |
351 prefs->RegisterListPref(prefs::kPluginsDisabledPluginsExceptions, | |
352 PrefService::UNSYNCABLE_PREF); | |
353 prefs->RegisterListPref(prefs::kPluginsEnabledPlugins, | |
354 PrefService::UNSYNCABLE_PREF); | |
355 } | |
OLD | NEW |