Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_master.h" | 5 #include "chrome/browser/extensions/user_script_master.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | |
| 10 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
| 12 #include "base/version.h" | 13 #include "base/version.h" |
| 13 #include "chrome/browser/chrome_notification_types.h" | 14 #include "chrome/browser/chrome_notification_types.h" |
| 14 #include "chrome/browser/extensions/extension_service.h" | 15 #include "chrome/browser/extensions/extension_service.h" |
| 15 #include "chrome/browser/extensions/extension_util.h" | 16 #include "chrome/browser/extensions/extension_util.h" |
| 16 #include "chrome/browser/extensions/image_loader.h" | 17 #include "chrome/browser/extensions/image_loader.h" |
| 17 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 18 #include "chrome/common/extensions/api/i18n/default_locale_handler.h" | 19 #include "chrome/common/extensions/api/i18n/default_locale_handler.h" |
| 19 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" | 20 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 159 this->extensions_info_ = extensions_info; | 160 this->extensions_info_ = extensions_info; |
| 160 BrowserThread::PostTask( | 161 BrowserThread::PostTask( |
| 161 BrowserThread::FILE, FROM_HERE, | 162 BrowserThread::FILE, FROM_HERE, |
| 162 base::Bind( | 163 base::Bind( |
| 163 &UserScriptMaster::ScriptReloader::RunLoad, this, user_scripts)); | 164 &UserScriptMaster::ScriptReloader::RunLoad, this, user_scripts)); |
| 164 } | 165 } |
| 165 | 166 |
| 166 UserScriptMaster::ScriptReloader::~ScriptReloader() {} | 167 UserScriptMaster::ScriptReloader::~ScriptReloader() {} |
| 167 | 168 |
| 168 void UserScriptMaster::ScriptReloader::NotifyMaster( | 169 void UserScriptMaster::ScriptReloader::NotifyMaster( |
| 169 base::SharedMemory* memory) { | 170 scoped_ptr<base::SharedMemory> memory) { |
| 170 // The master went away, so these new scripts aren't useful anymore. | 171 // The master could go away |
| 171 if (!master_) | 172 if (master_) |
| 172 delete memory; | 173 master_->NewScriptsAvailable(memory.Pass()); |
| 173 else | |
| 174 master_->NewScriptsAvailable(memory); | |
| 175 | 174 |
| 176 // Drop our self-reference. | 175 // Drop our self-reference. |
| 177 // Balances StartLoad(). | 176 // Balances StartLoad(). |
| 178 Release(); | 177 Release(); |
| 179 } | 178 } |
| 180 | 179 |
| 181 static void VerifyContent(ContentVerifier* verifier, | 180 static void VerifyContent(ContentVerifier* verifier, |
| 182 const std::string& extension_id, | 181 const std::string& extension_id, |
| 183 const base::FilePath& extension_root, | 182 const base::FilePath& extension_root, |
| 184 const base::FilePath& relative_path, | 183 const base::FilePath& relative_path, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 277 return NULL; | 276 return NULL; |
| 278 } | 277 } |
| 279 | 278 |
| 280 return file_util::LoadMessageBundleSubstitutionMap( | 279 return file_util::LoadMessageBundleSubstitutionMap( |
| 281 extensions_info_[extension_id].first, | 280 extensions_info_[extension_id].first, |
| 282 extension_id, | 281 extension_id, |
| 283 extensions_info_[extension_id].second); | 282 extensions_info_[extension_id].second); |
| 284 } | 283 } |
| 285 | 284 |
| 286 // Pickle user scripts and return pointer to the shared memory. | 285 // Pickle user scripts and return pointer to the shared memory. |
| 287 static base::SharedMemory* Serialize(const UserScriptList& scripts) { | 286 static scoped_ptr<base::SharedMemory> Serialize(const UserScriptList& scripts) { |
| 288 Pickle pickle; | 287 Pickle pickle; |
| 289 pickle.WriteUInt64(scripts.size()); | 288 pickle.WriteUInt64(scripts.size()); |
| 290 for (size_t i = 0; i < scripts.size(); i++) { | 289 for (size_t i = 0; i < scripts.size(); i++) { |
| 291 const UserScript& script = scripts[i]; | 290 const UserScript& script = scripts[i]; |
| 292 // TODO(aa): This can be replaced by sending content script metadata to | 291 // TODO(aa): This can be replaced by sending content script metadata to |
| 293 // renderers along with other extension data in ExtensionMsg_Loaded. | 292 // renderers along with other extension data in ExtensionMsg_Loaded. |
| 294 // See crbug.com/70516. | 293 // See crbug.com/70516. |
| 295 script.Pickle(&pickle); | 294 script.Pickle(&pickle); |
| 296 // Write scripts as 'data' so that we can read it out in the slave without | 295 // Write scripts as 'data' so that we can read it out in the slave without |
| 297 // allocating a new string. | 296 // allocating a new string. |
| 298 for (size_t j = 0; j < script.js_scripts().size(); j++) { | 297 for (size_t j = 0; j < script.js_scripts().size(); j++) { |
| 299 base::StringPiece contents = script.js_scripts()[j].GetContent(); | 298 base::StringPiece contents = script.js_scripts()[j].GetContent(); |
| 300 pickle.WriteData(contents.data(), contents.length()); | 299 pickle.WriteData(contents.data(), contents.length()); |
| 301 } | 300 } |
| 302 for (size_t j = 0; j < script.css_scripts().size(); j++) { | 301 for (size_t j = 0; j < script.css_scripts().size(); j++) { |
| 303 base::StringPiece contents = script.css_scripts()[j].GetContent(); | 302 base::StringPiece contents = script.css_scripts()[j].GetContent(); |
| 304 pickle.WriteData(contents.data(), contents.length()); | 303 pickle.WriteData(contents.data(), contents.length()); |
| 305 } | 304 } |
| 306 } | 305 } |
| 307 | 306 |
| 308 // Create the shared memory object. | 307 // Create the shared memory object. |
| 309 base::SharedMemory shared_memory; | 308 base::SharedMemory shared_memory; |
| 310 | 309 |
| 311 base::SharedMemoryCreateOptions options; | 310 base::SharedMemoryCreateOptions options; |
| 312 options.size = pickle.size(); | 311 options.size = pickle.size(); |
| 313 options.share_read_only = true; | 312 options.share_read_only = true; |
| 314 if (!shared_memory.Create(options)) | 313 if (!shared_memory.Create(options)) |
| 315 return NULL; | 314 return scoped_ptr<base::SharedMemory>(); |
| 316 | 315 |
| 317 if (!shared_memory.Map(pickle.size())) | 316 if (!shared_memory.Map(pickle.size())) |
| 318 return NULL; | 317 return scoped_ptr<base::SharedMemory>(); |
| 319 | 318 |
| 320 // Copy the pickle to shared memory. | 319 // Copy the pickle to shared memory. |
| 321 memcpy(shared_memory.memory(), pickle.data(), pickle.size()); | 320 memcpy(shared_memory.memory(), pickle.data(), pickle.size()); |
| 322 | 321 |
| 323 base::SharedMemoryHandle readonly_handle; | 322 base::SharedMemoryHandle readonly_handle; |
| 324 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), | 323 if (!shared_memory.ShareReadOnlyToProcess(base::GetCurrentProcessHandle(), |
| 325 &readonly_handle)) | 324 &readonly_handle)) |
| 326 return NULL; | 325 return scoped_ptr<base::SharedMemory>(); |
| 327 | 326 |
| 328 return new base::SharedMemory(readonly_handle, /*read_only=*/true); | 327 return make_scoped_ptr(new base::SharedMemory(readonly_handle, |
| 328 /*read_only=*/true)); | |
| 329 } | 329 } |
| 330 | 330 |
| 331 // This method will be called on the file thread. | 331 // This method will be called on the file thread. |
| 332 void UserScriptMaster::ScriptReloader::RunLoad( | 332 void UserScriptMaster::ScriptReloader::RunLoad( |
| 333 const UserScriptList& user_scripts) { | 333 const UserScriptList& user_scripts) { |
| 334 LoadUserScripts(const_cast<UserScriptList*>(&user_scripts)); | 334 LoadUserScripts(const_cast<UserScriptList*>(&user_scripts)); |
| 335 | 335 |
| 336 // Scripts now contains list of up-to-date scripts. Load the content in the | 336 // Scripts now contains list of up-to-date scripts. Load the content in the |
| 337 // shared memory and let the master know it's ready. We need to post the task | 337 // shared memory and let the master know it's ready. We need to post the task |
| 338 // back even if no scripts ware found to balance the AddRef/Release calls. | 338 // back even if no scripts ware found to balance the AddRef/Release calls. |
| 339 BrowserThread::PostTask( | 339 BrowserThread::PostTask( |
| 340 master_thread_id_, FROM_HERE, | 340 master_thread_id_, FROM_HERE, |
| 341 base::Bind( | 341 base::Bind(&ScriptReloader::NotifyMaster, this, |
|
Jeffrey Yasskin
2014/05/17 00:50:33
Generally use `git cl format` to format your chang
| |
| 342 &ScriptReloader::NotifyMaster, this, Serialize(user_scripts))); | 342 base::Passed(Serialize(user_scripts)))); |
| 343 } | 343 } |
| 344 | 344 |
| 345 UserScriptMaster::UserScriptMaster(Profile* profile) | 345 UserScriptMaster::UserScriptMaster(Profile* profile) |
| 346 : extensions_service_ready_(false), | 346 : extensions_service_ready_(false), |
| 347 pending_load_(false), | 347 pending_load_(false), |
| 348 profile_(profile), | 348 profile_(profile), |
| 349 extension_registry_observer_(this) { | 349 extension_registry_observer_(this) { |
| 350 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); | 350 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); |
| 351 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, | 351 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
| 352 content::Source<Profile>(profile_)); | 352 content::Source<Profile>(profile_)); |
| 353 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 353 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
| 354 content::NotificationService::AllBrowserContextsAndSources()); | 354 content::NotificationService::AllBrowserContextsAndSources()); |
| 355 } | 355 } |
| 356 | 356 |
| 357 UserScriptMaster::~UserScriptMaster() { | 357 UserScriptMaster::~UserScriptMaster() { |
| 358 if (script_reloader_.get()) | 358 if (script_reloader_.get()) |
| 359 script_reloader_->DisownMaster(); | 359 script_reloader_->DisownMaster(); |
| 360 } | 360 } |
| 361 | 361 |
| 362 void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) { | 362 void UserScriptMaster::NewScriptsAvailable( |
| 363 // Ensure handle is deleted or released. | 363 scoped_ptr<base::SharedMemory> handle) { |
| 364 scoped_ptr<base::SharedMemory> handle_deleter(handle); | |
| 365 | 364 |
| 366 if (pending_load_) { | 365 if (pending_load_) { |
| 367 // While we were loading, there were further changes. Don't bother | 366 // While we were loading, there were further changes. Don't bother |
| 368 // notifying about these scripts and instead just immediately reload. | 367 // notifying about these scripts and instead just immediately reload. |
| 369 pending_load_ = false; | 368 pending_load_ = false; |
| 370 StartLoad(); | 369 StartLoad(); |
| 371 } else { | 370 } else { |
| 372 // We're no longer loading. | 371 // We're no longer loading. |
| 373 script_reloader_ = NULL; | 372 script_reloader_ = NULL; |
| 374 | 373 |
| 375 if (handle == NULL) { | 374 if (handle == NULL) { |
| 376 // This can happen if we run out of file descriptors. In that case, we | 375 // This can happen if we run out of file descriptors. In that case, we |
| 377 // have a choice between silently omitting all user scripts for new tabs, | 376 // have a choice between silently omitting all user scripts for new tabs, |
| 378 // by nulling out shared_memory_, or only silently omitting new ones by | 377 // by nulling out shared_memory_, or only silently omitting new ones by |
| 379 // leaving the existing object in place. The second seems less bad, even | 378 // leaving the existing object in place. The second seems less bad, even |
| 380 // though it removes the possibility that freeing the shared memory block | 379 // though it removes the possibility that freeing the shared memory block |
| 381 // would open up enough FDs for long enough for a retry to succeed. | 380 // would open up enough FDs for long enough for a retry to succeed. |
| 382 | 381 |
| 383 // Pretend the extension change didn't happen. | 382 // Pretend the extension change didn't happen. |
| 384 return; | 383 return; |
| 385 } | 384 } |
| 386 | 385 |
| 387 // We've got scripts ready to go. | 386 // We've got scripts ready to go. |
| 388 shared_memory_.swap(handle_deleter); | 387 shared_memory_.swap(handle); |
|
Jeffrey Yasskin
2014/05/17 00:50:33
Since we're not using |handle| anymore, it's a bit
| |
| 389 | 388 |
| 390 for (content::RenderProcessHost::iterator i( | 389 for (content::RenderProcessHost::iterator i( |
| 391 content::RenderProcessHost::AllHostsIterator()); | 390 content::RenderProcessHost::AllHostsIterator()); |
| 392 !i.IsAtEnd(); i.Advance()) { | 391 !i.IsAtEnd(); i.Advance()) { |
| 393 SendUpdate(i.GetCurrentValue(), handle); | 392 SendUpdate(i.GetCurrentValue(), shared_memory_.get()); |
| 394 } | 393 } |
| 395 | 394 |
| 396 content::NotificationService::current()->Notify( | 395 content::NotificationService::current()->Notify( |
| 397 chrome::NOTIFICATION_USER_SCRIPTS_UPDATED, | 396 chrome::NOTIFICATION_USER_SCRIPTS_UPDATED, |
| 398 content::Source<Profile>(profile_), | 397 content::Source<Profile>(profile_), |
| 399 content::Details<base::SharedMemory>(handle)); | 398 content::Details<base::SharedMemory>(shared_memory_.get())); |
| 400 } | 399 } |
| 401 } | 400 } |
| 402 | 401 |
| 403 ContentVerifier* UserScriptMaster::content_verifier() { | 402 ContentVerifier* UserScriptMaster::content_verifier() { |
| 404 ExtensionSystem* system = ExtensionSystem::Get(profile_); | 403 ExtensionSystem* system = ExtensionSystem::Get(profile_); |
| 405 return system->content_verifier(); | 404 return system->content_verifier(); |
| 406 } | 405 } |
| 407 | 406 |
| 408 void UserScriptMaster::OnExtensionLoaded( | 407 void UserScriptMaster::OnExtensionLoaded( |
| 409 content::BrowserContext* browser_context, | 408 content::BrowserContext* browser_context, |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 510 | 509 |
| 511 base::SharedMemoryHandle handle_for_process; | 510 base::SharedMemoryHandle handle_for_process; |
| 512 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) | 511 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) |
| 513 return; // This can legitimately fail if the renderer asserts at startup. | 512 return; // This can legitimately fail if the renderer asserts at startup. |
| 514 | 513 |
| 515 if (base::SharedMemory::IsHandleValid(handle_for_process)) | 514 if (base::SharedMemory::IsHandleValid(handle_for_process)) |
| 516 process->Send(new ExtensionMsg_UpdateUserScripts(handle_for_process)); | 515 process->Send(new ExtensionMsg_UpdateUserScripts(handle_for_process)); |
| 517 } | 516 } |
| 518 | 517 |
| 519 } // namespace extensions | 518 } // namespace extensions |
| OLD | NEW |