OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/user_script_loader.h" | 5 #include "chrome/browser/extensions/user_script_loader.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
13 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
| 14 #include "base/memory/shared_memory.h" |
14 #include "base/version.h" | 15 #include "base/version.h" |
15 #include "chrome/browser/chrome_notification_types.h" | 16 #include "chrome/browser/chrome_notification_types.h" |
16 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
17 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
18 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
19 #include "content/public/browser/render_process_host.h" | 20 #include "content/public/browser/render_process_host.h" |
| 21 #include "extensions/browser/component_extension_resource_manager.h" |
20 #include "extensions/browser/content_verifier.h" | 22 #include "extensions/browser/content_verifier.h" |
| 23 #include "extensions/browser/extension_registry.h" |
| 24 #include "extensions/browser/extension_system.h" |
| 25 #include "extensions/browser/extensions_browser_client.h" |
21 #include "extensions/common/extension_messages.h" | 26 #include "extensions/common/extension_messages.h" |
22 #include "extensions/common/file_util.h" | 27 #include "extensions/common/file_util.h" |
| 28 #include "extensions/common/manifest_handlers/default_locale_handler.h" |
| 29 #include "extensions/common/message_bundle.h" |
| 30 #include "extensions/common/one_shot_event.h" |
| 31 #include "ui/base/resource/resource_bundle.h" |
23 | 32 |
24 using content::BrowserThread; | 33 using content::BrowserThread; |
| 34 using extensions::ExtensionsBrowserClient; |
25 | 35 |
26 namespace extensions { | 36 namespace extensions { |
27 | 37 |
28 namespace { | 38 namespace { |
29 | 39 |
30 using LoadScriptsCallback = | 40 typedef base::Callback< |
31 base::Callback<void(scoped_ptr<UserScriptList>, | 41 void(scoped_ptr<UserScriptList>, scoped_ptr<base::SharedMemory>)> |
32 scoped_ptr<base::SharedMemory>)>; | 42 LoadScriptsCallback; |
33 | 43 |
34 UserScriptLoader::SubstitutionMap* GetLocalizationMessages( | 44 void VerifyContent(scoped_refptr<ContentVerifier> verifier, |
35 const UserScriptLoader::HostsInfo& hosts_info, | 45 const ExtensionId& extension_id, |
36 const HostID& host_id) { | 46 const base::FilePath& extension_root, |
37 UserScriptLoader::HostsInfo::const_iterator iter = hosts_info.find(host_id); | 47 const base::FilePath& relative_path, |
38 if (iter == hosts_info.end()) | 48 const std::string& content) { |
39 return nullptr; | 49 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
40 return file_util::LoadMessageBundleSubstitutionMap( | 50 scoped_refptr<ContentVerifyJob> job( |
41 iter->second.first, host_id.id(), iter->second.second); | 51 verifier->CreateJobFor(extension_id, extension_root, relative_path)); |
| 52 if (job.get()) { |
| 53 job->Start(); |
| 54 job->BytesRead(content.size(), content.data()); |
| 55 job->DoneReading(); |
| 56 } |
42 } | 57 } |
43 | 58 |
44 void LoadUserScripts( | 59 bool LoadScriptContent(const ExtensionId& extension_id, |
45 UserScriptList* user_scripts, | 60 UserScript::File* script_file, |
46 const UserScriptLoader::HostsInfo& hosts_info, | 61 const SubstitutionMap* localization_messages, |
47 const std::set<int>& added_script_ids, | 62 scoped_refptr<ContentVerifier> verifier) { |
48 const scoped_refptr<ContentVerifier>& verifier, | 63 std::string content; |
49 UserScriptLoader::LoadUserScriptsContentFunction callback) { | 64 const base::FilePath& path = ExtensionResource::GetFilePath( |
| 65 script_file->extension_root(), |
| 66 script_file->relative_path(), |
| 67 ExtensionResource::SYMLINKS_MUST_RESOLVE_WITHIN_ROOT); |
| 68 if (path.empty()) { |
| 69 int resource_id; |
| 70 if (ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()-> |
| 71 IsComponentExtensionResource(script_file->extension_root(), |
| 72 script_file->relative_path(), |
| 73 &resource_id)) { |
| 74 const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 75 content = rb.GetRawDataResource(resource_id).as_string(); |
| 76 } else { |
| 77 LOG(WARNING) << "Failed to get file path to " |
| 78 << script_file->relative_path().value() << " from " |
| 79 << script_file->extension_root().value(); |
| 80 return false; |
| 81 } |
| 82 } else { |
| 83 if (!base::ReadFileToString(path, &content)) { |
| 84 LOG(WARNING) << "Failed to load user script file: " << path.value(); |
| 85 return false; |
| 86 } |
| 87 if (verifier.get()) { |
| 88 content::BrowserThread::PostTask(content::BrowserThread::IO, |
| 89 FROM_HERE, |
| 90 base::Bind(&VerifyContent, |
| 91 verifier, |
| 92 extension_id, |
| 93 script_file->extension_root(), |
| 94 script_file->relative_path(), |
| 95 content)); |
| 96 } |
| 97 } |
| 98 |
| 99 // Localize the content. |
| 100 if (localization_messages) { |
| 101 std::string error; |
| 102 MessageBundle::ReplaceMessagesWithExternalDictionary( |
| 103 *localization_messages, &content, &error); |
| 104 if (!error.empty()) { |
| 105 LOG(WARNING) << "Failed to replace messages in script: " << error; |
| 106 } |
| 107 } |
| 108 |
| 109 // Remove BOM from the content. |
| 110 std::string::size_type index = content.find(base::kUtf8ByteOrderMark); |
| 111 if (index == 0) { |
| 112 script_file->set_content(content.substr(strlen(base::kUtf8ByteOrderMark))); |
| 113 } else { |
| 114 script_file->set_content(content); |
| 115 } |
| 116 |
| 117 return true; |
| 118 } |
| 119 |
| 120 SubstitutionMap* GetLocalizationMessages(const ExtensionsInfo& extensions_info, |
| 121 const ExtensionId& extension_id) { |
| 122 ExtensionsInfo::const_iterator iter = extensions_info.find(extension_id); |
| 123 if (iter == extensions_info.end()) |
| 124 return NULL; |
| 125 return file_util::LoadMessageBundleSubstitutionMap( |
| 126 iter->second.first, extension_id, iter->second.second); |
| 127 } |
| 128 |
| 129 void LoadUserScripts(UserScriptList* user_scripts, |
| 130 const ExtensionsInfo& extensions_info, |
| 131 const std::set<int>& added_script_ids, |
| 132 ContentVerifier* verifier) { |
50 for (UserScriptList::iterator script = user_scripts->begin(); | 133 for (UserScriptList::iterator script = user_scripts->begin(); |
51 script != user_scripts->end(); | 134 script != user_scripts->end(); |
52 ++script) { | 135 ++script) { |
53 if (added_script_ids.count(script->id()) == 0) | 136 if (added_script_ids.count(script->id()) == 0) |
54 continue; | 137 continue; |
55 scoped_ptr<UserScriptLoader::SubstitutionMap> localization_messages( | 138 scoped_ptr<SubstitutionMap> localization_messages( |
56 GetLocalizationMessages(hosts_info, script->host_id())); | 139 GetLocalizationMessages(extensions_info, script->extension_id())); |
57 for (size_t k = 0; k < script->js_scripts().size(); ++k) { | 140 for (size_t k = 0; k < script->js_scripts().size(); ++k) { |
58 UserScript::File& script_file = script->js_scripts()[k]; | 141 UserScript::File& script_file = script->js_scripts()[k]; |
59 if (script_file.GetContent().empty()) | 142 if (script_file.GetContent().empty()) |
60 callback.Run(script->host_id(), &script_file, NULL, verifier); | 143 LoadScriptContent(script->extension_id(), &script_file, NULL, verifier); |
61 } | 144 } |
62 for (size_t k = 0; k < script->css_scripts().size(); ++k) { | 145 for (size_t k = 0; k < script->css_scripts().size(); ++k) { |
63 UserScript::File& script_file = script->css_scripts()[k]; | 146 UserScript::File& script_file = script->css_scripts()[k]; |
64 if (script_file.GetContent().empty()) | 147 if (script_file.GetContent().empty()) |
65 callback.Run(script->host_id(), &script_file, | 148 LoadScriptContent(script->extension_id(), |
66 localization_messages.get(), verifier); | 149 &script_file, |
| 150 localization_messages.get(), |
| 151 verifier); |
67 } | 152 } |
68 } | 153 } |
69 } | 154 } |
70 | 155 |
71 // Pickle user scripts and return pointer to the shared memory. | 156 // Pickle user scripts and return pointer to the shared memory. |
72 scoped_ptr<base::SharedMemory> Serialize(const UserScriptList& scripts) { | 157 scoped_ptr<base::SharedMemory> Serialize(const UserScriptList& scripts) { |
73 Pickle pickle; | 158 Pickle pickle; |
74 pickle.WriteSizeT(scripts.size()); | 159 pickle.WriteSizeT(scripts.size()); |
75 for (UserScriptList::const_iterator script = scripts.begin(); | 160 for (UserScriptList::const_iterator script = scripts.begin(); |
76 script != scripts.end(); | 161 script != scripts.end(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 | 193 |
109 base::SharedMemoryHandle readonly_handle; | 194 base::SharedMemoryHandle readonly_handle; |
110 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), | 195 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), |
111 &readonly_handle)) | 196 &readonly_handle)) |
112 return scoped_ptr<base::SharedMemory>(); | 197 return scoped_ptr<base::SharedMemory>(); |
113 | 198 |
114 return make_scoped_ptr(new base::SharedMemory(readonly_handle, | 199 return make_scoped_ptr(new base::SharedMemory(readonly_handle, |
115 /*read_only=*/true)); | 200 /*read_only=*/true)); |
116 } | 201 } |
117 | 202 |
118 void LoadScriptsOnFileThread( | 203 void LoadScriptsOnFileThread(scoped_ptr<UserScriptList> user_scripts, |
119 scoped_ptr<UserScriptList> user_scripts, | 204 const ExtensionsInfo& extensions_info, |
120 const UserScriptLoader::HostsInfo& hosts_info, | 205 const std::set<int>& added_script_ids, |
121 const std::set<int>& added_script_ids, | 206 scoped_refptr<ContentVerifier> verifier, |
122 const scoped_refptr<ContentVerifier>& verifier, | 207 LoadScriptsCallback callback) { |
123 UserScriptLoader::LoadUserScriptsContentFunction function, | |
124 LoadScriptsCallback callback) { | |
125 DCHECK(user_scripts.get()); | 208 DCHECK(user_scripts.get()); |
126 LoadUserScripts(user_scripts.get(), hosts_info, added_script_ids, | 209 LoadUserScripts( |
127 verifier, function); | 210 user_scripts.get(), extensions_info, added_script_ids, verifier.get()); |
128 scoped_ptr<base::SharedMemory> memory = Serialize(*user_scripts); | 211 scoped_ptr<base::SharedMemory> memory = Serialize(*user_scripts); |
129 BrowserThread::PostTask( | 212 BrowserThread::PostTask( |
130 BrowserThread::UI, | 213 BrowserThread::UI, |
131 FROM_HERE, | 214 FROM_HERE, |
132 base::Bind(callback, base::Passed(&user_scripts), base::Passed(&memory))); | 215 base::Bind(callback, base::Passed(&user_scripts), base::Passed(&memory))); |
133 } | 216 } |
134 | 217 |
135 // Helper function to parse greasesmonkey headers | 218 // Helper function to parse greasesmonkey headers |
136 bool GetDeclarationValue(const base::StringPiece& line, | 219 bool GetDeclarationValue(const base::StringPiece& line, |
137 const base::StringPiece& prefix, | 220 const base::StringPiece& prefix, |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 } | 323 } |
241 | 324 |
242 // If no patterns were specified, default to @include *. This is what | 325 // If no patterns were specified, default to @include *. This is what |
243 // Greasemonkey does. | 326 // Greasemonkey does. |
244 if (script->globs().empty() && script->url_patterns().is_empty()) | 327 if (script->globs().empty() && script->url_patterns().is_empty()) |
245 script->add_glob("*"); | 328 script->add_glob("*"); |
246 | 329 |
247 return true; | 330 return true; |
248 } | 331 } |
249 | 332 |
| 333 // static |
250 void UserScriptLoader::LoadScriptsForTest(UserScriptList* user_scripts) { | 334 void UserScriptLoader::LoadScriptsForTest(UserScriptList* user_scripts) { |
251 HostsInfo info; | 335 ExtensionsInfo info; |
252 std::set<int> added_script_ids; | 336 std::set<int> added_script_ids; |
253 for (UserScriptList::iterator it = user_scripts->begin(); | 337 for (UserScriptList::iterator it = user_scripts->begin(); |
254 it != user_scripts->end(); | 338 it != user_scripts->end(); |
255 ++it) { | 339 ++it) { |
256 added_script_ids.insert(it->id()); | 340 added_script_ids.insert(it->id()); |
257 } | 341 } |
258 LoadUserScripts(user_scripts, info, added_script_ids, | 342 LoadUserScripts( |
259 NULL /* no verifier for testing */, | 343 user_scripts, info, added_script_ids, NULL /* no verifier for testing */); |
260 GetLoadUserScriptsFunction()); | |
261 } | 344 } |
262 | 345 |
263 UserScriptLoader::UserScriptLoader( | 346 UserScriptLoader::UserScriptLoader(Profile* profile, |
264 Profile* profile, | 347 const ExtensionId& owner_extension_id, |
265 const HostID& host_id, | 348 bool listen_for_extension_system_loaded) |
266 const scoped_refptr<ContentVerifier>& content_verifier) | |
267 : user_scripts_(new UserScriptList()), | 349 : user_scripts_(new UserScriptList()), |
268 clear_scripts_(false), | 350 clear_scripts_(false), |
269 ready_(false), | 351 extension_system_ready_(false), |
270 pending_load_(false), | 352 pending_load_(false), |
271 profile_(profile), | 353 profile_(profile), |
272 host_id_(host_id), | 354 owner_extension_id_(owner_extension_id), |
273 content_verifier_(content_verifier), | 355 extension_registry_observer_(this), |
274 weak_factory_(this) { | 356 weak_factory_(this) { |
| 357 extension_registry_observer_.Add(ExtensionRegistry::Get(profile)); |
| 358 if (listen_for_extension_system_loaded) { |
| 359 ExtensionSystem::Get(profile_)->ready().Post( |
| 360 FROM_HERE, |
| 361 base::Bind(&UserScriptLoader::OnExtensionSystemReady, |
| 362 weak_factory_.GetWeakPtr())); |
| 363 } else { |
| 364 extension_system_ready_ = true; |
| 365 } |
275 registrar_.Add(this, | 366 registrar_.Add(this, |
276 content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 367 content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
277 content::NotificationService::AllBrowserContextsAndSources()); | 368 content::NotificationService::AllBrowserContextsAndSources()); |
278 } | 369 } |
279 | 370 |
280 UserScriptLoader::~UserScriptLoader() { | 371 UserScriptLoader::~UserScriptLoader() { |
281 } | 372 } |
282 | 373 |
283 void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts) { | 374 void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts) { |
284 for (std::set<UserScript>::const_iterator it = scripts.begin(); | 375 for (std::set<UserScript>::const_iterator it = scripts.begin(); |
(...skipping 25 matching lines...) Expand all Loading... |
310 void UserScriptLoader::Observe(int type, | 401 void UserScriptLoader::Observe(int type, |
311 const content::NotificationSource& source, | 402 const content::NotificationSource& source, |
312 const content::NotificationDetails& details) { | 403 const content::NotificationDetails& details) { |
313 DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED); | 404 DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED); |
314 content::RenderProcessHost* process = | 405 content::RenderProcessHost* process = |
315 content::Source<content::RenderProcessHost>(source).ptr(); | 406 content::Source<content::RenderProcessHost>(source).ptr(); |
316 Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); | 407 Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); |
317 if (!profile_->IsSameProfile(profile)) | 408 if (!profile_->IsSameProfile(profile)) |
318 return; | 409 return; |
319 if (scripts_ready()) { | 410 if (scripts_ready()) { |
320 SendUpdate(process, shared_memory_.get(), | 411 SendUpdate(process, |
321 std::set<HostID>()); // Include all hosts. | 412 shared_memory_.get(), |
| 413 std::set<ExtensionId>()); // Include all extensions. |
322 } | 414 } |
323 } | 415 } |
324 | 416 |
| 417 void UserScriptLoader::OnExtensionUnloaded( |
| 418 content::BrowserContext* browser_context, |
| 419 const Extension* extension, |
| 420 UnloadedExtensionInfo::Reason reason) { |
| 421 extensions_info_.erase(extension->id()); |
| 422 } |
| 423 |
| 424 void UserScriptLoader::OnExtensionSystemReady() { |
| 425 extension_system_ready_ = true; |
| 426 AttemptLoad(); |
| 427 } |
| 428 |
325 bool UserScriptLoader::ScriptsMayHaveChanged() const { | 429 bool UserScriptLoader::ScriptsMayHaveChanged() const { |
326 // Scripts may have changed if there are scripts added, scripts removed, or | 430 // Scripts may have changed if there are scripts added, scripts removed, or |
327 // if scripts were cleared and either: | 431 // if scripts were cleared and either: |
328 // (1) A load is in progress (which may result in a non-zero number of | 432 // (1) A load is in progress (which may result in a non-zero number of |
329 // scripts that need to be cleared), or | 433 // scripts that need to be cleared), or |
330 // (2) The current set of scripts is non-empty (so they need to be cleared). | 434 // (2) The current set of scripts is non-empty (so they need to be cleared). |
331 return (added_scripts_.size() || | 435 return (added_scripts_.size() || |
332 removed_scripts_.size() || | 436 removed_scripts_.size() || |
333 (clear_scripts_ && | 437 (clear_scripts_ && |
334 (is_loading() || user_scripts_->size()))); | 438 (is_loading() || user_scripts_->size()))); |
335 } | 439 } |
336 | 440 |
337 void UserScriptLoader::AttemptLoad() { | 441 void UserScriptLoader::AttemptLoad() { |
338 if (ready_ && ScriptsMayHaveChanged()) { | 442 if (extension_system_ready_ && ScriptsMayHaveChanged()) { |
339 if (is_loading()) | 443 if (is_loading()) |
340 pending_load_ = true; | 444 pending_load_ = true; |
341 else | 445 else |
342 StartLoad(); | 446 StartLoad(); |
343 } | 447 } |
344 } | 448 } |
345 | 449 |
346 void UserScriptLoader::StartLoad() { | 450 void UserScriptLoader::StartLoad() { |
347 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 451 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
348 DCHECK(!is_loading()); | 452 DCHECK(!is_loading()); |
(...skipping 15 matching lines...) Expand all Loading... |
364 user_scripts_->insert( | 468 user_scripts_->insert( |
365 user_scripts_->end(), added_scripts_.begin(), added_scripts_.end()); | 469 user_scripts_->end(), added_scripts_.begin(), added_scripts_.end()); |
366 | 470 |
367 std::set<int> added_script_ids; | 471 std::set<int> added_script_ids; |
368 for (std::set<UserScript>::const_iterator it = added_scripts_.begin(); | 472 for (std::set<UserScript>::const_iterator it = added_scripts_.begin(); |
369 it != added_scripts_.end(); | 473 it != added_scripts_.end(); |
370 ++it) { | 474 ++it) { |
371 added_script_ids.insert(it->id()); | 475 added_script_ids.insert(it->id()); |
372 } | 476 } |
373 | 477 |
374 // Expand |changed_hosts_| for OnScriptsLoaded, which will use it in | 478 // Expand |changed_extensions_| for OnScriptsLoaded, which will use it in |
375 // its IPC message. This must be done before we clear |added_scripts_| and | 479 // its IPC message. This must be done before we clear |added_scripts_| and |
376 // |removed_scripts_| below. | 480 // |removed_scripts_| below. |
377 std::set<UserScript> changed_scripts(added_scripts_); | 481 std::set<UserScript> changed_scripts(added_scripts_); |
378 changed_scripts.insert(removed_scripts_.begin(), removed_scripts_.end()); | 482 changed_scripts.insert(removed_scripts_.begin(), removed_scripts_.end()); |
379 for (const UserScript& script : changed_scripts) | 483 ExpandChangedExtensions(changed_scripts); |
380 changed_hosts_.insert(script.host_id()); | |
381 | 484 |
382 // |changed_hosts_| before passing it to LoadScriptsOnFileThread. | 485 // Update |extensions_info_| to contain info from every extension in |
383 UpdateHostsInfo(changed_hosts_); | 486 // |changed_extensions_| before passing it to LoadScriptsOnFileThread. |
| 487 UpdateExtensionsInfo(); |
384 | 488 |
385 BrowserThread::PostTask( | 489 BrowserThread::PostTask( |
386 BrowserThread::FILE, FROM_HERE, | 490 BrowserThread::FILE, |
387 base::Bind(&LoadScriptsOnFileThread, base::Passed(&user_scripts_), | 491 FROM_HERE, |
388 hosts_info_, added_script_ids, content_verifier_, | 492 base::Bind(&LoadScriptsOnFileThread, |
389 GetLoadUserScriptsFunction(), | 493 base::Passed(&user_scripts_), |
| 494 extensions_info_, |
| 495 added_script_ids, |
| 496 make_scoped_refptr( |
| 497 ExtensionSystem::Get(profile_)->content_verifier()), |
390 base::Bind(&UserScriptLoader::OnScriptsLoaded, | 498 base::Bind(&UserScriptLoader::OnScriptsLoaded, |
391 weak_factory_.GetWeakPtr()))); | 499 weak_factory_.GetWeakPtr()))); |
392 | 500 |
393 clear_scripts_ = false; | 501 clear_scripts_ = false; |
394 added_scripts_.clear(); | 502 added_scripts_.clear(); |
395 removed_scripts_.clear(); | 503 removed_scripts_.clear(); |
396 user_scripts_.reset(NULL); | 504 user_scripts_.reset(NULL); |
397 } | 505 } |
398 | 506 |
399 void UserScriptLoader::AddHostInfo(const HostID& host_id, | |
400 const PathAndDefaultLocale& location) { | |
401 if (hosts_info_.find(host_id) != hosts_info_.end()) | |
402 return; | |
403 hosts_info_[host_id] = location; | |
404 } | |
405 | |
406 void UserScriptLoader::RemoveHostInfo(const HostID& host_id) { | |
407 hosts_info_.erase(host_id); | |
408 } | |
409 | |
410 void UserScriptLoader::SetReady(bool ready) { | |
411 bool was_ready = ready_; | |
412 ready_ = ready; | |
413 if (ready_ && !was_ready) | |
414 AttemptLoad(); | |
415 } | |
416 | |
417 void UserScriptLoader::OnScriptsLoaded( | 507 void UserScriptLoader::OnScriptsLoaded( |
418 scoped_ptr<UserScriptList> user_scripts, | 508 scoped_ptr<UserScriptList> user_scripts, |
419 scoped_ptr<base::SharedMemory> shared_memory) { | 509 scoped_ptr<base::SharedMemory> shared_memory) { |
420 user_scripts_.reset(user_scripts.release()); | 510 user_scripts_.reset(user_scripts.release()); |
421 if (pending_load_) { | 511 if (pending_load_) { |
422 // While we were loading, there were further changes. Don't bother | 512 // While we were loading, there were further changes. Don't bother |
423 // notifying about these scripts and instead just immediately reload. | 513 // notifying about these scripts and instead just immediately reload. |
424 pending_load_ = false; | 514 pending_load_ = false; |
425 StartLoad(); | 515 StartLoad(); |
426 return; | 516 return; |
(...skipping 11 matching lines...) Expand all Loading... |
438 return; | 528 return; |
439 } | 529 } |
440 | 530 |
441 // We've got scripts ready to go. | 531 // We've got scripts ready to go. |
442 shared_memory_.reset(shared_memory.release()); | 532 shared_memory_.reset(shared_memory.release()); |
443 | 533 |
444 for (content::RenderProcessHost::iterator i( | 534 for (content::RenderProcessHost::iterator i( |
445 content::RenderProcessHost::AllHostsIterator()); | 535 content::RenderProcessHost::AllHostsIterator()); |
446 !i.IsAtEnd(); | 536 !i.IsAtEnd(); |
447 i.Advance()) { | 537 i.Advance()) { |
448 SendUpdate(i.GetCurrentValue(), shared_memory_.get(), changed_hosts_); | 538 SendUpdate(i.GetCurrentValue(), shared_memory_.get(), changed_extensions_); |
449 } | 539 } |
450 changed_hosts_.clear(); | 540 changed_extensions_.clear(); |
451 | 541 |
452 content::NotificationService::current()->Notify( | 542 content::NotificationService::current()->Notify( |
453 extensions::NOTIFICATION_USER_SCRIPTS_UPDATED, | 543 extensions::NOTIFICATION_USER_SCRIPTS_UPDATED, |
454 content::Source<Profile>(profile_), | 544 content::Source<Profile>(profile_), |
455 content::Details<base::SharedMemory>(shared_memory_.get())); | 545 content::Details<base::SharedMemory>(shared_memory_.get())); |
456 } | 546 } |
457 | 547 |
458 void UserScriptLoader::SendUpdate(content::RenderProcessHost* process, | 548 void UserScriptLoader::SendUpdate( |
459 base::SharedMemory* shared_memory, | 549 content::RenderProcessHost* process, |
460 const std::set<HostID>& changed_hosts) { | 550 base::SharedMemory* shared_memory, |
| 551 const std::set<ExtensionId>& changed_extensions) { |
461 // Don't allow injection of content scripts into <webview>. | 552 // Don't allow injection of content scripts into <webview>. |
462 if (process->IsIsolatedGuest()) | 553 if (process->IsIsolatedGuest()) |
463 return; | 554 return; |
464 | 555 |
465 Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); | 556 Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext()); |
466 // Make sure we only send user scripts to processes in our profile. | 557 // Make sure we only send user scripts to processes in our profile. |
467 if (!profile_->IsSameProfile(profile)) | 558 if (!profile_->IsSameProfile(profile)) |
468 return; | 559 return; |
469 | 560 |
470 // If the process is being started asynchronously, early return. We'll end up | 561 // If the process is being started asynchronously, early return. We'll end up |
471 // calling InitUserScripts when it's created which will call this again. | 562 // calling InitUserScripts when it's created which will call this again. |
472 base::ProcessHandle handle = process->GetHandle(); | 563 base::ProcessHandle handle = process->GetHandle(); |
473 if (!handle) | 564 if (!handle) |
474 return; | 565 return; |
475 | 566 |
476 base::SharedMemoryHandle handle_for_process; | 567 base::SharedMemoryHandle handle_for_process; |
477 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) | 568 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) |
478 return; // This can legitimately fail if the renderer asserts at startup. | 569 return; // This can legitimately fail if the renderer asserts at startup. |
479 | 570 |
480 // TODO(hanxi): update the IPC message to send a set of HostIDs to render. | |
481 // Also, remove this function when the refactor is done on render side. | |
482 std::set<std::string> changed_ids_set; | |
483 for (const HostID& id : changed_hosts) | |
484 changed_ids_set.insert(id.id()); | |
485 | |
486 if (base::SharedMemory::IsHandleValid(handle_for_process)) { | 571 if (base::SharedMemory::IsHandleValid(handle_for_process)) { |
487 process->Send(new ExtensionMsg_UpdateUserScripts( | 572 process->Send(new ExtensionMsg_UpdateUserScripts( |
488 handle_for_process, host_id().id(), changed_ids_set)); | 573 handle_for_process, owner_extension_id_, changed_extensions)); |
489 } | 574 } |
490 } | 575 } |
491 | 576 |
| 577 void UserScriptLoader::ExpandChangedExtensions( |
| 578 const std::set<UserScript>& scripts) { |
| 579 for (std::set<UserScript>::const_iterator it = scripts.begin(); |
| 580 it != scripts.end(); |
| 581 ++it) { |
| 582 changed_extensions_.insert(it->extension_id()); |
| 583 } |
| 584 } |
| 585 |
| 586 void UserScriptLoader::UpdateExtensionsInfo() { |
| 587 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
| 588 for (std::set<ExtensionId>::const_iterator it = changed_extensions_.begin(); |
| 589 it != changed_extensions_.end(); |
| 590 ++it) { |
| 591 if (extensions_info_.find(*it) == extensions_info_.end()) { |
| 592 const Extension* extension = |
| 593 registry->GetExtensionById(*it, ExtensionRegistry::EVERYTHING); |
| 594 // |changed_extensions_| may include extensions that have been removed, |
| 595 // which leads to the above lookup failing. In this case, just continue. |
| 596 if (!extension) |
| 597 continue; |
| 598 extensions_info_[*it] = ExtensionSet::ExtensionPathAndDefaultLocale( |
| 599 extension->path(), LocaleInfo::GetDefaultLocale(extension)); |
| 600 } |
| 601 } |
| 602 } |
| 603 |
492 } // namespace extensions | 604 } // namespace extensions |
OLD | NEW |