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 24 class Profile; 25 class GURL; 26 27 namespace base { 28 class FilePath; 29 } 30 31 namespace extensions { 32 33 class 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. 55 class 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. 151 class 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