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 |