| 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> |
| 11 | 11 |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/json/json_string_value_serializer.h" | 13 #include "base/json/json_string_value_serializer.h" |
| 14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/macros.h" | 16 #include "base/macros.h" |
| 17 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
| 18 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
| 19 #include "base/synchronization/lock.h" |
| 19 #include "base/threading/thread_checker.h" | 20 #include "base/threading/thread_checker.h" |
| 21 #include "chrome/browser/chrome_notification_types.h" |
| 20 #include "chrome/browser/extensions/activity_log/activity_action_constants.h" | 22 #include "chrome/browser/extensions/activity_log/activity_action_constants.h" |
| 21 #include "chrome/browser/extensions/activity_log/counting_policy.h" | 23 #include "chrome/browser/extensions/activity_log/counting_policy.h" |
| 22 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h" | 24 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h" |
| 23 #include "chrome/browser/extensions/api/activity_log_private/activity_log_privat
e_api.h" | 25 #include "chrome/browser/extensions/api/activity_log_private/activity_log_privat
e_api.h" |
| 24 #include "chrome/browser/extensions/extension_tab_util.h" | 26 #include "chrome/browser/extensions/extension_tab_util.h" |
| 25 #include "chrome/browser/prerender/prerender_manager.h" | 27 #include "chrome/browser/prerender/prerender_manager.h" |
| 26 #include "chrome/browser/prerender/prerender_manager_factory.h" | 28 #include "chrome/browser/prerender/prerender_manager_factory.h" |
| 27 #include "chrome/browser/profiles/profile.h" | 29 #include "chrome/browser/profiles/profile.h" |
| 28 #include "chrome/browser/ui/browser.h" | 30 #include "chrome/browser/ui/browser.h" |
| 29 #include "chrome/common/chrome_constants.h" | 31 #include "chrome/common/chrome_constants.h" |
| 30 #include "chrome/common/chrome_switches.h" | 32 #include "chrome/common/chrome_switches.h" |
| 31 #include "chrome/common/pref_names.h" | 33 #include "chrome/common/pref_names.h" |
| 32 #include "components/syncable_prefs/pref_service_syncable.h" | 34 #include "components/syncable_prefs/pref_service_syncable.h" |
| 33 #include "content/public/browser/browser_thread.h" | 35 #include "content/public/browser/browser_thread.h" |
| 36 #include "content/public/browser/notification_service.h" |
| 37 #include "content/public/browser/notification_source.h" |
| 34 #include "content/public/browser/web_contents.h" | 38 #include "content/public/browser/web_contents.h" |
| 39 #include "extensions/browser/api_activity_monitor.h" |
| 35 #include "extensions/browser/extension_registry.h" | 40 #include "extensions/browser/extension_registry.h" |
| 36 #include "extensions/browser/extension_registry_factory.h" | 41 #include "extensions/browser/extension_registry_factory.h" |
| 37 #include "extensions/browser/extension_system.h" | 42 #include "extensions/browser/extension_system.h" |
| 38 #include "extensions/browser/extension_system_provider.h" | 43 #include "extensions/browser/extension_system_provider.h" |
| 39 #include "extensions/browser/extensions_browser_client.h" | 44 #include "extensions/browser/extensions_browser_client.h" |
| 40 #include "extensions/common/extension.h" | 45 #include "extensions/common/extension.h" |
| 41 #include "extensions/common/one_shot_event.h" | 46 #include "extensions/common/one_shot_event.h" |
| 42 #include "third_party/re2/src/re2/re2.h" | 47 #include "third_party/re2/src/re2/re2.h" |
| 43 #include "url/gurl.h" | 48 #include "url/gurl.h" |
| 44 | 49 |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 default: | 331 default: |
| 327 NOTREACHED(); | 332 NOTREACHED(); |
| 328 } | 333 } |
| 329 | 334 |
| 330 if (arg_url.is_valid()) { | 335 if (arg_url.is_valid()) { |
| 331 action->set_arg_incognito(arg_incognito); | 336 action->set_arg_incognito(arg_incognito); |
| 332 action->set_arg_url(arg_url); | 337 action->set_arg_url(arg_url); |
| 333 } | 338 } |
| 334 } | 339 } |
| 335 | 340 |
| 341 // A global, thread-safe record of activity log state. |
| 342 class ActivityLogState { |
| 343 public: |
| 344 ActivityLogState() {} |
| 345 ~ActivityLogState() {} |
| 346 |
| 347 void AddActiveContext(content::BrowserContext* context) { |
| 348 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 349 base::AutoLock lock(lock_); |
| 350 contexts_.insert(context); |
| 351 } |
| 352 |
| 353 void RemoveActiveContext(content::BrowserContext* context) { |
| 354 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 355 base::AutoLock lock(lock_); |
| 356 contexts_.erase(context); |
| 357 } |
| 358 |
| 359 bool IsActiveContext(content::BrowserContext* context) { |
| 360 base::AutoLock lock(lock_); |
| 361 return contexts_.count(context) > 0; |
| 362 } |
| 363 |
| 364 void AddWhitelistedId(const std::string& id) { |
| 365 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 366 base::AutoLock lock(lock_); |
| 367 whitelisted_ids_.insert(id); |
| 368 } |
| 369 |
| 370 // We don't remove the id entry from g_activity_log_state because it may be |
| 371 // loaded in multiple profiles, and being whitelisted for the ActivityLog |
| 372 // is a global permission. |
| 373 |
| 374 bool IsWhitelistedId(const std::string& id) { |
| 375 base::AutoLock lock(lock_); |
| 376 return whitelisted_ids_.count(id) > 0; |
| 377 } |
| 378 |
| 379 private: |
| 380 std::set<const content::BrowserContext*> contexts_; |
| 381 std::set<std::string> whitelisted_ids_; |
| 382 base::Lock lock_; |
| 383 |
| 384 DISALLOW_COPY_AND_ASSIGN(ActivityLogState); |
| 385 }; |
| 386 |
| 387 base::LazyInstance<ActivityLogState> g_activity_log_state = |
| 388 LAZY_INSTANCE_INITIALIZER; |
| 389 |
| 390 // Calls into the ActivityLog to log an api event or function call. |
| 391 // Must be called on the UI thread. |
| 392 void LogApiActivityOnUI(content::BrowserContext* browser_context, |
| 393 const std::string& extension_id, |
| 394 const std::string& activity_name, |
| 395 std::unique_ptr<base::ListValue> args, |
| 396 Action::ActionType type) { |
| 397 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 398 ActivityLog* activity_log = ActivityLog::GetInstance(browser_context); |
| 399 if (!activity_log || !activity_log->ShouldLog(extension_id)) |
| 400 return; |
| 401 scoped_refptr<Action> action = |
| 402 new Action(extension_id, base::Time::Now(), type, activity_name); |
| 403 action->set_args(std::move(args)); |
| 404 activity_log->LogAction(action); |
| 405 } |
| 406 |
| 407 // Generic thread-safe handler for API calls and events. |
| 408 void LogApiActivity(content::BrowserContext* browser_context, |
| 409 const std::string& extension_id, |
| 410 const std::string& activity_name, |
| 411 const base::ListValue& args, |
| 412 Action::ActionType type) { |
| 413 ActivityLogState& state = g_activity_log_state.Get(); |
| 414 if (!state.IsActiveContext(browser_context) || |
| 415 state.IsWhitelistedId(extension_id)) |
| 416 return; |
| 417 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 418 BrowserThread::PostTask( |
| 419 BrowserThread::UI, FROM_HERE, |
| 420 base::Bind(&LogApiActivityOnUI, browser_context, extension_id, |
| 421 activity_name, base::Passed(args.CreateDeepCopy()), type)); |
| 422 return; |
| 423 } |
| 424 LogApiActivityOnUI(browser_context, extension_id, activity_name, |
| 425 args.CreateDeepCopy(), type); |
| 426 } |
| 427 |
| 428 // Handler for API events. Thread-safe. |
| 429 void LogApiEvent(content::BrowserContext* browser_context, |
| 430 const std::string& extension_id, |
| 431 const std::string& event_name, |
| 432 const base::ListValue& args) { |
| 433 LogApiActivity(browser_context, extension_id, event_name, args, |
| 434 Action::ACTION_API_EVENT); |
| 435 } |
| 436 |
| 437 // Handler for API function calls. Thread-safe. |
| 438 void LogApiFunction(content::BrowserContext* browser_context, |
| 439 const std::string& extension_id, |
| 440 const std::string& event_name, |
| 441 const base::ListValue& args) { |
| 442 LogApiActivity(browser_context, extension_id, event_name, args, |
| 443 Action::ACTION_API_CALL); |
| 444 } |
| 445 |
| 446 // Calls into the ActivityLog to log a webRequest usage. |
| 447 // Must be called on the UI thread. |
| 448 void LogWebRequestActivityOnUI(content::BrowserContext* browser_context, |
| 449 const std::string& extension_id, |
| 450 const GURL& url, |
| 451 bool is_incognito, |
| 452 const std::string& api_call, |
| 453 std::unique_ptr<base::DictionaryValue> details) { |
| 454 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 455 ActivityLog* activity_log = ActivityLog::GetInstance(browser_context); |
| 456 if (!activity_log || !activity_log->ShouldLog(extension_id)) |
| 457 return; |
| 458 scoped_refptr<Action> action = new Action( |
| 459 extension_id, base::Time::Now(), Action::ACTION_WEB_REQUEST, api_call); |
| 460 action->set_page_url(url); |
| 461 action->set_page_incognito(is_incognito); |
| 462 action->mutable_other()->Set(activity_log_constants::kActionWebRequest, |
| 463 std::move(details)); |
| 464 activity_log->LogAction(action); |
| 465 } |
| 466 |
| 467 // Handler for webRequest use. Thread-safe. |
| 468 void LogWebRequestActivity(content::BrowserContext* browser_context, |
| 469 const std::string& extension_id, |
| 470 const GURL& url, |
| 471 bool is_incognito, |
| 472 const std::string& api_call, |
| 473 std::unique_ptr<base::DictionaryValue> details) { |
| 474 ActivityLogState& state = g_activity_log_state.Get(); |
| 475 if (!state.IsActiveContext(browser_context) || |
| 476 state.IsWhitelistedId(extension_id)) |
| 477 return; |
| 478 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 479 BrowserThread::PostTask( |
| 480 BrowserThread::UI, FROM_HERE, |
| 481 base::Bind(&LogWebRequestActivityOnUI, browser_context, extension_id, |
| 482 url, is_incognito, api_call, base::Passed(&details))); |
| 483 return; |
| 484 } |
| 485 LogWebRequestActivityOnUI(browser_context, extension_id, url, is_incognito, |
| 486 api_call, std::move(details)); |
| 487 } |
| 488 |
| 489 void SetActivityHandlers() { |
| 490 // Set up event handlers. We don't have to worry about unsetting these, |
| 491 // because we check whether or not the activity log is active for the context |
| 492 // in the monitor methods. |
| 493 activity_monitor::Monitor current_function_monitor = |
| 494 activity_monitor::GetApiFunctionMonitor(); |
| 495 DCHECK(!current_function_monitor || |
| 496 current_function_monitor == &LogApiFunction); |
| 497 if (!current_function_monitor) |
| 498 activity_monitor::SetApiFunctionMonitor(&LogApiFunction); |
| 499 |
| 500 activity_monitor::Monitor current_event_monitor = |
| 501 activity_monitor::GetApiEventMonitor(); |
| 502 DCHECK(!current_event_monitor || current_event_monitor == &LogApiEvent); |
| 503 if (!current_function_monitor) |
| 504 activity_monitor::SetApiEventMonitor(&LogApiEvent); |
| 505 |
| 506 activity_monitor::WebRequestMonitor current_web_request_monitor = |
| 507 activity_monitor::GetWebRequestMonitor(); |
| 508 DCHECK(!current_web_request_monitor || |
| 509 current_web_request_monitor == &LogWebRequestActivity); |
| 510 if (!current_web_request_monitor) |
| 511 activity_monitor::SetWebRequestMonitor(&LogWebRequestActivity); |
| 512 } |
| 513 |
| 336 } // namespace | 514 } // namespace |
| 337 | 515 |
| 338 // SET THINGS UP. -------------------------------------------------------------- | 516 // SET THINGS UP. -------------------------------------------------------------- |
| 339 | 517 |
| 340 static base::LazyInstance<BrowserContextKeyedAPIFactory<ActivityLog> > | 518 static base::LazyInstance<BrowserContextKeyedAPIFactory<ActivityLog> > |
| 341 g_factory = LAZY_INSTANCE_INITIALIZER; | 519 g_factory = LAZY_INSTANCE_INITIALIZER; |
| 342 | 520 |
| 343 BrowserContextKeyedAPIFactory<ActivityLog>* ActivityLog::GetFactoryInstance() { | 521 BrowserContextKeyedAPIFactory<ActivityLog>* ActivityLog::GetFactoryInstance() { |
| 344 return g_factory.Pointer(); | 522 return g_factory.Pointer(); |
| 345 } | 523 } |
| 346 | 524 |
| 347 // static | 525 // static |
| 348 ActivityLog* ActivityLog::GetInstance(content::BrowserContext* context) { | 526 ActivityLog* ActivityLog::GetInstance(content::BrowserContext* context) { |
| 349 return ActivityLog::GetFactoryInstance()->Get( | 527 return ActivityLog::GetFactoryInstance()->Get( |
| 350 Profile::FromBrowserContext(context)); | 528 Profile::FromBrowserContext(context)); |
| 351 } | 529 } |
| 352 | 530 |
| 353 // Use GetInstance instead of directly creating an ActivityLog. | 531 // Use GetInstance instead of directly creating an ActivityLog. |
| 354 ActivityLog::ActivityLog(content::BrowserContext* context) | 532 ActivityLog::ActivityLog(content::BrowserContext* context) |
| 355 : database_policy_(NULL), | 533 : database_policy_(NULL), |
| 356 database_policy_type_(ActivityLogPolicy::POLICY_INVALID), | 534 database_policy_type_(ActivityLogPolicy::POLICY_INVALID), |
| 357 profile_(Profile::FromBrowserContext(context)), | 535 profile_(Profile::FromBrowserContext(context)), |
| 358 db_enabled_(false), | 536 db_enabled_(false), |
| 359 testing_mode_(false), | 537 testing_mode_(false), |
| 360 has_threads_(true), | 538 has_threads_(true), |
| 361 extension_registry_observer_(this), | 539 extension_registry_observer_(this), |
| 362 watchdog_apps_active_(0) { | 540 watchdog_apps_active_(0), |
| 541 is_active_(false) { |
| 542 SetActivityHandlers(); |
| 543 |
| 363 // This controls whether logging statements are printed & which policy is set. | 544 // This controls whether logging statements are printed & which policy is set. |
| 364 testing_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch( | 545 testing_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 365 switches::kEnableExtensionActivityLogTesting); | 546 switches::kEnableExtensionActivityLogTesting); |
| 366 | 547 |
| 367 // Check if the watchdog extension is previously installed and active. | 548 // Check if the watchdog extension is previously installed and active. |
| 368 watchdog_apps_active_ = | 549 watchdog_apps_active_ = |
| 369 profile_->GetPrefs()->GetInteger(prefs::kWatchdogExtensionActive); | 550 profile_->GetPrefs()->GetInteger(prefs::kWatchdogExtensionActive); |
| 370 | 551 |
| 371 observers_ = new base::ObserverListThreadSafe<Observer>; | 552 observers_ = new base::ObserverListThreadSafe<Observer>; |
| 372 | 553 |
| 373 // Check that the right threads exist for logging to the database. | 554 // Check that the right threads exist for logging to the database. |
| 374 // If not, we shouldn't try to do things that require them. | 555 // If not, we shouldn't try to do things that require them. |
| 375 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) || | 556 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) || |
| 376 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) || | 557 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) || |
| 377 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { | 558 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { |
| 378 has_threads_ = false; | 559 has_threads_ = false; |
| 379 } | 560 } |
| 380 | 561 |
| 381 db_enabled_ = | 562 db_enabled_ = |
| 382 has_threads_ && (base::CommandLine::ForCurrentProcess()->HasSwitch( | 563 has_threads_ && (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 383 switches::kEnableExtensionActivityLogging) || | 564 switches::kEnableExtensionActivityLogging) || |
| 384 watchdog_apps_active_); | 565 watchdog_apps_active_); |
| 385 | 566 |
| 386 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); | 567 extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); |
| 387 ChooseDatabasePolicy(); | 568 ChooseDatabasePolicy(); |
| 569 |
| 570 CheckActive(); |
| 388 } | 571 } |
| 389 | 572 |
| 390 void ActivityLog::SetDatabasePolicy( | 573 void ActivityLog::SetDatabasePolicy( |
| 391 ActivityLogPolicy::PolicyType policy_type) { | 574 ActivityLogPolicy::PolicyType policy_type) { |
| 392 if (database_policy_type_ == policy_type) | 575 if (database_policy_type_ == policy_type) |
| 393 return; | 576 return; |
| 394 if (!IsDatabaseEnabled() && !IsWatchdogAppActive()) | 577 if (!IsDatabaseEnabled() && !IsWatchdogAppActive()) |
| 395 return; | 578 return; |
| 396 | 579 |
| 397 // Deleting the old policy takes place asynchronously, on the database | 580 // Deleting the old policy takes place asynchronously, on the database |
| (...skipping 17 matching lines...) Expand all Loading... |
| 415 default: | 598 default: |
| 416 NOTREACHED(); | 599 NOTREACHED(); |
| 417 } | 600 } |
| 418 database_policy_->Init(); | 601 database_policy_->Init(); |
| 419 database_policy_type_ = policy_type; | 602 database_policy_type_ = policy_type; |
| 420 } | 603 } |
| 421 | 604 |
| 422 ActivityLog::~ActivityLog() { | 605 ActivityLog::~ActivityLog() { |
| 423 if (database_policy_) | 606 if (database_policy_) |
| 424 database_policy_->Close(); | 607 database_policy_->Close(); |
| 608 if (is_active_) |
| 609 g_activity_log_state.Get().RemoveActiveContext(profile_); |
| 425 } | 610 } |
| 426 | 611 |
| 427 // MAINTAIN STATUS. ------------------------------------------------------------ | 612 // MAINTAIN STATUS. ------------------------------------------------------------ |
| 428 | 613 |
| 429 void ActivityLog::ChooseDatabasePolicy() { | 614 void ActivityLog::ChooseDatabasePolicy() { |
| 430 if (!(IsDatabaseEnabled() || IsWatchdogAppActive())) | 615 if (!(IsDatabaseEnabled() || IsWatchdogAppActive())) |
| 431 return; | 616 return; |
| 432 if (testing_mode_) | 617 if (testing_mode_) |
| 433 SetDatabasePolicy(ActivityLogPolicy::POLICY_FULLSTREAM); | 618 SetDatabasePolicy(ActivityLogPolicy::POLICY_FULLSTREAM); |
| 434 else | 619 else |
| 435 SetDatabasePolicy(ActivityLogPolicy::POLICY_COUNTS); | 620 SetDatabasePolicy(ActivityLogPolicy::POLICY_COUNTS); |
| 436 } | 621 } |
| 437 | 622 |
| 438 bool ActivityLog::IsDatabaseEnabled() { | 623 bool ActivityLog::IsDatabaseEnabled() { |
| 439 // Make sure we are not enabled when there are no threads. | 624 // Make sure we are not enabled when there are no threads. |
| 440 DCHECK(has_threads_ || !db_enabled_); | 625 DCHECK(has_threads_ || !db_enabled_); |
| 441 return db_enabled_; | 626 return db_enabled_; |
| 442 } | 627 } |
| 443 | 628 |
| 444 bool ActivityLog::IsWatchdogAppActive() { | 629 bool ActivityLog::IsWatchdogAppActive() { |
| 445 return (watchdog_apps_active_ > 0); | 630 return (watchdog_apps_active_ > 0); |
| 446 } | 631 } |
| 447 | 632 |
| 448 void ActivityLog::SetWatchdogAppActiveForTesting(bool active) { | 633 void ActivityLog::SetWatchdogAppActiveForTesting(bool active) { |
| 449 watchdog_apps_active_ = active ? 1 : 0; | 634 watchdog_apps_active_ = active ? 1 : 0; |
| 635 CheckActive(); |
| 450 } | 636 } |
| 451 | 637 |
| 452 void ActivityLog::OnExtensionLoaded(content::BrowserContext* browser_context, | 638 void ActivityLog::OnExtensionLoaded(content::BrowserContext* browser_context, |
| 453 const Extension* extension) { | 639 const Extension* extension) { |
| 454 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) return; | 640 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) |
| 641 return; |
| 455 if (has_threads_) | 642 if (has_threads_) |
| 456 db_enabled_ = true; | 643 db_enabled_ = true; |
| 644 g_activity_log_state.Get().AddWhitelistedId(extension->id()); |
| 457 watchdog_apps_active_++; | 645 watchdog_apps_active_++; |
| 458 profile_->GetPrefs()->SetInteger(prefs::kWatchdogExtensionActive, | 646 profile_->GetPrefs()->SetInteger(prefs::kWatchdogExtensionActive, |
| 459 watchdog_apps_active_); | 647 watchdog_apps_active_); |
| 460 if (watchdog_apps_active_ == 1) | 648 if (watchdog_apps_active_ == 1) |
| 461 ChooseDatabasePolicy(); | 649 ChooseDatabasePolicy(); |
| 650 |
| 651 if (!is_active_) |
| 652 CheckActive(); |
| 462 } | 653 } |
| 463 | 654 |
| 464 void ActivityLog::OnExtensionUnloaded(content::BrowserContext* browser_context, | 655 void ActivityLog::OnExtensionUnloaded(content::BrowserContext* browser_context, |
| 465 const Extension* extension, | 656 const Extension* extension, |
| 466 UnloadedExtensionInfo::Reason reason) { | 657 UnloadedExtensionInfo::Reason reason) { |
| 467 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) return; | 658 if (!ActivityLogAPI::IsExtensionWhitelisted(extension->id())) |
| 659 return; |
| 468 watchdog_apps_active_--; | 660 watchdog_apps_active_--; |
| 469 profile_->GetPrefs()->SetInteger(prefs::kWatchdogExtensionActive, | 661 profile_->GetPrefs()->SetInteger(prefs::kWatchdogExtensionActive, |
| 470 watchdog_apps_active_); | 662 watchdog_apps_active_); |
| 471 if (watchdog_apps_active_ == 0 && | 663 if (watchdog_apps_active_ == 0 && |
| 472 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 664 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 473 switches::kEnableExtensionActivityLogging)) { | 665 switches::kEnableExtensionActivityLogging)) { |
| 474 db_enabled_ = false; | 666 db_enabled_ = false; |
| 475 } | 667 } |
| 668 |
| 669 if (is_active_) |
| 670 CheckActive(); |
| 476 } | 671 } |
| 477 | 672 |
| 478 // OnExtensionUnloaded will also be called right before this. | 673 // OnExtensionUnloaded will also be called right before this. |
| 479 void ActivityLog::OnExtensionUninstalled( | 674 void ActivityLog::OnExtensionUninstalled( |
| 480 content::BrowserContext* browser_context, | 675 content::BrowserContext* browser_context, |
| 481 const Extension* extension, | 676 const Extension* extension, |
| 482 extensions::UninstallReason reason) { | 677 extensions::UninstallReason reason) { |
| 483 if (ActivityLogAPI::IsExtensionWhitelisted(extension->id()) && | 678 if (ActivityLogAPI::IsExtensionWhitelisted(extension->id()) && |
| 484 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 679 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 485 switches::kEnableExtensionActivityLogging) && | 680 switches::kEnableExtensionActivityLogging) && |
| (...skipping 14 matching lines...) Expand all Loading... |
| 500 | 695 |
| 501 // static | 696 // static |
| 502 void ActivityLog::RegisterProfilePrefs( | 697 void ActivityLog::RegisterProfilePrefs( |
| 503 user_prefs::PrefRegistrySyncable* registry) { | 698 user_prefs::PrefRegistrySyncable* registry) { |
| 504 registry->RegisterIntegerPref(prefs::kWatchdogExtensionActive, false); | 699 registry->RegisterIntegerPref(prefs::kWatchdogExtensionActive, false); |
| 505 } | 700 } |
| 506 | 701 |
| 507 // LOG ACTIONS. ---------------------------------------------------------------- | 702 // LOG ACTIONS. ---------------------------------------------------------------- |
| 508 | 703 |
| 509 void ActivityLog::LogAction(scoped_refptr<Action> action) { | 704 void ActivityLog::LogAction(scoped_refptr<Action> action) { |
| 510 if (ActivityLogAPI::IsExtensionWhitelisted(action->extension_id())) | 705 DCHECK(ShouldLog(action->extension_id())); |
| 511 return; | |
| 512 | 706 |
| 513 // Perform some preprocessing of the Action data: convert tab IDs to URLs and | 707 // Perform some preprocessing of the Action data: convert tab IDs to URLs and |
| 514 // mask out incognito URLs if appropriate. | 708 // mask out incognito URLs if appropriate. |
| 515 ExtractUrls(action, profile_); | 709 ExtractUrls(action, profile_); |
| 516 | 710 |
| 517 // Mark DOM XHR requests as such, for easier processing later. | 711 // Mark DOM XHR requests as such, for easier processing later. |
| 518 if (action->action_type() == Action::ACTION_DOM_ACCESS && | 712 if (action->action_type() == Action::ACTION_DOM_ACCESS && |
| 519 base::StartsWith(action->api_name(), kDomXhrPrefix, | 713 base::StartsWith(action->api_name(), kDomXhrPrefix, |
| 520 base::CompareCase::SENSITIVE) && | 714 base::CompareCase::SENSITIVE) && |
| 521 action->other()) { | 715 action->other()) { |
| 522 base::DictionaryValue* other = action->mutable_other(); | 716 base::DictionaryValue* other = action->mutable_other(); |
| 523 int dom_verb = -1; | 717 int dom_verb = -1; |
| 524 if (other->GetInteger(constants::kActionDomVerb, &dom_verb) && | 718 if (other->GetInteger(constants::kActionDomVerb, &dom_verb) && |
| 525 dom_verb == DomActionType::METHOD) { | 719 dom_verb == DomActionType::METHOD) { |
| 526 other->SetInteger(constants::kActionDomVerb, DomActionType::XHR); | 720 other->SetInteger(constants::kActionDomVerb, DomActionType::XHR); |
| 527 } | 721 } |
| 528 } | 722 } |
| 529 | 723 |
| 530 if (IsDatabaseEnabled() && database_policy_) | 724 if (IsDatabaseEnabled() && database_policy_) |
| 531 database_policy_->ProcessAction(action); | 725 database_policy_->ProcessAction(action); |
| 532 if (IsWatchdogAppActive()) | 726 if (IsWatchdogAppActive()) |
| 533 observers_->Notify(FROM_HERE, &Observer::OnExtensionActivity, action); | 727 observers_->Notify(FROM_HERE, &Observer::OnExtensionActivity, action); |
| 534 if (testing_mode_) | 728 if (testing_mode_) |
| 535 VLOG(1) << action->PrintForDebug(); | 729 VLOG(1) << action->PrintForDebug(); |
| 536 } | 730 } |
| 537 | 731 |
| 732 bool ActivityLog::ShouldLog(const std::string& extension_id) const { |
| 733 return is_active_ && !ActivityLogAPI::IsExtensionWhitelisted(extension_id); |
| 734 } |
| 735 |
| 538 void ActivityLog::OnScriptsExecuted( | 736 void ActivityLog::OnScriptsExecuted( |
| 539 const content::WebContents* web_contents, | 737 const content::WebContents* web_contents, |
| 540 const ExecutingScriptsMap& extension_ids, | 738 const ExecutingScriptsMap& extension_ids, |
| 541 const GURL& on_url) { | 739 const GURL& on_url) { |
| 542 Profile* profile = | 740 if (!is_active_) |
| 543 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 741 return; |
| 544 ExtensionRegistry* registry = ExtensionRegistry::Get(profile); | 742 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); |
| 545 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin(); | 743 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin(); |
| 546 it != extension_ids.end(); ++it) { | 744 it != extension_ids.end(); ++it) { |
| 547 const Extension* extension = | 745 const Extension* extension = |
| 548 registry->GetExtensionById(it->first, ExtensionRegistry::ENABLED); | 746 registry->GetExtensionById(it->first, ExtensionRegistry::ENABLED); |
| 549 if (!extension || ActivityLogAPI::IsExtensionWhitelisted(extension->id())) | 747 if (!extension || ActivityLogAPI::IsExtensionWhitelisted(extension->id())) |
| 550 continue; | 748 continue; |
| 551 | 749 |
| 552 // If OnScriptsExecuted is fired because of tabs.executeScript, the list | 750 // If OnScriptsExecuted is fired because of tabs.executeScript, the list |
| 553 // of content scripts will be empty. We don't want to log it because | 751 // of content scripts will be empty. We don't want to log it because |
| 554 // the call to tabs.executeScript will have already been logged anyway. | 752 // the call to tabs.executeScript will have already been logged anyway. |
| 555 if (!it->second.empty()) { | 753 if (!it->second.empty()) { |
| 556 scoped_refptr<Action> action; | 754 scoped_refptr<Action> action; |
| 557 action = new Action(extension->id(), | 755 action = new Action(extension->id(), |
| 558 base::Time::Now(), | 756 base::Time::Now(), |
| 559 Action::ACTION_CONTENT_SCRIPT, | 757 Action::ACTION_CONTENT_SCRIPT, |
| 560 ""); // no API call here | 758 ""); // no API call here |
| 561 action->set_page_url(on_url); | 759 action->set_page_url(on_url); |
| 562 action->set_page_title(base::UTF16ToUTF8(web_contents->GetTitle())); | 760 action->set_page_title(base::UTF16ToUTF8(web_contents->GetTitle())); |
| 563 action->set_page_incognito( | 761 action->set_page_incognito( |
| 564 web_contents->GetBrowserContext()->IsOffTheRecord()); | 762 web_contents->GetBrowserContext()->IsOffTheRecord()); |
| 565 | 763 |
| 566 const prerender::PrerenderManager* prerender_manager = | 764 const prerender::PrerenderManager* prerender_manager = |
| 567 prerender::PrerenderManagerFactory::GetForProfile(profile); | 765 prerender::PrerenderManagerFactory::GetForProfile(profile_); |
| 568 if (prerender_manager && | 766 if (prerender_manager && |
| 569 prerender_manager->IsWebContentsPrerendering(web_contents, NULL)) | 767 prerender_manager->IsWebContentsPrerendering(web_contents, NULL)) |
| 570 action->mutable_other()->SetBoolean(constants::kActionPrerender, true); | 768 action->mutable_other()->SetBoolean(constants::kActionPrerender, true); |
| 571 for (std::set<std::string>::const_iterator it2 = it->second.begin(); | 769 for (std::set<std::string>::const_iterator it2 = it->second.begin(); |
| 572 it2 != it->second.end(); | 770 it2 != it->second.end(); |
| 573 ++it2) { | 771 ++it2) { |
| 574 action->mutable_args()->AppendString(*it2); | 772 action->mutable_args()->AppendString(*it2); |
| 575 } | 773 } |
| 576 LogAction(action); | 774 LogAction(action); |
| 577 } | 775 } |
| 578 } | 776 } |
| 579 } | 777 } |
| 580 | 778 |
| 581 void ActivityLog::OnApiEventDispatched( | |
| 582 const std::string& extension_id, | |
| 583 const std::string& event_name, | |
| 584 std::unique_ptr<base::ListValue> event_args) { | |
| 585 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 586 scoped_refptr<Action> action = new Action(extension_id, | |
| 587 base::Time::Now(), | |
| 588 Action::ACTION_API_EVENT, | |
| 589 event_name); | |
| 590 action->set_args(std::move(event_args)); | |
| 591 LogAction(action); | |
| 592 } | |
| 593 | |
| 594 void ActivityLog::OnApiFunctionCalled(const std::string& extension_id, | |
| 595 const std::string& api_name, | |
| 596 std::unique_ptr<base::ListValue> args) { | |
| 597 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 598 scoped_refptr<Action> action = new Action(extension_id, | |
| 599 base::Time::Now(), | |
| 600 Action::ACTION_API_CALL, | |
| 601 api_name); | |
| 602 action->set_args(std::move(args)); | |
| 603 LogAction(action); | |
| 604 } | |
| 605 | |
| 606 // LOOKUP ACTIONS. ------------------------------------------------------------- | 779 // LOOKUP ACTIONS. ------------------------------------------------------------- |
| 607 | 780 |
| 608 void ActivityLog::GetFilteredActions( | 781 void ActivityLog::GetFilteredActions( |
| 609 const std::string& extension_id, | 782 const std::string& extension_id, |
| 610 const Action::ActionType type, | 783 const Action::ActionType type, |
| 611 const std::string& api_name, | 784 const std::string& api_name, |
| 612 const std::string& page_url, | 785 const std::string& page_url, |
| 613 const std::string& arg_url, | 786 const std::string& arg_url, |
| 614 const int daysAgo, | 787 const int daysAgo, |
| 615 const base::Callback< | 788 const base::Callback< |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 urls.push_back(url); | 826 urls.push_back(url); |
| 654 RemoveURLs(urls); | 827 RemoveURLs(urls); |
| 655 } | 828 } |
| 656 | 829 |
| 657 void ActivityLog::DeleteDatabase() { | 830 void ActivityLog::DeleteDatabase() { |
| 658 if (!database_policy_) | 831 if (!database_policy_) |
| 659 return; | 832 return; |
| 660 database_policy_->DeleteDatabase(); | 833 database_policy_->DeleteDatabase(); |
| 661 } | 834 } |
| 662 | 835 |
| 836 void ActivityLog::CheckActive() { |
| 837 bool has_db = db_enabled_ && database_policy_; |
| 838 ActivityLogState& state = g_activity_log_state.Get(); |
| 839 content::BrowserContext* off_the_record = |
| 840 profile_->HasOffTheRecordProfile() ? profile_->GetOffTheRecordProfile() |
| 841 : nullptr; |
| 842 if (has_db || IsWatchdogAppActive()) { |
| 843 if (is_active_) |
| 844 return; // Already enabled. |
| 845 state.AddActiveContext(profile_); |
| 846 if (off_the_record) |
| 847 state.AddActiveContext(off_the_record); |
| 848 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
| 849 content::NotificationService::AllSources()); |
| 850 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 851 content::NotificationService::AllSources()); |
| 852 is_active_ = true; |
| 853 } else if (is_active_) { |
| 854 state.RemoveActiveContext(profile_); |
| 855 if (off_the_record) |
| 856 state.RemoveActiveContext(off_the_record); |
| 857 registrar_.RemoveAll(); |
| 858 is_active_ = false; |
| 859 } |
| 860 } |
| 861 |
| 862 void ActivityLog::Observe(int type, |
| 863 const content::NotificationSource& source, |
| 864 const content::NotificationDetails& details) { |
| 865 DCHECK(is_active_); |
| 866 switch (type) { |
| 867 case chrome::NOTIFICATION_PROFILE_CREATED: { |
| 868 Profile* profile = content::Source<Profile>(source).ptr(); |
| 869 if (profile_->IsSameProfile(profile)) |
| 870 g_activity_log_state.Get().AddActiveContext(profile); |
| 871 break; |
| 872 } |
| 873 case chrome::NOTIFICATION_PROFILE_DESTROYED: { |
| 874 Profile* profile = content::Source<Profile>(source).ptr(); |
| 875 if (profile_->IsSameProfile(profile)) |
| 876 g_activity_log_state.Get().RemoveActiveContext(profile); |
| 877 break; |
| 878 } |
| 879 default: |
| 880 NOTREACHED(); |
| 881 } |
| 882 } |
| 883 |
| 663 template <> | 884 template <> |
| 664 void BrowserContextKeyedAPIFactory<ActivityLog>::DeclareFactoryDependencies() { | 885 void BrowserContextKeyedAPIFactory<ActivityLog>::DeclareFactoryDependencies() { |
| 665 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); | 886 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory()); |
| 666 DependsOn(ExtensionRegistryFactory::GetInstance()); | 887 DependsOn(ExtensionRegistryFactory::GetInstance()); |
| 667 } | 888 } |
| 668 | 889 |
| 669 } // namespace extensions | 890 } // namespace extensions |
| OLD | NEW |