// 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_RLZ_RLZ_H_
#define CHROME_BROWSER_RLZ_RLZ_H_
#include "build/build_config.h"
#if defined(ENABLE_RLZ)
#include <map>
#include <string>
#include "base/basictypes.h"
#include "base/memory/singleton.h"
#include "base/strings/string16.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "rlz/lib/rlz_lib.h"
class Profile;
namespace net {
class URLRequestContextGetter;
}
// RLZ is a library which is used to measure distribution scenarios.
// Its job is to record certain lifetime events in the registry and to send
// them encoded as a compact string at most twice. The sent data does
// not contain information that can be used to identify a user or to infer
// browsing habits. The API in this file is a wrapper around the open source
// RLZ library which can be found at http://code.google.com/p/rlz.
//
// For partner or bundled installs, the RLZ might send more information
// according to the terms disclosed in the EULA.
class RLZTracker : public content::NotificationObserver {
public:
// Initializes the RLZ library services for use in chrome. Schedules a delayed
// task that performs the ping and registers some events when 'first-run' is
// true.
//
// When |send_ping_immediately| is true, a financial ping should be sent
// immediately after a first search is recorded, without waiting for |delay|.
// However, we only want this behaviour on first run.
//
// If the chrome brand is organic (no partners) then the pings don't occur.
static bool InitRlzFromProfileDelayed(Profile* profile,
bool first_run,
bool send_ping_immediately,
base::TimeDelta delay);
// Records an RLZ event. Some events can be access point independent.
// Returns false it the event could not be recorded. Requires write access
// to the HKCU registry hive on windows.
static bool RecordProductEvent(rlz_lib::Product product,
rlz_lib::AccessPoint point,
rlz_lib::Event event_id);
// For the point parameter of RecordProductEvent.
static const rlz_lib::AccessPoint CHROME_OMNIBOX;
static const rlz_lib::AccessPoint CHROME_HOME_PAGE;
// Gets the HTTP header value that can be added to requests from the
// specific access point. The string returned is of the form:
//
// "X-Rlz-String: <access-point-rlz>\r\n"
//
static std::string GetAccessPointHttpHeader(rlz_lib::AccessPoint point);
// Gets the RLZ value of the access point.
// Returns false if the rlz string could not be obtained. In some cases
// an empty string can be returned which is not an error.
static bool GetAccessPointRlz(rlz_lib::AccessPoint point,
base::string16* rlz);
// Invoked during shutdown to clean up any state created by RLZTracker.
static void CleanupRlz();
#if defined(OS_CHROMEOS)
// Clears all product state. Should be called when turning RLZ off. On other
// platforms, this is done by product uninstaller.
static void ClearRlzState();
#endif
// This method is public for use by the Singleton class.
static RLZTracker* GetInstance();
// Enables zero delay for InitRlzFromProfileDelayed. For testing only.
static void EnableZeroDelayForTesting();
// The following methods are made protected so that they can be used for
// testing purposes. Production code should never need to call these.
protected:
RLZTracker();
virtual ~RLZTracker();
// Called by InitRlzFromProfileDelayed with values taken from |profile|.
static bool InitRlzDelayed(bool first_run,
bool send_ping_immediately,
base::TimeDelta delay,
bool is_google_default_search,
bool is_google_homepage,
bool is_google_in_startpages);
// Performs initialization of RLZ tracker that is purposefully delayed so
// that it does not interfere with chrome startup time.
virtual void DelayedInit();
// content::NotificationObserver implementation:
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Used by test code to override the default RLZTracker instance returned
// by GetInstance().
void set_tracker(RLZTracker* tracker) {
tracker_ = tracker;
}
// Sends the financial ping to the RLZ servers and invalidates the RLZ string
// cache since the response from the RLZ server may have changed then.
// Protected so that its accessible from tests.
void PingNowImpl();
private:
friend struct DefaultSingletonTraits<RLZTracker>;
friend class base::RefCountedThreadSafe<RLZTracker>;
// Implementation called from InitRlzDelayed() static method.
bool Init(bool first_run,
bool send_ping_immediately,
base::TimeDelta delay,
bool google_default_search,
bool google_default_homepage,
bool is_google_in_startpages);
// Implementation called from RecordProductEvent() static method.
bool RecordProductEventImpl(rlz_lib::Product product,
rlz_lib::AccessPoint point,
rlz_lib::Event event_id);
// Records FIRST_SEARCH event. Called from Observe() on blocking task runner.
void RecordFirstSearch(rlz_lib::AccessPoint point);
// Implementation called from GetAccessPointRlz() static method.
bool GetAccessPointRlzImpl(rlz_lib::AccessPoint point, base::string16* rlz);
// Schedules the delayed initialization. This method is virtual to allow
// tests to override how the scheduling is done.
virtual void ScheduleDelayedInit(base::TimeDelta delay);
// Schedules a call to rlz_lib::RecordProductEvent(). This method is virtual
// to allow tests to override how the scheduling is done.
virtual bool ScheduleRecordProductEvent(rlz_lib::Product product,
rlz_lib::AccessPoint point,
rlz_lib::Event event_id);
// Schedules a call to rlz_lib::RecordFirstSearch(). This method is virtual
// to allow tests to override how the scheduling is done.
virtual bool ScheduleRecordFirstSearch(rlz_lib::AccessPoint point);
// Schedules a call to rlz_lib::SendFinancialPing(). This method is virtual
// to allow tests to override how the scheduling is done.
virtual void ScheduleFinancialPing();
// Schedules a call to GetAccessPointRlz() on the I/O thread if the current
// thread is not already the I/O thread, otherwise does nothing. Returns
// true if the call was scheduled, and false otherwise. This method is
// virtual to allow tests to override how the scheduling is done.
virtual bool ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point);
// Sends the financial ping to the RLZ servers. This method is virtual to
// allow tests to override.
virtual bool SendFinancialPing(const std::string& brand,
const base::string16& lang,
const base::string16& referral);
#if defined(OS_CHROMEOS)
// Implementation called from ClearRlzState static method.
void ClearRlzStateImpl();
// Schedules a call to ClearRlzStateImpl(). This method is virtual
// to allow tests to override how the scheduling is done.
virtual bool ScheduleClearRlzState();
#endif
// Tracker used for testing purposes only. If this value is non-NULL, it
// will be returned from GetInstance() instead of the regular singleton.
static RLZTracker* tracker_;
// Configuation data for RLZ tracker. Set by call to Init().
bool first_run_;
bool send_ping_immediately_;
bool is_google_default_search_;
bool is_google_homepage_;
bool is_google_in_startpages_;
// Unique sequence token so that tasks posted by RLZTracker are executed
// sequentially in the blocking pool.
base::SequencedWorkerPool::SequenceToken worker_pool_token_;
// Keeps track if the RLZ tracker has already performed its delayed
// initialization.
bool already_ran_;
// Keeps a cache of RLZ access point strings, since they rarely change.
// The cache must be protected by a lock since it may be accessed from
// the UI thread for reading and the IO thread for reading and/or writing.
base::Lock cache_lock_;
std::map<rlz_lib::AccessPoint, base::string16> rlz_cache_;
// Keeps track of whether the omnibox or host page have been used.
bool omnibox_used_;
bool homepage_used_;
// Main and (optionally) reactivation brand codes, assigned on UI thread.
std::string brand_;
std::string reactivation_brand_;
content::NotificationRegistrar registrar_;
// Minimum delay before sending financial ping after initialization.
base::TimeDelta min_init_delay_;
DISALLOW_COPY_AND_ASSIGN(RLZTracker);
};
#endif // defined(ENABLE_RLZ)
#endif // CHROME_BROWSER_RLZ_RLZ_H_