diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/rlz/rlz.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_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/rlz.cc')
-rw-r--r-- | chrome/browser/rlz/rlz.cc | 279 |
1 files changed, 279 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; +} |