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/background/background_contents_service.h" | 5 #include "chrome/browser/background/background_contents_service.h" |
6 | 6 |
7 #include "apps/app_load_service.h" | 7 #include "apps/app_load_service.h" |
8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 // <appid_2>: { "url": <url2>, "name": <frame_name> }, | 254 // <appid_2>: { "url": <url2>, "name": <frame_name> }, |
255 // ... etc ... | 255 // ... etc ... |
256 // } | 256 // } |
257 const char kUrlKey[] = "url"; | 257 const char kUrlKey[] = "url"; |
258 const char kFrameNameKey[] = "name"; | 258 const char kFrameNameKey[] = "name"; |
259 | 259 |
260 int BackgroundContentsService::restart_delay_in_ms_ = 3000; // 3 seconds. | 260 int BackgroundContentsService::restart_delay_in_ms_ = 3000; // 3 seconds. |
261 | 261 |
262 BackgroundContentsService::BackgroundContentsService( | 262 BackgroundContentsService::BackgroundContentsService( |
263 Profile* profile, const CommandLine* command_line) | 263 Profile* profile, const CommandLine* command_line) |
264 : prefs_(NULL) { | 264 : prefs_(NULL), extension_registry_observer_(this) { |
265 // Don't load/store preferences if the parent profile is incognito. | 265 // Don't load/store preferences if the parent profile is incognito. |
266 if (!profile->IsOffTheRecord()) | 266 if (!profile->IsOffTheRecord()) |
267 prefs_ = profile->GetPrefs(); | 267 prefs_ = profile->GetPrefs(); |
268 | 268 |
269 // Listen for events to tell us when to load/unload persisted background | 269 // Listen for events to tell us when to load/unload persisted background |
270 // contents. | 270 // contents. |
271 StartObserving(profile); | 271 StartObserving(profile); |
272 } | 272 } |
273 | 273 |
274 BackgroundContentsService::~BackgroundContentsService() { | 274 BackgroundContentsService::~BackgroundContentsService() { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 // Stop tracking BackgroundContents when they have been deleted (happens | 322 // Stop tracking BackgroundContents when they have been deleted (happens |
323 // during shutdown or if the render process dies). | 323 // during shutdown or if the render process dies). |
324 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, | 324 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, |
325 content::Source<Profile>(profile)); | 325 content::Source<Profile>(profile)); |
326 | 326 |
327 // Track when the BackgroundContents navigates to a new URL so we can update | 327 // Track when the BackgroundContents navigates to a new URL so we can update |
328 // our persisted information as appropriate. | 328 // our persisted information as appropriate. |
329 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, | 329 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, |
330 content::Source<Profile>(profile)); | 330 content::Source<Profile>(profile)); |
331 | 331 |
332 // Listen for new extension installs so that we can load any associated | |
333 // background page. | |
334 registrar_.Add(this, | |
335 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, | |
336 content::Source<Profile>(profile)); | |
337 | |
338 // Track when the extensions crash so that the user can be notified | 332 // Track when the extensions crash so that the user can be notified |
339 // about it, and the crashed contents can be restarted. | 333 // about it, and the crashed contents can be restarted. |
340 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, | 334 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, |
341 content::Source<Profile>(profile)); | 335 content::Source<Profile>(profile)); |
342 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED, | 336 registrar_.Add(this, chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED, |
343 content::Source<Profile>(profile)); | 337 content::Source<Profile>(profile)); |
344 | 338 |
345 // Listen for extensions to be unloaded so we can shutdown associated | 339 // Listen for extension uninstall, load, unloaded notification. |
346 // BackgroundContents. | 340 extension_registry_observer_.Add(extensions::ExtensionRegistry::Get(profile)); |
347 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, | |
348 content::Source<Profile>(profile)); | |
349 | |
350 // Make sure the extension-crash balloons are removed when the extension is | |
351 // uninstalled/reloaded. We cannot do this from UNLOADED since a crashed | |
352 // extension is unloaded immediately after the crash, not when user reloads or | |
353 // uninstalls the extension. | |
354 registrar_.Add(this, | |
355 chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED, | |
356 content::Source<Profile>(profile)); | |
357 } | 341 } |
358 | 342 |
359 void BackgroundContentsService::Observe( | 343 void BackgroundContentsService::Observe( |
360 int type, | 344 int type, |
361 const content::NotificationSource& source, | 345 const content::NotificationSource& source, |
362 const content::NotificationDetails& details) { | 346 const content::NotificationDetails& details) { |
363 switch (type) { | 347 switch (type) { |
364 case chrome::NOTIFICATION_EXTENSIONS_READY: { | 348 case chrome::NOTIFICATION_EXTENSIONS_READY: { |
365 Profile* profile = content::Source<Profile>(source).ptr(); | 349 Profile* profile = content::Source<Profile>(source).ptr(); |
366 LoadBackgroundContentsFromManifests(profile); | 350 LoadBackgroundContentsFromManifests(profile); |
(...skipping 27 matching lines...) Expand all Loading... |
394 // extension_service can be NULL when running tests. | 378 // extension_service can be NULL when running tests. |
395 if (extension_service) { | 379 if (extension_service) { |
396 const Extension* extension = extension_service->GetExtensionById( | 380 const Extension* extension = extension_service->GetExtensionById( |
397 base::UTF16ToUTF8(appid), false); | 381 base::UTF16ToUTF8(appid), false); |
398 if (extension && BackgroundInfo::HasBackgroundPage(extension)) | 382 if (extension && BackgroundInfo::HasBackgroundPage(extension)) |
399 break; | 383 break; |
400 } | 384 } |
401 RegisterBackgroundContents(bgcontents); | 385 RegisterBackgroundContents(bgcontents); |
402 break; | 386 break; |
403 } | 387 } |
404 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: { | |
405 const Extension* extension = | |
406 content::Details<const Extension>(details).ptr(); | |
407 Profile* profile = content::Source<Profile>(source).ptr(); | |
408 if (extension->is_hosted_app() && | |
409 BackgroundInfo::HasBackgroundPage(extension)) { | |
410 // If there is a background page specified in the manifest for a hosted | |
411 // app, then blow away registered urls in the pref. | |
412 ShutdownAssociatedBackgroundContents( | |
413 base::ASCIIToUTF16(extension->id())); | |
414 | |
415 ExtensionService* service = | |
416 extensions::ExtensionSystem::Get(profile)->extension_service(); | |
417 if (service && service->is_ready()) { | |
418 // Now load the manifest-specified background page. If service isn't | |
419 // ready, then the background page will be loaded from the | |
420 // EXTENSIONS_READY callback. | |
421 LoadBackgroundContents(profile, | |
422 BackgroundInfo::GetBackgroundURL(extension), | |
423 base::ASCIIToUTF16("background"), | |
424 base::UTF8ToUTF16(extension->id())); | |
425 } | |
426 } | |
427 | |
428 // Close the crash notification balloon for the app/extension, if any. | |
429 ScheduleCloseBalloon(extension->id()); | |
430 SendChangeNotification(profile); | |
431 break; | |
432 } | |
433 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: | 388 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: |
434 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED: { | 389 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED: { |
435 Profile* profile = content::Source<Profile>(source).ptr(); | 390 Profile* profile = content::Source<Profile>(source).ptr(); |
436 const Extension* extension = NULL; | 391 const Extension* extension = NULL; |
437 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED) { | 392 if (type == chrome::NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED) { |
438 BackgroundContents* bg = | 393 BackgroundContents* bg = |
439 content::Details<BackgroundContents>(details).ptr(); | 394 content::Details<BackgroundContents>(details).ptr(); |
440 std::string extension_id = base::UTF16ToASCII( | 395 std::string extension_id = base::UTF16ToASCII( |
441 BackgroundContentsServiceFactory::GetForProfile(profile)-> | 396 BackgroundContentsServiceFactory::GetForProfile(profile)-> |
442 GetParentApplicationId(bg)); | 397 GetParentApplicationId(bg)); |
(...skipping 12 matching lines...) Expand all Loading... |
455 extensions::Manifest::IsComponentLocation(extension->location()) || | 410 extensions::Manifest::IsComponentLocation(extension->location()) || |
456 extensions::Manifest::IsPolicyLocation(extension->location()); | 411 extensions::Manifest::IsPolicyLocation(extension->location()); |
457 if (!force_installed) { | 412 if (!force_installed) { |
458 ShowBalloon(extension, profile); | 413 ShowBalloon(extension, profile); |
459 } else { | 414 } else { |
460 // Restart the extension. | 415 // Restart the extension. |
461 RestartForceInstalledExtensionOnCrash(extension, profile); | 416 RestartForceInstalledExtensionOnCrash(extension, profile); |
462 } | 417 } |
463 break; | 418 break; |
464 } | 419 } |
465 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: | |
466 switch (content::Details<UnloadedExtensionInfo>(details)->reason) { | |
467 case UnloadedExtensionInfo::REASON_DISABLE: // Fall through. | |
468 case UnloadedExtensionInfo::REASON_TERMINATE: // Fall through. | |
469 case UnloadedExtensionInfo::REASON_UNINSTALL: // Fall through. | |
470 case UnloadedExtensionInfo::REASON_BLACKLIST: // Fall through. | |
471 case UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN: | |
472 ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16( | |
473 content::Details<UnloadedExtensionInfo>(details)-> | |
474 extension->id())); | |
475 SendChangeNotification(content::Source<Profile>(source).ptr()); | |
476 break; | |
477 case UnloadedExtensionInfo::REASON_UPDATE: { | |
478 // If there is a manifest specified background page, then shut it down | |
479 // here, since if the updated extension still has the background page, | |
480 // then it will be loaded from LOADED callback. Otherwise, leave | |
481 // BackgroundContents in place. | |
482 // We don't call SendChangeNotification here - it will be generated | |
483 // from the LOADED callback. | |
484 const Extension* extension = | |
485 content::Details<UnloadedExtensionInfo>(details)->extension; | |
486 if (BackgroundInfo::HasBackgroundPage(extension)) { | |
487 ShutdownAssociatedBackgroundContents( | |
488 base::ASCIIToUTF16(extension->id())); | |
489 } | |
490 break; | |
491 } | |
492 default: | |
493 NOTREACHED(); | |
494 ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16( | |
495 content::Details<UnloadedExtensionInfo>(details)-> | |
496 extension->id())); | |
497 break; | |
498 } | |
499 break; | |
500 | |
501 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED: { | |
502 // Close the crash notification balloon for the app/extension, if any. | |
503 ScheduleCloseBalloon( | |
504 content::Details<const Extension>(details).ptr()->id()); | |
505 break; | |
506 } | |
507 | 420 |
508 default: | 421 default: |
509 NOTREACHED(); | 422 NOTREACHED(); |
510 break; | 423 break; |
511 } | 424 } |
512 } | 425 } |
513 | 426 |
| 427 void BackgroundContentsService::OnExtensionLoaded( |
| 428 content::BrowserContext* browser_context, |
| 429 const extensions::Extension* extension) { |
| 430 Profile* profile = Profile::FromBrowserContext(browser_context); |
| 431 if (extension->is_hosted_app() && |
| 432 BackgroundInfo::HasBackgroundPage(extension)) { |
| 433 // If there is a background page specified in the manifest for a hosted |
| 434 // app, then blow away registered urls in the pref. |
| 435 ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16(extension->id())); |
| 436 |
| 437 ExtensionService* service = |
| 438 extensions::ExtensionSystem::Get(browser_context)->extension_service(); |
| 439 if (service && service->is_ready()) { |
| 440 // Now load the manifest-specified background page. If service isn't |
| 441 // ready, then the background page will be loaded from the |
| 442 // EXTENSIONS_READY callback. |
| 443 LoadBackgroundContents(profile, |
| 444 BackgroundInfo::GetBackgroundURL(extension), |
| 445 base::ASCIIToUTF16("background"), |
| 446 base::UTF8ToUTF16(extension->id())); |
| 447 } |
| 448 } |
| 449 |
| 450 // Close the crash notification balloon for the app/extension, if any. |
| 451 ScheduleCloseBalloon(extension->id()); |
| 452 SendChangeNotification(profile); |
| 453 } |
| 454 |
| 455 void BackgroundContentsService::OnExtensionUnloaded( |
| 456 content::BrowserContext* browser_context, |
| 457 const extensions::Extension* extension, |
| 458 extensions::UnloadedExtensionInfo::Reason reason) { |
| 459 switch (reason) { |
| 460 case UnloadedExtensionInfo::REASON_DISABLE: // Fall through. |
| 461 case UnloadedExtensionInfo::REASON_TERMINATE: // Fall through. |
| 462 case UnloadedExtensionInfo::REASON_UNINSTALL: // Fall through. |
| 463 case UnloadedExtensionInfo::REASON_BLACKLIST: // Fall through. |
| 464 case UnloadedExtensionInfo::REASON_PROFILE_SHUTDOWN: |
| 465 ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16(extension->id())); |
| 466 SendChangeNotification(Profile::FromBrowserContext(browser_context)); |
| 467 break; |
| 468 case UnloadedExtensionInfo::REASON_UPDATE: { |
| 469 // If there is a manifest specified background page, then shut it down |
| 470 // here, since if the updated extension still has the background page, |
| 471 // then it will be loaded from LOADED callback. Otherwise, leave |
| 472 // BackgroundContents in place. |
| 473 // We don't call SendChangeNotification here - it will be generated |
| 474 // from the LOADED callback. |
| 475 if (BackgroundInfo::HasBackgroundPage(extension)) { |
| 476 ShutdownAssociatedBackgroundContents( |
| 477 base::ASCIIToUTF16(extension->id())); |
| 478 } |
| 479 break; |
| 480 } |
| 481 default: |
| 482 NOTREACHED(); |
| 483 ShutdownAssociatedBackgroundContents(base::ASCIIToUTF16(extension->id())); |
| 484 break; |
| 485 } |
| 486 } |
| 487 |
| 488 void BackgroundContentsService::OnExtensionUninstalled( |
| 489 content::BrowserContext* browser_context, |
| 490 const extensions::Extension* extension, |
| 491 extensions::UninstallReason reason) { |
| 492 // Make sure the extension-crash balloons are removed when the extension is |
| 493 // uninstalled/reloaded. We cannot do this from UNLOADED since a crashed |
| 494 // extension is unloaded immediately after the crash, not when user reloads or |
| 495 // uninstalls the extension. |
| 496 ScheduleCloseBalloon(extension->id()); |
| 497 } |
| 498 |
514 void BackgroundContentsService::RestartForceInstalledExtensionOnCrash( | 499 void BackgroundContentsService::RestartForceInstalledExtensionOnCrash( |
515 const Extension* extension, | 500 const Extension* extension, |
516 Profile* profile) { | 501 Profile* profile) { |
517 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, | 502 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, |
518 base::Bind(&ReloadExtension, extension->id(), profile), | 503 base::Bind(&ReloadExtension, extension->id(), profile), |
519 base::TimeDelta::FromMilliseconds(restart_delay_in_ms_)); | 504 base::TimeDelta::FromMilliseconds(restart_delay_in_ms_)); |
520 } | 505 } |
521 | 506 |
522 // Loads all background contents whose urls have been stored in prefs. | 507 // Loads all background contents whose urls have been stored in prefs. |
523 void BackgroundContentsService::LoadBackgroundContentsFromPrefs( | 508 void BackgroundContentsService::LoadBackgroundContentsFromPrefs( |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 bool user_gesture, | 771 bool user_gesture, |
787 bool* was_blocked) { | 772 bool* was_blocked) { |
788 Browser* browser = chrome::FindLastActiveWithProfile( | 773 Browser* browser = chrome::FindLastActiveWithProfile( |
789 Profile::FromBrowserContext(new_contents->GetBrowserContext()), | 774 Profile::FromBrowserContext(new_contents->GetBrowserContext()), |
790 chrome::GetActiveDesktop()); | 775 chrome::GetActiveDesktop()); |
791 if (browser) { | 776 if (browser) { |
792 chrome::AddWebContents(browser, NULL, new_contents, disposition, | 777 chrome::AddWebContents(browser, NULL, new_contents, disposition, |
793 initial_pos, user_gesture, was_blocked); | 778 initial_pos, user_gesture, was_blocked); |
794 } | 779 } |
795 } | 780 } |
OLD | NEW |