summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/activity_log/activity_log.h
blob: b934d97e3ee82d31ebf71258f2a37eb638ecac00 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_H_
#define CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_H_

#include <map>
#include <string>
#include <vector>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/hash_tables.h"
#include "base/memory/singleton.h"
#include "base/observer_list_threadsafe.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "chrome/browser/extensions/activity_log/activity_actions.h"
#include "chrome/browser/extensions/activity_log/activity_database.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
#include "content/public/browser/browser_thread.h"

class Profile;
using content::BrowserThread;

namespace extensions {
class Extension;

// A utility for tracing interesting activity for each extension.
// It writes to an ActivityDatabase on a separate thread to record the activity.
class ActivityLog : public ProfileKeyedService,
                    public TabHelper::ScriptExecutionObserver {
 public:
  enum Activity {
    ACTIVITY_EXTENSION_API_CALL,   // Extension API invocation is called.
    ACTIVITY_EXTENSION_API_BLOCK,  // Extension API invocation is blocked.
    ACTIVITY_CONTENT_SCRIPT,       // Content script is executing.
    ACTIVITY_EVENT_DISPATCH,       // Event sent to listener in extension.
  };

  // Observers can listen for activity events.
  class Observer {
   public:
    virtual void OnExtensionActivity(
        const Extension* extension,
        Activity activity,
        const std::string& message) = 0;
  };

  // ActivityLog is a singleton, so don't instantiate it with the constructor;
  // use GetInstance instead.
  static ActivityLog* GetInstance(Profile* profile);

  // Currently, we only want to record actions if the user has opted in to the
  // ActivityLog feature.
  static bool IsLogEnabled();

  // Recompute whether logging should be enabled (the value of IsLogEnabled is
  // normally cached).  WARNING: This may not be thread-safe, and is only
  // really intended for use by unit tests.
  static void RecomputeLoggingIsEnabled();

  // Add/remove observer.
  void AddObserver(const Extension* extension, Observer* observer);
  void RemoveObserver(const Extension* extension,
                      Observer* observer);

  // Check for the existence observer list by extension_id.
  bool HasObservers(const Extension* extension) const;

  // Log a successful API call made by an extension.
  // This will create an APIAction for storage in the database.
  // (Note: implemented as a wrapper for LogAPIActionInternal.)
  void LogAPIAction(const Extension* extension,
                    const std::string& name,    // e.g., tabs.get
                    ListValue* args,            // the argument values e.g. 46
                    const std::string& extra);  // any extra logging info

  // Log an event notification delivered to an extension.
  // This will create an APIAction for storage in the database.
  // (Note: implemented as a wrapper for LogAPIActionInternal.)
  void LogEventAction(const Extension* extension,
                      const std::string& name,    // e.g., tabs.onUpdate
                      ListValue* args,            // arguments to the callback
                      const std::string& extra);  // any extra logging info

  // Log a blocked API call made by an extension.
  // This will create a BlockedAction for storage in the database.
  void LogBlockedAction(const Extension* extension,
                        const std::string& blocked_call,  // e.g., tabs.get
                        ListValue* args,                  // argument values
                        const BlockedAction::Reason reason,  // why it's blocked
                        const std::string& extra);        // extra logging info

  // Log an interaction between an extension and a URL.
  // This will create a DOMAction for storage in the database.
  // The technical message might be the list of content scripts that have been
  // injected, or the DOM API call; it's what's shown under "More".
  void LogDOMAction(const Extension* extension,
                    const GURL& url,                      // target URL
                    const string16& url_title,            // title of the URL
                    const std::string& api_call,          // api call
                    const ListValue* args,                // arguments
                    const std::string& extra);            // extra logging info

  // Log a use of the WebRequest API to redirect, cancel, or modify page
  // headers.
  void LogWebRequestAction(const Extension* extension,
                           const GURL& url,
                           const std::string& api_call,
                           scoped_ptr<base::DictionaryValue> details,
                           const std::string& extra);

  // Retrieves the list of actions for a given extension on a specific day.
  // Today is 0, yesterday is 1, etc. Returns one day at a time.
  // Response is sent to the method/function in the callback.
  // Use base::Bind to create the callback.
  void GetActions(const std::string& extension_id,
                  const int day,
                  const base::Callback
                      <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>&
                      callback);

  // An error has happened; we want to rollback and close the db.
  // Needs to be public so the error delegate can call it.
  void KillActivityLogDatabase();

  // For unit tests only.
  void SetArgumentLoggingForTesting(bool log_arguments);

 private:
  friend class ActivityLogFactory;

  explicit ActivityLog(Profile* profile);
  virtual ~ActivityLog();

  // We log callbacks and API calls very similarly, so we handle them the same
  // way internally.
  void LogAPIActionInternal(
      const Extension* extension,
      const std::string& api_call,
      ListValue* args,
      const std::string& extra,
      const APIAction::Type type);

  // We log content script injection and DOM API calls using the same underlying
  // mechanism, so they have the same internal logging structure.
  void LogDOMActionInternal(const Extension* extension,
                            const GURL& url,
                            const string16& url_title,
                            const std::string& api_call,
                            const ListValue* args,
                            const std::string& extra,
                            DOMAction::DOMActionType verb);

  // TabHelper::ScriptExecutionObserver implementation.
  // Fires when a ContentScript is executed.
  virtual void OnScriptsExecuted(
      const content::WebContents* web_contents,
      const ExecutingScriptsMap& extension_ids,
      int32 page_id,
      const GURL& on_url) OVERRIDE;

  // The callback when initializing the database.
  void OnDBInitComplete();

  static const char* ActivityToString(Activity activity);

  // The Schedule methods dispatch the calls to the database on a
  // separate thread. We dispatch to the UI thread if the DB thread doesn't
  // exist, which should only happen in tests where there is no DB thread.
  template<typename DatabaseFunc>
  void ScheduleAndForget(DatabaseFunc func) {
    BrowserThread::PostTask(dispatch_thread_,
                            FROM_HERE,
                            base::Bind(func, base::Unretained(db_)));
  }

  template<typename DatabaseFunc, typename ArgA>
  void ScheduleAndForget(DatabaseFunc func, ArgA a) {
    BrowserThread::PostTask(dispatch_thread_,
                            FROM_HERE,
                            base::Bind(func, base::Unretained(db_), a));
  }

  template<typename DatabaseFunc, typename ArgA, typename ArgB>
  void ScheduleAndForget(DatabaseFunc func, ArgA a, ArgB b) {
    BrowserThread::PostTask(dispatch_thread_,
                            FROM_HERE,
                            base::Bind(func, base::Unretained(db_), a, b));
  }

  typedef ObserverListThreadSafe<Observer> ObserverList;
  typedef std::map<const Extension*, scoped_refptr<ObserverList> >
      ObserverMap;
  // A map of extensions to activity observers for that extension.
  ObserverMap observers_;

  // The database wrapper that does the actual database I/O.
  // We initialize this on the same thread as the ActivityLog, but then
  // subsequent operations occur on the DB thread. Instead of destructing the
  // ActivityDatabase, we call its Close() method on the DB thread and it
  // commits suicide.
  extensions::ActivityDatabase* db_;

  // Normally the DB thread. In some cases (tests), it might not exist
  // we dispatch to the UI thread.
  BrowserThread::ID dispatch_thread_;

  // Whether to log activity to stdout or the UI. These are set by switches.
  bool log_activity_to_stdout_;
  bool log_activity_to_ui_;

  // testing_mode_ controls whether to log API call arguments. By default, we
  // don't log most arguments to avoid saving too much data. In testing mode,
  // argument collection is enabled. We also whitelist some arguments for
  // collection regardless of whether this bool is true.
  bool testing_mode_;
  base::hash_set<std::string> arg_whitelist_api_;

  Profile* profile_;

  DISALLOW_COPY_AND_ASSIGN(ActivityLog);
};

// Each profile has different extensions, so we keep a different database for
// each profile.
class ActivityLogFactory : public ProfileKeyedServiceFactory {
 public:
  static ActivityLog* GetForProfile(Profile* profile) {
    return static_cast<ActivityLog*>(
        GetInstance()->GetServiceForProfile(profile, true));
  }

  static ActivityLogFactory* GetInstance();

 private:
  friend struct DefaultSingletonTraits<ActivityLogFactory>;
  ActivityLogFactory()
      : ProfileKeyedServiceFactory("ActivityLog",
                                   ProfileDependencyManager::GetInstance()) {}
  virtual ~ActivityLogFactory() {}

  virtual ProfileKeyedService* BuildServiceInstanceFor(
      content::BrowserContext* profile) const OVERRIDE;

  virtual content::BrowserContext* GetBrowserContextToUse(
      content::BrowserContext* context) const OVERRIDE;

  DISALLOW_COPY_AND_ASSIGN(ActivityLogFactory);
};


}  // namespace extensions

#endif  // CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_H_