summaryrefslogtreecommitdiffstats
path: root/chrome/browser/rlz
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/rlz
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/rlz')
-rw-r--r--chrome/browser/rlz/rlz.cc279
-rw-r--r--chrome/browser/rlz/rlz.h129
-rw-r--r--chrome/browser/rlz/rlz_unittest.cc92
3 files changed, 500 insertions, 0 deletions
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
new file mode 100644
index 0000000..00cee6d
--- /dev/null
+++ b/chrome/browser/rlz/rlz.cc
@@ -0,0 +1,279 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This code glues the RLZ library DLL with Chrome. It allows Chrome to work
+// with or without the DLL being present. If the DLL is not present the
+// functions do nothing and just return false.
+
+#include "chrome/browser/rlz/rlz.h"
+
+#include <windows.h>
+#include <process.h>
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/task.h"
+#include "base/thread.h"
+#include "chrome/app/google_update_settings.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/profile_manager.h"
+#include "chrome/browser/template_url_model.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/env_vars.h"
+//#include "chrome/common/pref_names.h"
+//#include "chrome/common/pref_service.h"
+
+namespace {
+
+// The maximum length of an access points RLZ in wide chars.
+const DWORD kMaxRlzLength = 64;
+
+// The RLZ is a DLL that might not be present in the system. We load it
+// as needed but never unload it.
+volatile HMODULE rlz_dll = NULL;
+
+
+enum {
+ ACCESS_VALUES_STALE, // Possibly new values available.
+ ACCESS_VALUES_FRESH // The cached values are current.
+};
+
+// Tracks if we have tried and succeeded sending the ping. This helps us
+// decide if we need to refresh the some cached strings.
+volatile int access_values_state = ACCESS_VALUES_STALE;
+
+extern "C" {
+typedef bool (*RecordProductEventFn)(RLZTracker::Product product,
+ RLZTracker::AccessPoint point,
+ RLZTracker::Event event_id,
+ void* reserved);
+
+typedef bool (*GetAccessPointRlzFn)(RLZTracker::AccessPoint point,
+ wchar_t* rlz,
+ DWORD rlz_size,
+ void* reserved);
+
+typedef bool (*ClearAllProductEventsFn)(RLZTracker::Product product,
+ void* reserved);
+
+typedef bool (*SendFinancialPingFn)(RLZTracker::Product product,
+ RLZTracker::AccessPoint* access_points,
+ const WCHAR* product_signature,
+ const WCHAR* product_brand,
+ const WCHAR* product_id,
+ const WCHAR* product_lang,
+ void* reserved);
+} // extern "C"
+
+RecordProductEventFn record_event = NULL;
+GetAccessPointRlzFn get_access_point = NULL;
+ClearAllProductEventsFn clear_all_events = NULL;
+SendFinancialPingFn send_ping = NULL;
+
+template <typename FuncT>
+FuncT WireExport(HMODULE module, const char* export_name) {
+ void* entry_point = ::GetProcAddress(module, export_name);
+ return (module)? reinterpret_cast<FuncT>(entry_point) : NULL;
+}
+
+HMODULE LoadRLZLibraryInternal(int directory_key) {
+ std::wstring rlz_path;
+ if (!PathService::Get(directory_key, &rlz_path))
+ return NULL;
+ file_util::AppendToPath(&rlz_path, L"rlz.dll");
+ return ::LoadLibraryW(rlz_path.c_str());
+}
+
+bool LoadRLZLibrary(int directory_key) {
+ rlz_dll = LoadRLZLibraryInternal(directory_key);
+ if (!rlz_dll) {
+ // As a last resort we can try the EXE directory.
+ if (directory_key != base::DIR_EXE)
+ rlz_dll = LoadRLZLibraryInternal(base::DIR_EXE);
+ }
+ if (rlz_dll) {
+ record_event =
+ WireExport<RecordProductEventFn>(rlz_dll, "RecordProductEvent");
+ get_access_point =
+ WireExport<GetAccessPointRlzFn>(rlz_dll, "GetAccessPointRlz");
+ clear_all_events =
+ WireExport<ClearAllProductEventsFn>(rlz_dll, "ClearAllProductEvents");
+ send_ping =
+ WireExport<SendFinancialPingFn>(rlz_dll, "SendFinancialPing");
+ return true;
+ }
+ return false;
+}
+
+class DailyPingTask : public Task {
+ public:
+ virtual ~DailyPingTask() {
+ }
+ virtual void Run() {
+ // We use a transient thread because we have no guarantees about
+ // how long the RLZ lib can block us.
+ _beginthread(PingNow, 0, NULL);
+ }
+
+ private:
+ // Causes a ping to the server using WinInet. There is logic inside RLZ dll
+ // that throttles it to a maximum of one ping per day.
+ static void _cdecl PingNow(void*) {
+ std::wstring lang;
+ GoogleUpdateSettings::GetLanguage(&lang);
+ if (lang.empty())
+ lang = L"en";
+ std::wstring brand;
+ GoogleUpdateSettings::GetBrand(&brand);
+ if (brand.empty())
+ brand = L"GGLD";
+ if (RLZTracker::SendFinancialPing(RLZTracker::CHROME, L"chrome",
+ brand.c_str(), NULL, lang.c_str())) {
+ access_values_state = ACCESS_VALUES_STALE;
+ }
+ }
+};
+
+// Performs late RLZ initialization and RLZ event recording for chrome.
+// This task needs to run on the UI thread.
+class DelayedInitTask : public Task {
+ public:
+ explicit DelayedInitTask(int directory_key, bool first_run)
+ : directory_key_(directory_key), first_run_(first_run) {
+ }
+ virtual ~DelayedInitTask() {
+ }
+ virtual void Run() {
+ if (!LoadRLZLibrary(directory_key_))
+ return;
+ // For non-interactive tests we don't do the rest of the initialization.
+ if (::GetEnvironmentVariableW(env_vars::kHeadless, NULL, 0))
+ return;
+ if (first_run_) {
+ // Record the installation of chrome.
+ RLZTracker::RecordProductEvent(RLZTracker::CHROME,
+ RLZTracker::CHROME_OMNIBOX,
+ RLZTracker::INSTALL);
+ RLZTracker::RecordProductEvent(RLZTracker::CHROME,
+ RLZTracker::CHROME_HOME_PAGE,
+ RLZTracker::INSTALL);
+ // Record if google is the initial search provider.
+ if (IsGoogleDefaultSearch()) {
+ RLZTracker::RecordProductEvent(RLZTracker::CHROME,
+ RLZTracker::CHROME_OMNIBOX,
+ RLZTracker::SET_TO_GOOGLE);
+ }
+ }
+ // Schedule the daily RLZ ping.
+ Thread* thread = g_browser_process->file_thread();
+ if (thread)
+ thread->message_loop()->PostTask(FROM_HERE, new DailyPingTask());
+ }
+
+ private:
+ bool IsGoogleDefaultSearch() {
+ if (!g_browser_process)
+ return false;
+ std::wstring user_data_dir;
+ if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
+ return false;
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
+ if (!profile)
+ return false;
+ const TemplateURL* url_template =
+ profile->GetTemplateURLModel()->GetDefaultSearchProvider();
+ if (!url_template)
+ return false;
+ return url_template->url()->HasGoogleBaseURLs();
+ }
+
+ int directory_key_;
+ bool first_run_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask);
+};
+
+} // namespace
+
+bool RLZTracker::InitRlz(int directory_key) {
+ return LoadRLZLibrary(directory_key);
+}
+
+bool RLZTracker::InitRlzDelayed(int directory_key, bool first_run) {
+ // Schedule the delayed init items.
+ const int kOneHundredSeconds = 100000;
+ MessageLoop::current()->PostDelayedTask(FROM_HERE,
+ new DelayedInitTask(directory_key, first_run), kOneHundredSeconds);
+ return true;
+}
+
+bool RLZTracker::RecordProductEvent(Product product, AccessPoint point,
+ Event event) {
+ return (record_event) ? record_event(product, point, event, NULL) : false;
+}
+
+bool RLZTracker::ClearAllProductEvents(Product product) {
+ return (clear_all_events) ? clear_all_events(product, NULL) : false;
+}
+
+// We implement caching of the answer of get_access_point() if the request
+// is for CHROME_OMNIBOX. If we had a successful ping, then we update the
+// cached value.
+
+bool RLZTracker::GetAccessPointRlz(AccessPoint point, std::wstring* rlz) {
+ static std::wstring cached_ommibox_rlz;
+ if (!get_access_point)
+ return false;
+ if ((CHROME_OMNIBOX == point) &&
+ (access_values_state == ACCESS_VALUES_FRESH)) {
+ *rlz = cached_ommibox_rlz;
+ return true;
+ }
+ wchar_t str_rlz[kMaxRlzLength];
+ if (!get_access_point(point, str_rlz, kMaxRlzLength, NULL))
+ return false;
+ if (CHROME_OMNIBOX == point) {
+ access_values_state = ACCESS_VALUES_FRESH;
+ cached_ommibox_rlz.assign(str_rlz);
+ }
+ *rlz = str_rlz;
+ return true;
+}
+
+bool RLZTracker::SendFinancialPing(Product product,
+ const wchar_t* product_signature,
+ const wchar_t* product_brand,
+ const wchar_t* product_id,
+ const wchar_t* product_lang) {
+ AccessPoint points[] = {CHROME_OMNIBOX, CHROME_HOME_PAGE, NO_ACCESS_POINT};
+ return (send_ping) ? send_ping(product, points, product_signature,
+ product_brand, product_id, product_lang, NULL) : false;
+}
diff --git a/chrome/browser/rlz/rlz.h b/chrome/browser/rlz/rlz.h
new file mode 100644
index 0000000..a05b141
--- /dev/null
+++ b/chrome/browser/rlz/rlz.h
@@ -0,0 +1,129 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_BROWSER_RLZ_RLZ_H__
+#define CHROME_BROWSER_RLZ_RLZ_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+
+// RLZ is a library which is used to measure partner distribution deals.
+// Its job is to record certain lifetime events in the registry and to send
+// them encoded as a compact string at most once per day. 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 to rlz.dll which can be
+// removed of the system with no adverse effects on chrome.
+
+class RLZTracker {
+
+ public:
+ // An Access Point offers a way to search using Google. Other products
+ // have specific entries here so do not remove the reserved access points.
+ enum AccessPoint {
+ NO_ACCESS_POINT = 0,
+ RESERVED_ACCESS_POINT_01,
+ RESERVED_ACCESS_POINT_02,
+ RESERVED_ACCESS_POINT_03,
+ RESERVED_ACCESS_POINT_04,
+ RESERVED_ACCESS_POINT_05,
+ RESERVED_ACCESS_POINT_06,
+ RESERVED_ACCESS_POINT_07,
+ RESERVED_ACCESS_POINT_08,
+ CHROME_OMNIBOX,
+ CHROME_HOME_PAGE,
+ LAST_ACCESS_POINT
+ };
+
+ // A product is an entity which wants to gets credit for setting an access
+ // point. Currently only the browser itself is supported but installed apps
+ // could have their own entry here.
+ enum Product {
+ RESERVED_PRODUCT_01 = 1,
+ RESERVED_PRODUCT_02,
+ RESERVED_PRODUCT_03,
+ RESERVED_PRODUCT_04,
+ CHROME,
+ LAST_PRODUCT
+ };
+
+ // Life cycle events. Some of them are applicable to all access points.
+ enum Event {
+ INVALID_EVENT = 0,
+ INSTALL = 1,
+ SET_TO_GOOGLE,
+ FIRST_SEARCH,
+ REPORT_RLS,
+ LAST_EVENT
+ };
+
+ // Initializes the RLZ library services. 'directory_key' indicates the base
+ // directory the RLZ dll would be found. For example base::DIR_CURRENT.
+ // If the RLZ dll is not found in this directory the code falls back to try
+ // to load it from base::DIR_EXE.
+ // Returns false if the dll could not be loaded and initialized.
+ // This function is intended primarily for testing.
+ static bool InitRlz(int directory_key);
+
+ // Like InitRlz() this function the RLZ library services for use in chrome.
+ // Besides binding the dll, it schedules a delayed task that performs the
+ // daily ping and registers the some events when 'first-run' is true.
+ static bool InitRlzDelayed(int directory_key, bool first_run);
+
+ // 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(Product product, AccessPoint point,
+ Event event_id);
+
+ // Get 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(AccessPoint point, std::wstring* rlz);
+
+ // Clear all events reported by this product. In Chrome this will be called
+ // when it is un-installed.
+ static bool ClearAllProductEvents(Product product);
+
+ // Called once a day to report the events to the server and to get updated
+ // RLZs for the different access points. This call uses Wininet to perform
+ // the http request. Returns true if the transaction succeeded and returns
+ // false if the transaction failed OR if a previous ping request was done
+ // in the last 24 hours.
+ static bool SendFinancialPing(Product product,
+ const wchar_t* product_signature,
+ const wchar_t* product_brand,
+ const wchar_t* product_id,
+ const wchar_t* product_lang);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RLZTracker);
+};
+
+#endif // CHROME_BROWSER_RLZ_RLZ_H__
diff --git a/chrome/browser/rlz/rlz_unittest.cc b/chrome/browser/rlz/rlz_unittest.cc
new file mode 100644
index 0000000..c8005c5
--- /dev/null
+++ b/chrome/browser/rlz/rlz_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/rlz/rlz.h"
+
+#include "base/registry.h"
+#include "base/path_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+// Gets rid of registry leftovers from testing. Returns false if there
+// is nothing to clean.
+bool CleanValue(const wchar_t* key_name, const wchar_t* value) {
+ RegKey key;
+ if (!key.Open(HKEY_CURRENT_USER, key_name, KEY_READ | KEY_WRITE))
+ return false;
+ EXPECT_TRUE(key.DeleteValue(value));
+ return true;
+}
+
+// The chrome events RLZ key lives here.
+const wchar_t kKeyName[] = L"Software\\Google\\Common\\Rlz\\Events\\C";
+
+} // namespace
+
+TEST(RlzLibTest, RecordProductEvent) {
+ if (!RLZTracker::InitRlz(base::DIR_EXE))
+ return;
+
+ DWORD recorded_value = 0;
+ EXPECT_TRUE(RLZTracker::RecordProductEvent(RLZTracker::CHROME,
+ RLZTracker::CHROME_OMNIBOX, RLZTracker::FIRST_SEARCH));
+ const wchar_t kEvent1[] = L"C1F";
+ RegKey key1;
+ EXPECT_TRUE(key1.Open(HKEY_CURRENT_USER, kKeyName, KEY_READ));
+ EXPECT_TRUE(key1.ReadValueDW(kEvent1, &recorded_value));
+ EXPECT_EQ(1, recorded_value);
+ EXPECT_TRUE(CleanValue(kKeyName, kEvent1));
+
+ EXPECT_TRUE(RLZTracker::RecordProductEvent(RLZTracker::CHROME,
+ RLZTracker::CHROME_HOME_PAGE, RLZTracker::SET_TO_GOOGLE));
+ const wchar_t kEvent2[] = L"C2S";
+ RegKey key2;
+ EXPECT_TRUE(key2.Open(HKEY_CURRENT_USER, kKeyName, KEY_READ));
+ DWORD value = 0;
+ EXPECT_TRUE(key2.ReadValueDW(kEvent2, &recorded_value));
+ EXPECT_EQ(1, recorded_value);
+ EXPECT_TRUE(CleanValue(kKeyName, kEvent2));
+}
+
+TEST(RlzLibTest, CleanProductEvents) {
+ if (!RLZTracker::InitRlz(base::DIR_EXE))
+ return;
+
+ DWORD recorded_value = 0;
+ EXPECT_TRUE(RLZTracker::RecordProductEvent(RLZTracker::CHROME,
+ RLZTracker::CHROME_OMNIBOX, RLZTracker::FIRST_SEARCH));
+ const wchar_t kEvent1[] = L"C1F";
+ RegKey key1;
+ EXPECT_TRUE(key1.Open(HKEY_CURRENT_USER, kKeyName, KEY_READ));
+ EXPECT_TRUE(key1.ReadValueDW(kEvent1, &recorded_value));
+ EXPECT_EQ(1, recorded_value);
+
+ EXPECT_TRUE(RLZTracker::ClearAllProductEvents(RLZTracker::CHROME));
+ EXPECT_FALSE(CleanValue(kKeyName, kEvent1));
+}