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(master_thread_id_, |
340 master_thread_id_, FROM_HERE, | 340 FROM_HERE, |
341 base::Bind( | 341 base::Bind(&ScriptReloader::NotifyMaster, |
342 &ScriptReloader::NotifyMaster, this, Serialize(user_scripts))); | 342 this, |
| 343 base::Passed(Serialize(user_scripts)))); |
343 } | 344 } |
344 | 345 |
345 UserScriptMaster::UserScriptMaster(Profile* profile) | 346 UserScriptMaster::UserScriptMaster(Profile* profile) |
346 : extensions_service_ready_(false), | 347 : extensions_service_ready_(false), |
347 pending_load_(false), | 348 pending_load_(false), |
348 profile_(profile), | 349 profile_(profile), |
349 extension_registry_observer_(this) { | 350 extension_registry_observer_(this) { |
350 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); | 351 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); |
351 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, | 352 registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY, |
352 content::Source<Profile>(profile_)); | 353 content::Source<Profile>(profile_)); |
353 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 354 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
354 content::NotificationService::AllBrowserContextsAndSources()); | 355 content::NotificationService::AllBrowserContextsAndSources()); |
355 } | 356 } |
356 | 357 |
357 UserScriptMaster::~UserScriptMaster() { | 358 UserScriptMaster::~UserScriptMaster() { |
358 if (script_reloader_.get()) | 359 if (script_reloader_.get()) |
359 script_reloader_->DisownMaster(); | 360 script_reloader_->DisownMaster(); |
360 } | 361 } |
361 | 362 |
362 void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) { | 363 void UserScriptMaster::NewScriptsAvailable( |
363 // Ensure handle is deleted or released. | 364 scoped_ptr<base::SharedMemory> handle) { |
364 scoped_ptr<base::SharedMemory> handle_deleter(handle); | |
365 | |
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_ = handle.Pass(); |
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 |