| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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/activity_log/activity_log.h" | 5 #include "chrome/browser/extensions/activity_log/activity_log.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 ActivityLog* ActivityLog::GetInstance(content::BrowserContext* context) { | 538 ActivityLog* ActivityLog::GetInstance(content::BrowserContext* context) { |
| 539 return ActivityLog::GetFactoryInstance()->Get( | 539 return ActivityLog::GetFactoryInstance()->Get( |
| 540 Profile::FromBrowserContext(context)); | 540 Profile::FromBrowserContext(context)); |
| 541 } | 541 } |
| 542 | 542 |
| 543 // Use GetInstance instead of directly creating an ActivityLog. | 543 // Use GetInstance instead of directly creating an ActivityLog. |
| 544 ActivityLog::ActivityLog(content::BrowserContext* context) | 544 ActivityLog::ActivityLog(content::BrowserContext* context) |
| 545 : database_policy_(NULL), | 545 : database_policy_(NULL), |
| 546 database_policy_type_(ActivityLogPolicy::POLICY_INVALID), | 546 database_policy_type_(ActivityLogPolicy::POLICY_INVALID), |
| 547 profile_(Profile::FromBrowserContext(context)), | 547 profile_(Profile::FromBrowserContext(context)), |
| 548 extension_system_(ExtensionSystem::Get(context)), |
| 548 db_enabled_(false), | 549 db_enabled_(false), |
| 549 testing_mode_(false), | 550 testing_mode_(false), |
| 550 has_threads_(true), | 551 has_threads_(true), |
| 551 extension_registry_observer_(this), | 552 extension_registry_observer_(this), |
| 552 watchdog_apps_active_(0), | 553 active_consumers_(0), |
| 553 is_active_(false) { | 554 cached_consumer_count_(0), |
| 555 is_active_(false), |
| 556 weak_factory_(this) { |
| 554 SetActivityHandlers(); | 557 SetActivityHandlers(); |
| 555 | 558 |
| 556 // This controls whether logging statements are printed & which policy is set. | 559 // This controls whether logging statements are printed & which policy is set. |
| 557 testing_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch( | 560 testing_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 558 switches::kEnableExtensionActivityLogTesting); | 561 switches::kEnableExtensionActivityLogTesting); |
| 559 | 562 |
| 560 // Check if the watchdog extension is previously installed and active. | 563 // Check if the watchdog extension is previously installed and active. |
| 561 watchdog_apps_active_ = | 564 cached_consumer_count_ = |
| 562 profile_->GetPrefs()->GetInteger(prefs::kWatchdogExtensionActive); | 565 profile_->GetPrefs()->GetInteger(prefs::kWatchdogExtensionActive); |
| 563 | 566 |
| 564 observers_ = new base::ObserverListThreadSafe<Observer>; | 567 observers_ = new base::ObserverListThreadSafe<Observer>; |
| 565 | 568 |
| 566 // Check that the right threads exist for logging to the database. | 569 // Check that the right threads exist for logging to the database. |
| 567 // If not, we shouldn't try to do things that require them. | 570 // If not, we shouldn't try to do things that require them. |
| 568 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) || | 571 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) || |
| 569 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) || | 572 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) || |
| 570 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { | 573 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { |
| 571 has_threads_ = false; | 574 has_threads_ = false; |
| 572 } | 575 } |
| 573 | 576 |
| 574 db_enabled_ = | |
| 575 has_threads_ && (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 576 switches::kEnableExtensionActivityLogging) || | |
| 577 watchdog_apps_active_); | |
| 578 | |
| 579 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); | 577 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); |
| 580 ChooseDatabasePolicy(); | 578 CheckActive(true); // use cached |
| 581 | 579 extension_system_->ready().Post( |
| 582 CheckActive(); | 580 FROM_HERE, |
| 581 base::Bind(&ActivityLog::OnExtensionSystemReady, |
| 582 weak_factory_.GetWeakPtr())); |
| 583 } | 583 } |
| 584 | 584 |
| 585 void ActivityLog::SetDatabasePolicy( | 585 void ActivityLog::SetDatabasePolicy( |
| 586 ActivityLogPolicy::PolicyType policy_type) { | 586 ActivityLogPolicy::PolicyType policy_type) { |
| 587 if (database_policy_type_ == policy_type) | 587 if (database_policy_type_ == policy_type) |
| 588 return; | 588 return; |
| 589 if (!IsDatabaseEnabled() && !IsWatchdogAppActive()) | 589 if (!IsDatabaseEnabled() && !IsWatchdogAppActive()) |
| 590 return; | 590 return; |
| 591 | 591 |
| 592 // Deleting the old policy takes place asynchronously, on the database | 592 // Deleting the old policy takes place asynchronously, on the database |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 632 SetDatabasePolicy(ActivityLogPolicy::POLICY_COUNTS); | 632 SetDatabasePolicy(ActivityLogPolicy::POLICY_COUNTS); |
| 633 } | 633 } |
| 634 | 634 |
| 635 bool ActivityLog::IsDatabaseEnabled() { | 635 bool ActivityLog::IsDatabaseEnabled() { |
| 636 // Make sure we are not enabled when there are no threads. | 636 // Make sure we are not enabled when there are no threads. |
| 637 DCHECK(has_threads_ || !db_enabled_); | 637 DCHECK(has_threads_ || !db_enabled_); |
| 638 return db_enabled_; | 638 return db_enabled_; |
| 639 } | 639 } |
| 640 | 640 |
| 641 bool ActivityLog::IsWatchdogAppActive() { | 641 bool ActivityLog::IsWatchdogAppActive() { |
| 642 return (watchdog_apps_active_ > 0); | 642 return active_consumers_ > 0; |
| 643 } |
| 644 |
| 645 void ActivityLog::UpdateCachedConsumerCount() { |
| 646 cached_consumer_count_ = active_consumers_; |
| 647 profile_->GetPrefs()->SetInteger(prefs::kWatchdogExtensionActive, |
| 648 cached_consumer_count_); |
| 643 } | 649 } |
| 644 | 650 |
| 645 void ActivityLog::SetWatchdogAppActiveForTesting(bool active) { | 651 void ActivityLog::SetWatchdogAppActiveForTesting(bool active) { |
| 646 watchdog_apps_active_ = active ? 1 : 0; | 652 active_consumers_ = active ? 1 : 0; |
| 647 CheckActive(); | 653 CheckActive(false); // don't use cached |
| 648 } | 654 } |
| 649 | 655 |
| 650 void ActivityLog::OnExtensionLoaded(content::BrowserContext* browser_context, | 656 void ActivityLog::OnExtensionLoaded(content::BrowserContext* browser_context, |
| 651 const Extension* extension) { | 657 const Extension* extension) { |
| 652 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) | 658 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) |
| 653 return; | 659 return; |
| 654 if (has_threads_) | |
| 655 db_enabled_ = true; | |
| 656 g_activity_log_state.Get().AddWhitelistedId(extension->id()); | 660 g_activity_log_state.Get().AddWhitelistedId(extension->id()); |
| 657 watchdog_apps_active_++; | 661 ++active_consumers_; |
| 658 profile_->GetPrefs()->SetInteger(prefs::kWatchdogExtensionActive, | |
| 659 watchdog_apps_active_); | |
| 660 if (watchdog_apps_active_ == 1) | |
| 661 ChooseDatabasePolicy(); | |
| 662 | 662 |
| 663 if (!is_active_) | 663 if (!extension_system_->ready().is_signaled()) |
| 664 CheckActive(); | 664 return; |
| 665 |
| 666 CheckActive(false); // don't use cached |
| 667 UpdateCachedConsumerCount(); |
| 665 } | 668 } |
| 666 | 669 |
| 667 void ActivityLog::OnExtensionUnloaded(content::BrowserContext* browser_context, | 670 void ActivityLog::OnExtensionUnloaded(content::BrowserContext* browser_context, |
| 668 const Extension* extension, | 671 const Extension* extension, |
| 669 UnloadedExtensionInfo::Reason reason) { | 672 UnloadedExtensionInfo::Reason reason) { |
| 670 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) | 673 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) |
| 671 return; | 674 return; |
| 672 watchdog_apps_active_--; | 675 --active_consumers_; |
| 673 profile_->GetPrefs()->SetInteger(prefs::kWatchdogExtensionActive, | |
| 674 watchdog_apps_active_); | |
| 675 if (watchdog_apps_active_ == 0 && | |
| 676 !base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 677 switches::kEnableExtensionActivityLogging)) { | |
| 678 db_enabled_ = false; | |
| 679 } | |
| 680 | 676 |
| 681 if (is_active_) | 677 if (!extension_system_->ready().is_signaled()) |
| 682 CheckActive(); | 678 return; |
| 679 |
| 680 CheckActive(false); // don't use cached |
| 681 UpdateCachedConsumerCount(); |
| 683 } | 682 } |
| 684 | 683 |
| 685 // OnExtensionUnloaded will also be called right before this. | 684 // OnExtensionUnloaded will also be called right before this. |
| 686 void ActivityLog::OnExtensionUninstalled( | 685 void ActivityLog::OnExtensionUninstalled( |
| 687 content::BrowserContext* browser_context, | 686 content::BrowserContext* browser_context, |
| 688 const Extension* extension, | 687 const Extension* extension, |
| 689 extensions::UninstallReason reason) { | 688 extensions::UninstallReason reason) { |
| 690 if (ActivityLogAPI::IsExtensionWhitelisted(extension->id()) && | 689 if (ActivityLogAPI::IsExtensionWhitelisted(extension->id()) && |
| 691 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 690 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 692 switches::kEnableExtensionActivityLogging) && | 691 switches::kEnableExtensionActivityLogging) && |
| 693 watchdog_apps_active_ == 0) { | 692 active_consumers_ == 0) { |
| 694 DeleteDatabase(); | 693 DeleteDatabase(); |
| 695 } else if (database_policy_) { | 694 } else if (database_policy_) { |
| 696 database_policy_->RemoveExtensionData(extension->id()); | 695 database_policy_->RemoveExtensionData(extension->id()); |
| 697 } | 696 } |
| 698 } | 697 } |
| 699 | 698 |
| 700 void ActivityLog::AddObserver(ActivityLog::Observer* observer) { | 699 void ActivityLog::AddObserver(ActivityLog::Observer* observer) { |
| 701 observers_->AddObserver(observer); | 700 observers_->AddObserver(observer); |
| 702 } | 701 } |
| 703 | 702 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 725 base::StartsWith(action->api_name(), kDomXhrPrefix, | 724 base::StartsWith(action->api_name(), kDomXhrPrefix, |
| 726 base::CompareCase::SENSITIVE) && | 725 base::CompareCase::SENSITIVE) && |
| 727 action->other()) { | 726 action->other()) { |
| 728 base::DictionaryValue* other = action->mutable_other(); | 727 base::DictionaryValue* other = action->mutable_other(); |
| 729 int dom_verb = -1; | 728 int dom_verb = -1; |
| 730 if (other->GetInteger(constants::kActionDomVerb, &dom_verb) && | 729 if (other->GetInteger(constants::kActionDomVerb, &dom_verb) && |
| 731 dom_verb == DomActionType::METHOD) { | 730 dom_verb == DomActionType::METHOD) { |
| 732 other->SetInteger(constants::kActionDomVerb, DomActionType::XHR); | 731 other->SetInteger(constants::kActionDomVerb, DomActionType::XHR); |
| 733 } | 732 } |
| 734 } | 733 } |
| 735 | |
| 736 if (IsDatabaseEnabled() && database_policy_) | 734 if (IsDatabaseEnabled() && database_policy_) |
| 737 database_policy_->ProcessAction(action); | 735 database_policy_->ProcessAction(action); |
| 738 if (IsWatchdogAppActive()) | 736 if (IsWatchdogAppActive()) |
| 739 observers_->Notify(FROM_HERE, &Observer::OnExtensionActivity, action); | 737 observers_->Notify(FROM_HERE, &Observer::OnExtensionActivity, action); |
| 740 if (testing_mode_) | 738 if (testing_mode_) |
| 741 VLOG(1) << action->PrintForDebug(); | 739 VLOG(1) << action->PrintForDebug(); |
| 742 } | 740 } |
| 743 | 741 |
| 744 bool ActivityLog::ShouldLog(const std::string& extension_id) const { | 742 bool ActivityLog::ShouldLog(const std::string& extension_id) const { |
| 745 return is_active_ && !ActivityLogAPI::IsExtensionWhitelisted(extension_id); | 743 return is_active_ && !ActivityLogAPI::IsExtensionWhitelisted(extension_id); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 838 urls.push_back(url); | 836 urls.push_back(url); |
| 839 RemoveURLs(urls); | 837 RemoveURLs(urls); |
| 840 } | 838 } |
| 841 | 839 |
| 842 void ActivityLog::DeleteDatabase() { | 840 void ActivityLog::DeleteDatabase() { |
| 843 if (!database_policy_) | 841 if (!database_policy_) |
| 844 return; | 842 return; |
| 845 database_policy_->DeleteDatabase(); | 843 database_policy_->DeleteDatabase(); |
| 846 } | 844 } |
| 847 | 845 |
| 848 void ActivityLog::CheckActive() { | 846 void ActivityLog::CheckActive(bool use_cached) { |
| 849 bool has_db = db_enabled_ && database_policy_; | 847 bool has_consumer = |
| 848 active_consumers_ || (use_cached && cached_consumer_count_); |
| 849 bool needs_db = |
| 850 has_threads_ && (has_consumer || |
| 851 base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 852 switches::kEnableExtensionActivityLogging)); |
| 853 bool should_be_active = needs_db || has_consumer; |
| 854 |
| 855 if (should_be_active == is_active_) |
| 856 return; |
| 857 |
| 850 ActivityLogState& state = g_activity_log_state.Get(); | 858 ActivityLogState& state = g_activity_log_state.Get(); |
| 851 content::BrowserContext* off_the_record = | 859 content::BrowserContext* off_the_record = |
| 852 profile_->HasOffTheRecordProfile() ? profile_->GetOffTheRecordProfile() | 860 profile_->HasOffTheRecordProfile() ? profile_->GetOffTheRecordProfile() |
| 853 : nullptr; | 861 : nullptr; |
| 862 bool has_db = db_enabled_ && database_policy_; |
| 863 bool old_is_active = is_active_; |
| 854 | 864 |
| 855 bool old_is_active = is_active_; | 865 if (should_be_active) { |
| 856 if (has_db || IsWatchdogAppActive()) { | 866 if (needs_db && !has_db) { |
| 857 if (is_active_) | 867 db_enabled_ = true; |
| 858 return; // Already enabled. | 868 ChooseDatabasePolicy(); |
| 869 } |
| 870 |
| 859 state.AddActiveContext(profile_); | 871 state.AddActiveContext(profile_); |
| 860 if (off_the_record) | 872 if (off_the_record) |
| 861 state.AddActiveContext(off_the_record); | 873 state.AddActiveContext(off_the_record); |
| 862 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, | 874 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
| 863 content::NotificationService::AllSources()); | 875 content::NotificationService::AllSources()); |
| 864 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 876 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 865 content::NotificationService::AllSources()); | 877 content::NotificationService::AllSources()); |
| 866 is_active_ = true; | 878 is_active_ = true; |
| 867 } else if (is_active_) { | 879 } else { |
| 880 if (has_db && !needs_db) |
| 881 db_enabled_ = false; |
| 868 state.RemoveActiveContext(profile_); | 882 state.RemoveActiveContext(profile_); |
| 869 if (off_the_record) | 883 if (off_the_record) |
| 870 state.RemoveActiveContext(off_the_record); | 884 state.RemoveActiveContext(off_the_record); |
| 871 registrar_.RemoveAll(); | 885 registrar_.RemoveAll(); |
| 872 is_active_ = false; | 886 is_active_ = false; |
| 873 } | 887 } |
| 874 | 888 |
| 875 if (old_is_active != is_active_) { | 889 DCHECK_NE(is_active_, old_is_active); |
| 876 for (content::RenderProcessHost::iterator iter( | 890 for (content::RenderProcessHost::iterator iter( |
| 877 content::RenderProcessHost::AllHostsIterator()); | 891 content::RenderProcessHost::AllHostsIterator()); |
| 878 !iter.IsAtEnd(); iter.Advance()) { | 892 !iter.IsAtEnd(); iter.Advance()) { |
| 879 content::RenderProcessHost* host = iter.GetCurrentValue(); | 893 content::RenderProcessHost* host = iter.GetCurrentValue(); |
| 880 if (profile_->IsSameProfile( | 894 if (profile_->IsSameProfile( |
| 881 Profile::FromBrowserContext(host->GetBrowserContext()))) { | 895 Profile::FromBrowserContext(host->GetBrowserContext()))) { |
| 882 host->Send(new ExtensionMsg_SetActivityLoggingEnabled(is_active_)); | 896 host->Send(new ExtensionMsg_SetActivityLoggingEnabled(is_active_)); |
| 883 } | |
| 884 } | 897 } |
| 885 } | 898 } |
| 886 } | 899 } |
| 887 | 900 |
| 888 void ActivityLog::Observe(int type, | 901 void ActivityLog::Observe(int type, |
| 889 const content::NotificationSource& source, | 902 const content::NotificationSource& source, |
| 890 const content::NotificationDetails& details) { | 903 const content::NotificationDetails& details) { |
| 891 DCHECK(is_active_); | 904 DCHECK(is_active_); |
| 892 switch (type) { | 905 switch (type) { |
| 893 case chrome::NOTIFICATION_PROFILE_CREATED: { | 906 case chrome::NOTIFICATION_PROFILE_CREATED: { |
| 894 Profile* profile = content::Source<Profile>(source).ptr(); | 907 Profile* profile = content::Source<Profile>(source).ptr(); |
| 895 if (profile_->IsSameProfile(profile)) | 908 if (profile_->IsSameProfile(profile)) |
| 896 g_activity_log_state.Get().AddActiveContext(profile); | 909 g_activity_log_state.Get().AddActiveContext(profile); |
| 897 break; | 910 break; |
| 898 } | 911 } |
| 899 case chrome::NOTIFICATION_PROFILE_DESTROYED: { | 912 case chrome::NOTIFICATION_PROFILE_DESTROYED: { |
| 900 Profile* profile = content::Source<Profile>(source).ptr(); | 913 Profile* profile = content::Source<Profile>(source).ptr(); |
| 901 if (profile_->IsSameProfile(profile)) | 914 if (profile_->IsSameProfile(profile)) |
| 902 g_activity_log_state.Get().RemoveActiveContext(profile); | 915 g_activity_log_state.Get().RemoveActiveContext(profile); |
| 903 break; | 916 break; |
| 904 } | 917 } |
| 905 default: | 918 default: |
| 906 NOTREACHED(); | 919 NOTREACHED(); |
| 907 } | 920 } |
| 908 } | 921 } |
| 909 | 922 |
| 923 void ActivityLog::OnExtensionSystemReady() { |
| 924 if (active_consumers_ != cached_consumer_count_) { |
| 925 CheckActive(false); |
| 926 UpdateCachedConsumerCount(); |
| 927 } |
| 928 } |
| 929 |
| 910 template <> | 930 template <> |
| 911 void BrowserContextKeyedAPIFactory<ActivityLog>::DeclareFactoryDependencies() { | 931 void BrowserContextKeyedAPIFactory<ActivityLog>::DeclareFactoryDependencies() { |
| 912 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); | 932 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); |
| 913 DependsOn(ExtensionRegistryFactory::GetInstance()); | 933 DependsOn(ExtensionRegistryFactory::GetInstance()); |
| 914 } | 934 } |
| 915 | 935 |
| 916 } // namespace extensions | 936 } // namespace extensions |
| OLD | NEW |