1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_POLICY_H_
6#define CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_POLICY_H_
7
8#include <map>
9#include <set>
10#include <string>
11#include <vector>
12
13#include "base/bind.h"
14#include "base/bind_helpers.h"
15#include "base/callback.h"
16#include "base/memory/scoped_ptr.h"
17#include "base/values.h"
18#include "chrome/browser/extensions/activity_log/activity_actions.h"
19#include "chrome/browser/extensions/activity_log/activity_database.h"
20#include "chrome/common/extensions/api/activity_log_private.h"
21#include "content/public/browser/browser_thread.h"
22#include "url/gurl.h"
23
24class Profile;
25class GURL;
26
27namespace base {
28class FilePath;
29}
30
31namespace extensions {
32
33class Extension;
34
35// An abstract class for processing and summarizing activity log data.
36// Subclasses will generally store data in an SQLite database (the
37// ActivityLogDatabasePolicy subclass includes some helper methods to assist
38// with this case), but this is not absolutely required.
39//
40// Implementations should support:
41// (1) Receiving Actions to process, and summarizing, compression, and storing
42//     these as appropriate.
43// (2) Reading Actions back from storage.
44// (3) Cleaning of URLs
45//
46// Implementations based on a database should likely implement
47// ActivityDatabase::Delegate, which provides hooks on database events and
48// allows the database to periodically request that actions (which the policy
49// is responsible for queueing) be flushed to storage.
50//
51// Since every policy implementation might summarize data differently, the
52// database implementation is policy-specific and therefore completely
53// encapsulated in the policy class.  All the member functions can be called
54// on the UI thread.
55class ActivityLogPolicy {
56 public:
57  enum PolicyType {
58    POLICY_FULLSTREAM,
59    POLICY_COUNTS,
60    POLICY_INVALID,
61  };
62
63  // Parameters are the profile and the thread that will be used to execute
64  // the callback when ReadData is called.
65  // TODO(felt,dbabic)  Since only ReadData uses thread_id, it would be
66  // cleaner to pass thread_id as a param of ReadData directly.
67  explicit ActivityLogPolicy(Profile* profile);
68
69  // Instead of a public destructor, ActivityLogPolicy objects have a Close()
70  // method which will cause the object to be deleted (but may do so on another
71  // thread or in a deferred fashion).
72  virtual void Close() = 0;
73
74  // Updates the internal state of the model summarizing actions and possibly
75  // writes to the database.  Implements the default policy storing internal
76  // state to memory every 5 min.
77  virtual void ProcessAction(scoped_refptr<Action> action) = 0;
78
79  // For unit testing only.
80  void SetClockForTesting(scoped_ptr<base::Clock> clock);
81
82  // A collection of methods that are useful for implementing policies.  These
83  // are all static methods; the ActivityLogPolicy::Util class cannot be
84  // instantiated.  This is nested within ActivityLogPolicy to make calling
85  // these methods more convenient from within a policy, but they are public.
86  class Util {
87   public:
88    // A collection of API calls, used to specify whitelists for argument
89    // filtering.
90    typedef std::set<std::pair<Action::ActionType, std::string> > ApiSet;
91
92    // Serialize a Value as a JSON string.  Returns an empty string if value is
93    // null.
94    static std::string Serialize(const base::Value* value);
95
96    // Removes potentially privacy-sensitive data that should not be logged.
97    // This should generally be called on an Action before logging, unless
98    // debugging flags are enabled.  Modifies the Action object in place; if
99    // the action might be shared with other users, it is up to the caller to
100    // call ->Clone() first.
101    static void StripPrivacySensitiveFields(scoped_refptr<Action> action);
102
103    // Strip arguments from most API actions, preserving actions only for a
104    // whitelisted set.  Modifies the Action object in-place.
105    static void StripArguments(const ApiSet& api_whitelist,
106                               scoped_refptr<Action> action);
107
108    // Given a base day (timestamp at local midnight), computes the timestamp
109    // at midnight the given number of days before or after.
110    static base::Time AddDays(const base::Time& base_date, int days);
111
112    // Compute the time bounds that should be used for a database query to
113    // cover a time range days_ago days in the past, relative to the specified
114    // time.
115    static void ComputeDatabaseTimeBounds(const base::Time& now,
116                                          int days_ago,
117                                          int64* early_bound,
118                                          int64* late_bound);
119
120    // Deletes obsolete database tables from an activity log database.  This
121    // can be used in InitDatabase() methods of ActivityLogDatabasePolicy
122    // subclasses to clean up data from old versions of the activity logging
123    // code.  Returns true on success, false on database error.
124    static bool DropObsoleteTables(sql::Connection* db);
125
126   private:
127    DISALLOW_IMPLICIT_CONSTRUCTORS(Util);
128  };
129
130 protected:
131  // An ActivityLogPolicy is not directly destroyed.  Instead, call Close()
132  // which will cause the object to be deleted when it is safe.
133  virtual ~ActivityLogPolicy();
134
135  // Returns Time::Now() unless a mock clock has been installed with
136  // SetClockForTesting, in which case the time according to that clock is used
137  // instead.
138  base::Time Now() const;
139
140 private:
141  // Support for a mock clock for testing purposes.  This is used by ReadData
142  // to determine the date for "today" when when interpreting date ranges to
143  // fetch.  This has no effect on batching of writes to the database.
144  scoped_ptr<base::Clock> testing_clock_;
145
146  DISALLOW_COPY_AND_ASSIGN(ActivityLogPolicy);
147};
148
149// A subclass of ActivityLogPolicy which is designed for policies that use
150// database storage; it contains several useful helper methods.
151class ActivityLogDatabasePolicy : public ActivityLogPolicy,
152                                  public ActivityDatabase::Delegate {
153 public:
154  ActivityLogDatabasePolicy(Profile* profile,
155                            const base::FilePath& database_name);
156
157  // Initializes an activity log policy database. This needs to be called after
158  // constructing ActivityLogDatabasePolicy.
159  void Init();
160
161  // Requests that in-memory state be written to the database.  This method can
162  // be called from any thread, but the database writes happen asynchronously
163  // on the database thread.
164  virtual void Flush();
165
166  // Gets all actions that match the specified fields. URLs are treated like
167  // prefixes; other fields are exact matches. Empty strings are not matched to
168  // anything. For the date: 0 = today, 1 = yesterday, etc.; if the data is
169  // negative, it will be treated as missing.
170  virtual void ReadFilteredData(
171      const std::string& extension_id,
172      const Action::ActionType type,
173      const std::string& api_name,
174      const std::string& page_url,
175      const std::string& arg_url,
176      const int days_ago,
177      const base::Callback
178         <void(scoped_ptr<Action::ActionVector>)>& callback) = 0;
179
180  // Remove actions (rows) which IDs are in the action_ids array.
181  virtual void RemoveActions(const std::vector<int64>& action_ids) = 0;
182
183  // Clean the relevant URL data. The cleaning may need to be different for
184  // different policies. If restrict_urls is empty then all URLs are removed.
185  virtual void RemoveURLs(const std::vector<GURL>& restrict_urls) = 0;
186
187  // Remove all rows relating to a given extension.
188  virtual void RemoveExtensionData(const std::string& extension_id) = 0;
189
190  // Deletes everything in the database.
191  virtual void DeleteDatabase() = 0;
192
193 protected:
194  // The Schedule methods dispatch the calls to the database on a
195  // separate thread.
196  template<typename DatabaseType, typename DatabaseFunc>
197  void ScheduleAndForget(DatabaseType db, DatabaseFunc func) {
198    content::BrowserThread::PostTask(
199        content::BrowserThread::DB,
200        FROM_HERE,
201        base::Bind(func, base::Unretained(db)));
202  }
203
204  template<typename DatabaseType, typename DatabaseFunc, typename ArgA>
205  void ScheduleAndForget(DatabaseType db, DatabaseFunc func, ArgA a) {
206    content::BrowserThread::PostTask(
207        content::BrowserThread::DB,
208        FROM_HERE,
209        base::Bind(func, base::Unretained(db), a));
210  }
211
212  template<typename DatabaseType, typename DatabaseFunc,
213      typename ArgA, typename ArgB>
214  void ScheduleAndForget(DatabaseType db, DatabaseFunc func, ArgA a, ArgB b) {
215    content::BrowserThread::PostTask(
216        content::BrowserThread::DB,
217        FROM_HERE,
218        base::Bind(func, base::Unretained(db), a, b));
219  }
220
221  // Access to the underlying ActivityDatabase.
222  ActivityDatabase* activity_database() const { return db_; }
223
224  // Access to the SQL connection in the ActivityDatabase.  This should only be
225  // called from the database thread.  May return NULL if the database is not
226  // valid.
227  sql::Connection* GetDatabaseConnection() const;
228
229 private:
230  // See the comments for the ActivityDatabase class for a discussion of how
231  // database cleanup runs.
232  ActivityDatabase* db_;
233  base::FilePath database_path_;
234};
235
236}  // namespace extensions
237
238#endif  // CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_POLICY_H_
239