blob: bd1d96a10e6a9e2dd793f25f9855da1ba840290a [file] [log] [blame]
// Copyright 2013 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_POLICY_H_
#define CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_POLICY_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/values.h"
#include "chrome/browser/extensions/activity_log/activity_actions.h"
#include "chrome/browser/extensions/activity_log/activity_database.h"
#include "chrome/browser/extensions/activity_log/activity_log_task_runner.h"
#include "chrome/common/extensions/api/activity_log_private.h"
#include "content/public/browser/browser_thread.h"
#include "url/gurl.h"
class Profile;
class GURL;
namespace base {
class Clock;
class FilePath;
}
namespace extensions {
// An abstract class for processing and summarizing activity log data.
// Subclasses will generally store data in an SQLite database (the
// ActivityLogDatabasePolicy subclass includes some helper methods to assist
// with this case), but this is not absolutely required.
//
// Implementations should support:
// (1) Receiving Actions to process, and summarizing, compression, and storing
// these as appropriate.
// (2) Reading Actions back from storage.
// (3) Cleaning of URLs
//
// Implementations based on a database should likely implement
// ActivityDatabase::Delegate, which provides hooks on database events and
// allows the database to periodically request that actions (which the policy
// is responsible for queueing) be flushed to storage.
//
// Since every policy implementation might summarize data differently, the
// database implementation is policy-specific and therefore completely
// encapsulated in the policy class. All the member functions can be called
// on the UI thread.
class ActivityLogPolicy {
public:
enum PolicyType {
POLICY_FULLSTREAM,
POLICY_COUNTS,
POLICY_INVALID,
};
// Parameters are the profile and the thread that will be used to execute
// the callback when ReadData is called.
// TODO(felt,dbabic) Since only ReadData uses thread_id, it would be
// cleaner to pass thread_id as a param of ReadData directly.
explicit ActivityLogPolicy(Profile* profile);
// Instead of a public destructor, ActivityLogPolicy objects have a Close()
// method which will cause the object to be deleted (but may do so on another
// thread or in a deferred fashion).
virtual void Close() = 0;
// Updates the internal state of the model summarizing actions and possibly
// writes to the database. Implements the default policy storing internal
// state to memory every 5 min.
virtual void ProcessAction(scoped_refptr<Action> action) = 0;
// For unit testing only.
void SetClockForTesting(base::Clock* clock);
// A collection of methods that are useful for implementing policies. These
// are all static methods; the ActivityLogPolicy::Util class cannot be
// instantiated. This is nested within ActivityLogPolicy to make calling
// these methods more convenient from within a policy, but they are public.
class Util {
public:
// A collection of API calls, used to specify whitelists for argument
// filtering.
typedef std::set<std::pair<Action::ActionType, std::string> > ApiSet;
// Serialize a Value as a JSON string. Returns an empty string if value is
// null.
static std::string Serialize(const base::Value* value);
// Removes potentially privacy-sensitive data that should not be logged.
// This should generally be called on an Action before logging, unless
// debugging flags are enabled. Modifies the Action object in place; if
// the action might be shared with other users, it is up to the caller to
// call ->Clone() first.
static void StripPrivacySensitiveFields(scoped_refptr<Action> action);
// Strip arguments from most API actions, preserving actions only for a
// whitelisted set. Modifies the Action object in-place.
static void StripArguments(const ApiSet& api_whitelist,
scoped_refptr<Action> action);
// Given a base day (timestamp at local midnight), computes the timestamp
// at midnight the given number of days before or after.
static base::Time AddDays(const base::Time& base_date, int days);
// Compute the time bounds that should be used for a database query to
// cover a time range days_ago days in the past, relative to the specified
// time.
static void ComputeDatabaseTimeBounds(const base::Time& now,
int days_ago,
int64_t* early_bound,
int64_t* late_bound);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Util);
};
protected:
// An ActivityLogPolicy is not directly destroyed. Instead, call Close()
// which will cause the object to be deleted when it is safe.
virtual ~ActivityLogPolicy();
// Returns Time::Now() unless a mock clock has been installed with
// SetClockForTesting, in which case the time according to that clock is used
// instead.
base::Time Now() const;
private:
// Support for a mock clock for testing purposes. This is used by ReadData
// to determine the date for "today" when when interpreting date ranges to
// fetch. This has no effect on batching of writes to the database.
base::Clock* testing_clock_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ActivityLogPolicy);
};
// A subclass of ActivityLogPolicy which is designed for policies that use
// database storage; it contains several useful helper methods.
class ActivityLogDatabasePolicy : public ActivityLogPolicy,
public ActivityDatabase::Delegate {
public:
ActivityLogDatabasePolicy(Profile* profile,
const base::FilePath& database_name);
// Initializes an activity log policy database. This needs to be called after
// constructing ActivityLogDatabasePolicy.
void Init();
// Requests that in-memory state be written to the database. This method can
// be called from any thread, but the database writes happen asynchronously
// on the database thread.
virtual void Flush();
// Gets all actions that match the specified fields. URLs are treated like
// prefixes; other fields are exact matches. Empty strings are not matched to
// anything. For the date: 0 = today, 1 = yesterday, etc.; if the data is
// negative, it will be treated as missing.
virtual void ReadFilteredData(
const std::string& extension_id,
const Action::ActionType type,
const std::string& api_name,
const std::string& page_url,
const std::string& arg_url,
const int days_ago,
base::OnceCallback<void(std::unique_ptr<Action::ActionVector>)>
callback) = 0;
// Remove actions (rows) which IDs are in the action_ids array.
virtual void RemoveActions(const std::vector<int64_t>& action_ids) = 0;
// Clean the relevant URL data. The cleaning may need to be different for
// different policies. If restrict_urls is empty then all URLs are removed.
virtual void RemoveURLs(const std::vector<GURL>& restrict_urls) = 0;
// Remove all rows relating to a given extension.
virtual void RemoveExtensionData(const std::string& extension_id) = 0;
// Deletes everything in the database.
virtual void DeleteDatabase() = 0;
protected:
// The Schedule methods dispatch the calls to the database on a
// separate thread.
template<typename DatabaseType, typename DatabaseFunc>
void ScheduleAndForget(DatabaseType db, DatabaseFunc func) {
GetActivityLogTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(func, base::Unretained(db)));
}
template<typename DatabaseType, typename DatabaseFunc, typename ArgA>
void ScheduleAndForget(DatabaseType db, DatabaseFunc func, ArgA a) {
GetActivityLogTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(func, base::Unretained(db), a));
}
template<typename DatabaseType, typename DatabaseFunc,
typename ArgA, typename ArgB>
void ScheduleAndForget(DatabaseType db, DatabaseFunc func, ArgA a, ArgB b) {
GetActivityLogTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(func, base::Unretained(db), a, b));
}
// Access to the underlying ActivityDatabase.
ActivityDatabase* activity_database() const { return db_; }
// Access to the SQL connection in the ActivityDatabase. This should only be
// called from the database thread. May return NULL if the database is not
// valid.
sql::Database* GetDatabaseConnection() const;
private:
// See the comments for the ActivityDatabase class for a discussion of how
// database cleanup runs.
ActivityDatabase* db_;
base::FilePath database_path_;
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_POLICY_H_