15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/extensions/activity_log/activity_log.h"
6a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <set>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector>
9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_string_value_serializer.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
14558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/strings/utf_string_conversions.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_checker.h"
16558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/extensions/activity_log/activity_action_constants.h"
174311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch#include "chrome/browser/extensions/activity_log/counting_policy.h"
184311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch#include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_system_factory.h"
23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/extensions/extension_tab_util.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/install_tracker_factory.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/prerender/prerender_manager.h"
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/prerender/prerender_manager_factory.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/profiles/incognito_helpers.h"
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_constants.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h"
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/re2/re2/re2.h"
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
37558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochnamespace constants = activity_log_constants;
38558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Concatenate arguments.
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstd::string MakeArgList(const base::ListValue* args) {
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string call_signature;
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ListValue::const_iterator it = args->begin();
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (; it != args->end(); ++it) {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string arg;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    JSONStringValueSerializer serializer(&arg);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (serializer.SerializeAndOmitBinaryValues(**it)) {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != args->begin())
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        call_signature += ", ";
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      call_signature += arg;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return call_signature;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// This is a hack for AL callers who don't have access to a profile object
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// when deciding whether or not to do the work required for logging. The state
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// is accessed through the static ActivityLog::IsLogEnabledOnAnyProfile()
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// method. It returns true if --enable-extension-activity-logging is set on the
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// command line OR *ANY* profile has the activity log whitelisted extension
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// installed.
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class LogIsEnabled {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  LogIsEnabled() : any_profile_enabled_(false) {
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ComputeIsFlagEnabled();
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void ComputeIsFlagEnabled() {
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::AutoLock auto_lock(lock_);
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    cmd_line_enabled_ = CommandLine::ForCurrentProcess()->
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        HasSwitch(switches::kEnableExtensionActivityLogging);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static LogIsEnabled* GetInstance() {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return Singleton<LogIsEnabled>::get();
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool IsEnabled() {
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::AutoLock auto_lock(lock_);
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return cmd_line_enabled_ || any_profile_enabled_;
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void SetProfileEnabled(bool any_profile_enabled) {
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::AutoLock auto_lock(lock_);
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    any_profile_enabled_ = any_profile_enabled;
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::Lock lock_;
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool any_profile_enabled_;
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool cmd_line_enabled_;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Gets the URL for a given tab ID.  Helper method for LookupTabId.  Returns
96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// true if able to perform the lookup.  The URL is stored to *url, and
97a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// *is_incognito is set to indicate whether the URL is for an incognito tab.
98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool GetUrlForTabId(int tab_id,
99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                    Profile* profile,
100a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                    GURL* url,
101a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                    bool* is_incognito) {
102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  content::WebContents* contents = NULL;
103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Browser* browser = NULL;
104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool found = ExtensionTabUtil::GetTabById(tab_id,
105a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                            profile,
106a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                            true,  // search incognito tabs too
107a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                            &browser,
108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                            NULL,
109a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                            &contents,
110a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                            NULL);
111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (found) {
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    *url = contents->GetURL();
113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    *is_incognito = browser->profile()->IsOffTheRecord();
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return true;
115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return false;
117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
119a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Translate tab IDs to URLs in tabs API calls.  Mutates the Action object in
121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// place.  There is a small chance that the URL translation could be wrong, if
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// the tab has already been navigated by the time of invocation.
123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)//
124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// If a single tab ID is translated to a URL, the URL is stored into arg_url
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// where it can more easily be searched for in the database.  For APIs that
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// take a list of tab IDs, replace each tab ID with the URL in the argument
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// list; we can only extract a single URL into arg_url so arbitrarily pull out
128a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// the first one.
129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void LookupTabIds(scoped_refptr<extensions::Action> action, Profile* profile) {
130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  const std::string& api_call = action->api_name();
131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (api_call == "tabs.get" ||                 // api calls, ID as int
132a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.connect" ||
133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.sendMessage" ||
134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.duplicate" ||
135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.update" ||
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.reload" ||
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.detectLanguage" ||
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.executeScript" ||
139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.insertCSS" ||
140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.move" ||                // api calls, IDs in array
141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.remove" ||
142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.onUpdated" ||           // events, ID as int
143a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.onMoved" ||
144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.onDetached" ||
145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.onAttached" ||
146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.onRemoved" ||
147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      api_call == "tabs.onReplaced") {
148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    int tab_id;
149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    base::ListValue* id_list;
150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    base::ListValue* args = action->mutable_args();
151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (args->GetInteger(0, &tab_id)) {
152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // Single tab ID to translate.
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      GURL url;
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      bool is_incognito;
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      if (GetUrlForTabId(tab_id, profile, &url, &is_incognito)) {
156a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        action->set_arg_url(url);
157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        action->set_arg_incognito(is_incognito);
158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      }
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    } else if ((api_call == "tabs.move" || api_call == "tabs.remove") &&
160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)               args->GetList(0, &id_list)) {
161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      // Array of tab IDs to translate.
162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      for (int i = 0; i < static_cast<int>(id_list->GetSize()); ++i) {
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        if (id_list->GetInteger(i, &tab_id)) {
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          GURL url;
165a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          bool is_incognito;
166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          if (GetUrlForTabId(tab_id, profile, &url, &is_incognito) &&
167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              !is_incognito) {
168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            id_list->Set(i, new base::StringValue(url.spec()));
169a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            if (i == 0) {
170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              action->set_arg_url(url);
171a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              action->set_arg_incognito(is_incognito);
172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            }
173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          }
174a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        } else {
175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          LOG(ERROR) << "The tab ID array is malformed at index " << i;
176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        }
177a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      }
178a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
179a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
180a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
181a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ActivityLog::IsLogEnabledOnAnyProfile() {
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return LogIsEnabled::GetInstance()->IsEnabled();
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ActivityLog::RecomputeLoggingIsEnabled(bool profile_enabled) {
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  LogIsEnabled::GetInstance()->ComputeIsFlagEnabled();
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  LogIsEnabled::GetInstance()->SetProfileEnabled(profile_enabled);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ActivityLogFactory
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ActivityLogFactory* ActivityLogFactory::GetInstance() {
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Singleton<ActivityLogFactory>::get();
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)BrowserContextKeyedService* ActivityLogFactory::BuildServiceInstanceFor(
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    content::BrowserContext* profile) const {
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return new ActivityLog(static_cast<Profile*>(profile));
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)content::BrowserContext* ActivityLogFactory::GetBrowserContextToUse(
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    content::BrowserContext* context) const {
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return chrome::GetBrowserContextRedirectedInIncognito(context);
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ActivityLogFactory::ActivityLogFactory()
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : BrowserContextKeyedServiceFactory(
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        "ActivityLog",
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        BrowserContextDependencyManager::GetInstance()) {
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DependsOn(ExtensionSystemFactory::GetInstance());
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DependsOn(InstallTrackerFactory::GetInstance());
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ActivityLogFactory::~ActivityLogFactory() {
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ActivityLog
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void ActivityLog::SetDefaultPolicy(ActivityLogPolicy::PolicyType policy_type) {
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Can't use IsLogEnabled() here because this is called from inside Init.
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (policy_type != policy_type_ && enabled_) {
2297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Deleting the old policy takes place asynchronously, on the database
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // thread.  Initializing a new policy below similarly happens
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // asynchronously.  Since the two operations are both queued for the
2327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // database, the queue ordering should ensure that the deletion completes
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // before database initialization occurs.
2347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    //
2357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // However, changing policies at runtime is still not recommended, and
2367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // likely only should be done for unit tests.
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (policy_)
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      policy_->Close();
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    switch (policy_type) {
2417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      case ActivityLogPolicy::POLICY_FULLSTREAM:
2427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        policy_ = new FullStreamUIPolicy(profile_);
2437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        break;
2444311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      case ActivityLogPolicy::POLICY_COUNTS:
2454311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch        policy_ = new CountingPolicy(profile_);
2467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        break;
2477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      default:
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        NOTREACHED();
2497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
2507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    policy_type_ = policy_type;
2517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use GetInstance instead of directly creating an ActivityLog.
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)ActivityLog::ActivityLog(Profile* profile)
2567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : policy_(NULL),
2577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      policy_type_(ActivityLogPolicy::POLICY_INVALID),
2587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      profile_(profile),
2597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      enabled_(false),
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      initialized_(false),
2617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      policy_chosen_(false),
2627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      testing_mode_(false),
2637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      has_threads_(true),
2647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      tracker_(NULL) {
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This controls whether logging statements are printed, which policy is set,
2667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // etc.
2677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  testing_mode_ = CommandLine::ForCurrentProcess()->HasSwitch(
2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    switches::kEnableExtensionActivityLogTesting);
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Check that the right threads exist. If not, we shouldn't try to do things
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // that require them.
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) ||
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) ||
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LOG(ERROR) << "Missing threads, disabling Activity Logging!";
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    has_threads_ = false;
2777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  } else {
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    enabled_ = IsLogEnabledOnAnyProfile();
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ExtensionSystem::Get(profile_)->ready().Post(
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      FROM_HERE, base::Bind(&ActivityLog::Init, base::Unretained(this)));
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  observers_ = new ObserverListThreadSafe<Observer>;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ActivityLog::Init() {
2877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(has_threads_);
2887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(!initialized_);
2897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const Extension* whitelisted_extension = ExtensionSystem::Get(profile_)->
2907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      extension_service()->GetExtensionById(kActivityLogExtensionId, false);
2917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (whitelisted_extension) {
2927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    enabled_ = true;
2937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    LogIsEnabled::GetInstance()->SetProfileEnabled(true);
2947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  tracker_ = InstallTrackerFactory::GetForProfile(profile_);
2967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  tracker_->AddObserver(this);
2977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ChooseDefaultPolicy();
2987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  initialized_ = true;
2997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ActivityLog::ChooseDefaultPolicy() {
3027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (policy_chosen_ || !enabled_) return;
3037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (testing_mode_)
3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    SetDefaultPolicy(ActivityLogPolicy::POLICY_FULLSTREAM);
3057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  else
3064311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    SetDefaultPolicy(ActivityLogPolicy::POLICY_COUNTS);
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ActivityLog::Shutdown() {
3107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (tracker_) tracker_->RemoveObserver(this);
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ActivityLog::~ActivityLog() {
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (policy_)
3157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    policy_->Close();
316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ActivityLog::IsLogEnabled() {
3197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!has_threads_ || !initialized_) return false;
320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return enabled_;
321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ActivityLog::OnExtensionLoaded(const Extension* extension) {
324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (extension->id() != kActivityLogExtensionId) return;
325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  enabled_ = true;
326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  LogIsEnabled::GetInstance()->SetProfileEnabled(true);
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ChooseDefaultPolicy();
328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ActivityLog::OnExtensionUnloaded(const Extension* extension) {
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (extension->id() != kActivityLogExtensionId) return;
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!CommandLine::ForCurrentProcess()->HasSwitch(
333868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      switches::kEnableExtensionActivityLogging))
334868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    enabled_ = false;
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ActivityLog* ActivityLog::GetInstance(Profile* profile) {
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ActivityLogFactory::GetForProfile(profile);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ActivityLog::AddObserver(ActivityLog::Observer* observer) {
343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  observers_->AddObserver(observer);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ActivityLog::RemoveObserver(ActivityLog::Observer* observer) {
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  observers_->RemoveObserver(observer);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
350558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid ActivityLog::LogAction(scoped_refptr<Action> action) {
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!IsLogEnabled() ||
352a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      ActivityLogAPI::IsExtensionWhitelisted(action->extension_id()))
353a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
354a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
355a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Perform some preprocessing of the Action data: convert tab IDs to URLs and
356a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // mask out incognito URLs if appropriate.
357a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if ((action->action_type() == Action::ACTION_API_CALL ||
358a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       action->action_type() == Action::ACTION_API_EVENT) &&
359a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      StartsWithASCII(action->api_name(), "tabs.", true)) {
360a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    LookupTabIds(action, profile_);
3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
363a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // TODO(mvrable): Add any necessary processing of incognito URLs here, for
364a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // crbug.com/253368
3657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
366a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (policy_)
367a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    policy_->ProcessAction(action);
368a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  observers_->Notify(&Observer::OnExtensionActivity, action);
369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (testing_mode_)
370a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    LOG(INFO) << action->PrintForDebug();
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ActivityLog::GetActions(
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& extension_id,
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const int day,
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Callback
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>& callback) {
3787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (policy_) {
3797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    policy_->ReadData(extension_id, day, callback);
3807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ActivityLog::OnScriptsExecuted(
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::WebContents* web_contents,
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ExecutingScriptsMap& extension_ids,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int32 on_page_id,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& on_url) {
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!IsLogEnabled()) return;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile =
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Profile::FromBrowserContext(web_contents->GetBrowserContext());
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ExtensionService* extension_service =
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ExtensionSystem::Get(profile)->extension_service();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ExtensionSet* extensions = extension_service->extensions();
394868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const prerender::PrerenderManager* prerender_manager =
395868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      prerender::PrerenderManagerFactory::GetForProfile(
396868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          Profile::FromBrowserContext(web_contents->GetBrowserContext()));
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ExecutingScriptsMap::const_iterator it = extension_ids.begin();
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != extension_ids.end(); ++it) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Extension* extension = extensions->GetByID(it->first);
401868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!extension || ActivityLogAPI::IsExtensionWhitelisted(extension->id()))
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If OnScriptsExecuted is fired because of tabs.executeScript, the list
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // of content scripts will be empty.  We don't want to log it because
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the call to tabs.executeScript will have already been logged anyway.
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!it->second.empty()) {
408a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      scoped_refptr<Action> action;
409a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      action = new Action(extension->id(),
410a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                          base::Time::Now(),
411a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                          Action::ACTION_CONTENT_SCRIPT,
412a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                          "");  // no API call here
413a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      action->set_page_url(on_url);
414a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      action->set_page_title(base::UTF16ToUTF8(web_contents->GetTitle()));
415a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      action->set_page_incognito(
416a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          web_contents->GetBrowserContext()->IsOffTheRecord());
417a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      if (prerender_manager &&
418a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          prerender_manager->IsWebContentsPrerendering(web_contents, NULL))
419a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        action->mutable_other()->SetBoolean(constants::kActionPrerender, true);
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (std::set<std::string>::const_iterator it2 = it->second.begin();
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)           it2 != it->second.end();
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)           ++it2) {
423a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        action->mutable_args()->AppendString(*it2);
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
425a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      LogAction(action);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
431