| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // This code glues the RLZ library DLL with Chrome. It allows Chrome to work | 5 // This code glues the RLZ library DLL with Chrome. It allows Chrome to work |
| 6 // with or without the DLL being present. If the DLL is not present the | 6 // with or without the DLL being present. If the DLL is not present the |
| 7 // functions do nothing and just return false. | 7 // functions do nothing and just return false. |
| 8 | 8 |
| 9 #include "chrome/browser/rlz/rlz.h" | 9 #include "chrome/browser/rlz/rlz.h" |
| 10 | 10 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 #include "chrome/common/env_vars.h" | 27 #include "chrome/common/env_vars.h" |
| 28 #include "chrome/common/notification_registrar.h" | 28 #include "chrome/common/notification_registrar.h" |
| 29 #include "chrome/common/notification_service.h" | 29 #include "chrome/common/notification_service.h" |
| 30 #include "chrome/installer/util/google_update_settings.h" | 30 #include "chrome/installer/util/google_update_settings.h" |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 // The maximum length of an access points RLZ in wide chars. | 34 // The maximum length of an access points RLZ in wide chars. |
| 35 const DWORD kMaxRlzLength = 64; | 35 const DWORD kMaxRlzLength = 64; |
| 36 | 36 |
| 37 // The RLZ is a DLL that might not be present in the system. We load it | |
| 38 // as needed but never unload it. | |
| 39 volatile HMODULE rlz_dll = NULL; | |
| 40 | |
| 41 enum { | 37 enum { |
| 42 ACCESS_VALUES_STALE, // Possibly new values available. | 38 ACCESS_VALUES_STALE, // Possibly new values available. |
| 43 ACCESS_VALUES_FRESH // The cached values are current. | 39 ACCESS_VALUES_FRESH // The cached values are current. |
| 44 }; | 40 }; |
| 45 | 41 |
| 46 // Tracks if we have tried and succeeded sending the ping. This helps us | 42 // Tracks if we have tried and succeeded sending the ping. This helps us |
| 47 // decide if we need to refresh the some cached strings. | 43 // decide if we need to refresh the some cached strings. |
| 48 volatile int access_values_state = ACCESS_VALUES_STALE; | 44 volatile int access_values_state = ACCESS_VALUES_STALE; |
| 49 | 45 |
| 50 extern "C" { | 46 bool SendFinancialPing(const std::wstring& brand, const std::wstring& lang, |
| 51 typedef bool (*RecordProductEventFn)(RLZTracker::Product product, | 47 const std::wstring& referral, bool exclude_id) { |
| 52 RLZTracker::AccessPoint point, | 48 rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, |
| 53 RLZTracker::Event event_id, | 49 rlz_lib::CHROME_HOME_PAGE, |
| 54 void* reserved); | 50 rlz_lib::NO_ACCESS_POINT}; |
| 51 std::string brand_ascii(WideToASCII(brand)); |
| 52 std::string lang_ascii(WideToASCII(lang)); |
| 53 std::string referral_ascii(WideToASCII(referral)); |
| 55 | 54 |
| 56 typedef bool (*GetAccessPointRlzFn)(RLZTracker::AccessPoint point, | 55 return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", |
| 57 wchar_t* rlz, | 56 brand_ascii.c_str(), referral_ascii.c_str(), |
| 58 DWORD rlz_size, | 57 lang_ascii.c_str(), exclude_id, NULL, true); |
| 59 void* reserved); | |
| 60 | |
| 61 typedef bool (*ClearAllProductEventsFn)(RLZTracker::Product product, | |
| 62 void* reserved); | |
| 63 | |
| 64 typedef bool (*SendFinancialPingNoDelayFn)(RLZTracker::Product product, | |
| 65 RLZTracker::AccessPoint* access_point
s, | |
| 66 const WCHAR* product_signature, | |
| 67 const WCHAR* product_brand, | |
| 68 const WCHAR* product_id, | |
| 69 const WCHAR* product_lang, | |
| 70 bool exclude_id, | |
| 71 void* reserved); | |
| 72 } // extern "C". | |
| 73 | |
| 74 RecordProductEventFn record_event = NULL; | |
| 75 GetAccessPointRlzFn get_access_point = NULL; | |
| 76 ClearAllProductEventsFn clear_all_events = NULL; | |
| 77 SendFinancialPingNoDelayFn send_ping_no_delay = NULL; | |
| 78 | |
| 79 template <typename FuncT> | |
| 80 FuncT WireExport(HMODULE module, const char* export_name) { | |
| 81 if (!module) | |
| 82 return NULL; | |
| 83 void* entry_point = ::GetProcAddress(module, export_name); | |
| 84 return reinterpret_cast<FuncT>(entry_point); | |
| 85 } | |
| 86 | |
| 87 HMODULE LoadRLZLibraryInternal(int directory_key) { | |
| 88 FilePath rlz_path; | |
| 89 if (!PathService::Get(directory_key, &rlz_path)) | |
| 90 return NULL; | |
| 91 rlz_path = rlz_path.AppendASCII("rlz.dll"); | |
| 92 return ::LoadLibraryW(rlz_path.value().c_str()); | |
| 93 } | |
| 94 | |
| 95 bool LoadRLZLibrary(int directory_key) { | |
| 96 rlz_dll = LoadRLZLibraryInternal(directory_key); | |
| 97 if (!rlz_dll) { | |
| 98 // As a last resort we can try the EXE directory. | |
| 99 if (directory_key != base::DIR_EXE) | |
| 100 rlz_dll = LoadRLZLibraryInternal(base::DIR_EXE); | |
| 101 } | |
| 102 if (rlz_dll) { | |
| 103 record_event = | |
| 104 WireExport<RecordProductEventFn>(rlz_dll, "RecordProductEvent"); | |
| 105 get_access_point = | |
| 106 WireExport<GetAccessPointRlzFn>(rlz_dll, "GetAccessPointRlz"); | |
| 107 clear_all_events = | |
| 108 WireExport<ClearAllProductEventsFn>(rlz_dll, "ClearAllProductEvents"); | |
| 109 send_ping_no_delay = | |
| 110 WireExport<SendFinancialPingNoDelayFn>(rlz_dll, | |
| 111 "SendFinancialPingNoDelay"); | |
| 112 return (record_event && get_access_point && clear_all_events && | |
| 113 send_ping_no_delay); | |
| 114 } | |
| 115 return false; | |
| 116 } | |
| 117 | |
| 118 bool SendFinancialPing(const wchar_t* brand, const wchar_t* lang, | |
| 119 const wchar_t* referral, bool exclude_id) { | |
| 120 RLZTracker::AccessPoint points[] = {RLZTracker::CHROME_OMNIBOX, | |
| 121 RLZTracker::CHROME_HOME_PAGE, | |
| 122 RLZTracker::NO_ACCESS_POINT}; | |
| 123 if (!send_ping_no_delay) | |
| 124 return false; | |
| 125 return send_ping_no_delay(RLZTracker::CHROME, points, L"chrome", brand, | |
| 126 referral, lang, exclude_id, NULL); | |
| 127 } | 58 } |
| 128 | 59 |
| 129 // This class leverages the AutocompleteEditModel notification to know when | 60 // This class leverages the AutocompleteEditModel notification to know when |
| 130 // the user first interacted with the omnibox and set a global accordingly. | 61 // the user first interacted with the omnibox and set a global accordingly. |
| 131 class OmniBoxUsageObserver : public NotificationObserver { | 62 class OmniBoxUsageObserver : public NotificationObserver { |
| 132 public: | 63 public: |
| 133 OmniBoxUsageObserver() { | 64 OmniBoxUsageObserver() { |
| 134 registrar_.Add(this, NotificationType::OMNIBOX_OPENED_URL, | 65 registrar_.Add(this, NotificationType::OMNIBOX_OPENED_URL, |
| 135 NotificationService::AllSources()); | 66 NotificationService::AllSources()); |
| 136 omnibox_used_ = false; | 67 omnibox_used_ = false; |
| 137 DCHECK(!instance_); | 68 DCHECK(!instance_); |
| 138 instance_ = this; | 69 instance_ = this; |
| 139 } | 70 } |
| 140 | 71 |
| 141 virtual void Observe(NotificationType type, | 72 virtual void Observe(NotificationType type, |
| 142 const NotificationSource& source, | 73 const NotificationSource& source, |
| 143 const NotificationDetails& details) { | 74 const NotificationDetails& details) { |
| 144 // Try to record event now, else set the flag to try later when we | 75 // Try to record event now, else set the flag to try later when we |
| 145 // attempt the ping. | 76 // attempt the ping. |
| 146 if (!RLZTracker::RecordProductEvent(RLZTracker::CHROME, | 77 if (!RLZTracker::RecordProductEvent(rlz_lib::CHROME, |
| 147 RLZTracker::CHROME_OMNIBOX, | 78 rlz_lib::CHROME_OMNIBOX, |
| 148 RLZTracker::FIRST_SEARCH)) | 79 rlz_lib::FIRST_SEARCH)) |
| 149 omnibox_used_ = true; | 80 omnibox_used_ = true; |
| 150 delete this; | 81 delete this; |
| 151 } | 82 } |
| 152 | 83 |
| 153 static bool used() { | 84 static bool used() { |
| 154 return omnibox_used_; | 85 return omnibox_used_; |
| 155 } | 86 } |
| 156 | 87 |
| 157 // Deletes the single instance of OmniBoxUsageObserver. | 88 // Deletes the single instance of OmniBoxUsageObserver. |
| 158 static void DeleteInstance() { | 89 static void DeleteInstance() { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 // Causes a ping to the server using WinInet. | 126 // Causes a ping to the server using WinInet. |
| 196 static void _cdecl PingNow(void*) { | 127 static void _cdecl PingNow(void*) { |
| 197 std::wstring lang; | 128 std::wstring lang; |
| 198 GoogleUpdateSettings::GetLanguage(&lang); | 129 GoogleUpdateSettings::GetLanguage(&lang); |
| 199 if (lang.empty()) | 130 if (lang.empty()) |
| 200 lang = L"en"; | 131 lang = L"en"; |
| 201 std::wstring brand; | 132 std::wstring brand; |
| 202 GoogleUpdateSettings::GetBrand(&brand); | 133 GoogleUpdateSettings::GetBrand(&brand); |
| 203 std::wstring referral; | 134 std::wstring referral; |
| 204 GoogleUpdateSettings::GetReferral(&referral); | 135 GoogleUpdateSettings::GetReferral(&referral); |
| 205 if (SendFinancialPing(brand.c_str(), lang.c_str(), referral.c_str(), | 136 if (SendFinancialPing(brand, lang, referral, is_organic(brand))) { |
| 206 is_organic(brand))) { | |
| 207 access_values_state = ACCESS_VALUES_STALE; | 137 access_values_state = ACCESS_VALUES_STALE; |
| 208 GoogleUpdateSettings::ClearReferral(); | 138 GoogleUpdateSettings::ClearReferral(); |
| 209 } | 139 } |
| 210 } | 140 } |
| 211 | 141 |
| 212 // Organic brands all start with GG, such as GGCM. | 142 // Organic brands all start with GG, such as GGCM. |
| 213 static bool is_organic(const std::wstring& brand) { | 143 static bool is_organic(const std::wstring& brand) { |
| 214 return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG"); | 144 return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG"); |
| 215 } | 145 } |
| 216 }; | 146 }; |
| 217 | 147 |
| 218 // Performs late RLZ initialization and RLZ event recording for chrome. | 148 // Performs late RLZ initialization and RLZ event recording for chrome. |
| 219 // This task needs to run on the UI thread. | 149 // This task needs to run on the UI thread. |
| 220 class DelayedInitTask : public Task { | 150 class DelayedInitTask : public Task { |
| 221 public: | 151 public: |
| 222 explicit DelayedInitTask(int directory_key, bool first_run) | 152 explicit DelayedInitTask(bool first_run) |
| 223 : directory_key_(directory_key), first_run_(first_run) { | 153 : first_run_(first_run) { |
| 224 } | 154 } |
| 225 virtual ~DelayedInitTask() { | 155 virtual ~DelayedInitTask() { |
| 226 } | 156 } |
| 227 virtual void Run() { | 157 virtual void Run() { |
| 228 // For non-interactive tests we don't do the rest of the initialization | 158 // For non-interactive tests we don't do the rest of the initialization |
| 229 // because sometimes the very act of loading the dll causes QEMU to crash. | 159 // because sometimes the very act of loading the dll causes QEMU to crash. |
| 230 if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(), | 160 if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(), |
| 231 NULL, 0)) { | 161 NULL, 0)) { |
| 232 return; | 162 return; |
| 233 } | 163 } |
| 234 // For organic brandcodes do not use rlz at all. Empty brandcode usually | 164 // For organic brandcodes do not use rlz at all. Empty brandcode usually |
| 235 // means a chromium install. This is ok. | 165 // means a chromium install. This is ok. |
| 236 std::wstring brand; | 166 std::wstring brand; |
| 237 GoogleUpdateSettings::GetBrand(&brand); | 167 GoogleUpdateSettings::GetBrand(&brand); |
| 238 if (is_strict_organic(brand)) | 168 if (is_strict_organic(brand)) |
| 239 return; | 169 return; |
| 240 | 170 |
| 241 if (!LoadRLZLibrary(directory_key_)) | |
| 242 return; | |
| 243 // Do the initial event recording if is the first run or if we have an | 171 // Do the initial event recording if is the first run or if we have an |
| 244 // empty rlz which means we haven't got a chance to do it. | 172 // empty rlz which means we haven't got a chance to do it. |
| 245 std::wstring omnibox_rlz; | 173 std::wstring omnibox_rlz; |
| 246 RLZTracker::GetAccessPointRlz(RLZTracker::CHROME_OMNIBOX, &omnibox_rlz); | 174 RLZTracker::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, &omnibox_rlz); |
| 247 | 175 |
| 248 if (first_run_ || omnibox_rlz.empty()) { | 176 if (first_run_ || omnibox_rlz.empty()) { |
| 249 // Record the installation of chrome. | 177 // Record the installation of chrome. |
| 250 RLZTracker::RecordProductEvent(RLZTracker::CHROME, | 178 RLZTracker::RecordProductEvent(rlz_lib::CHROME, |
| 251 RLZTracker::CHROME_OMNIBOX, | 179 rlz_lib::CHROME_OMNIBOX, |
| 252 RLZTracker::INSTALL); | 180 rlz_lib::INSTALL); |
| 253 RLZTracker::RecordProductEvent(RLZTracker::CHROME, | 181 RLZTracker::RecordProductEvent(rlz_lib::CHROME, |
| 254 RLZTracker::CHROME_HOME_PAGE, | 182 rlz_lib::CHROME_HOME_PAGE, |
| 255 RLZTracker::INSTALL); | 183 rlz_lib::INSTALL); |
| 256 // Record if google is the initial search provider. | 184 // Record if google is the initial search provider. |
| 257 if (IsGoogleDefaultSearch()) { | 185 if (IsGoogleDefaultSearch()) { |
| 258 RLZTracker::RecordProductEvent(RLZTracker::CHROME, | 186 RLZTracker::RecordProductEvent(rlz_lib::CHROME, |
| 259 RLZTracker::CHROME_OMNIBOX, | 187 rlz_lib::CHROME_OMNIBOX, |
| 260 RLZTracker::SET_TO_GOOGLE); | 188 rlz_lib::SET_TO_GOOGLE); |
| 261 } | 189 } |
| 262 } | 190 } |
| 263 // Record first user interaction with the omnibox. We call this all the | 191 // Record first user interaction with the omnibox. We call this all the |
| 264 // time but the rlz lib should ingore all but the first one. | 192 // time but the rlz lib should ingore all but the first one. |
| 265 if (OmniBoxUsageObserver::used()) { | 193 if (OmniBoxUsageObserver::used()) { |
| 266 RLZTracker::RecordProductEvent(RLZTracker::CHROME, | 194 RLZTracker::RecordProductEvent(rlz_lib::CHROME, |
| 267 RLZTracker::CHROME_OMNIBOX, | 195 rlz_lib::CHROME_OMNIBOX, |
| 268 RLZTracker::FIRST_SEARCH); | 196 rlz_lib::FIRST_SEARCH); |
| 269 } | 197 } |
| 270 // Schedule the daily RLZ ping. | 198 // Schedule the daily RLZ ping. |
| 271 base::Thread* thread = g_browser_process->file_thread(); | 199 base::Thread* thread = g_browser_process->file_thread(); |
| 272 if (thread) | 200 if (thread) |
| 273 thread->message_loop()->PostTask(FROM_HERE, new DailyPingTask()); | 201 thread->message_loop()->PostTask(FROM_HERE, new DailyPingTask()); |
| 274 } | 202 } |
| 275 | 203 |
| 276 private: | 204 private: |
| 277 bool IsGoogleDefaultSearch() { | 205 bool IsGoogleDefaultSearch() { |
| 278 if (!g_browser_process) | 206 if (!g_browser_process) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 305 const wchar_t** end = &kBrands[arraysize(kBrands)]; | 233 const wchar_t** end = &kBrands[arraysize(kBrands)]; |
| 306 const wchar_t** found = std::find(&kBrands[0], end, brand); | 234 const wchar_t** found = std::find(&kBrands[0], end, brand); |
| 307 if (found != end) | 235 if (found != end) |
| 308 return true; | 236 return true; |
| 309 if (StartsWith(brand, L"EUB", true) || StartsWith(brand, L"EUC", true) || | 237 if (StartsWith(brand, L"EUB", true) || StartsWith(brand, L"EUC", true) || |
| 310 StartsWith(brand, L"GGR", true)) | 238 StartsWith(brand, L"GGR", true)) |
| 311 return true; | 239 return true; |
| 312 return false; | 240 return false; |
| 313 } | 241 } |
| 314 | 242 |
| 315 int directory_key_; | |
| 316 bool first_run_; | 243 bool first_run_; |
| 317 DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask); | 244 DISALLOW_IMPLICIT_CONSTRUCTORS(DelayedInitTask); |
| 318 }; | 245 }; |
| 319 | 246 |
| 320 } // namespace | 247 } // namespace |
| 321 | 248 |
| 322 bool RLZTracker::InitRlz(int directory_key) { | 249 bool RLZTracker::InitRlzDelayed(bool first_run, int delay) { |
| 323 return LoadRLZLibrary(directory_key); | |
| 324 } | |
| 325 | |
| 326 bool RLZTracker::InitRlzDelayed(int directory_key, bool first_run, int delay) { | |
| 327 // Maximum and minimum delay we would allow to be set through master | 250 // Maximum and minimum delay we would allow to be set through master |
| 328 // preferences. Somewhat arbitrary, may need to be adjusted in future. | 251 // preferences. Somewhat arbitrary, may need to be adjusted in future. |
| 329 const int kMaxDelay = 200 * 1000; | 252 const int kMaxDelay = 200 * 1000; |
| 330 const int kMinDelay = 20 * 1000; | 253 const int kMinDelay = 20 * 1000; |
| 331 | 254 |
| 332 delay *= 1000; | 255 delay *= 1000; |
| 333 delay = (delay < kMinDelay) ? kMinDelay : delay; | 256 delay = (delay < kMinDelay) ? kMinDelay : delay; |
| 334 delay = (delay > kMaxDelay) ? kMaxDelay : delay; | 257 delay = (delay > kMaxDelay) ? kMaxDelay : delay; |
| 335 | 258 |
| 336 if (!OmniBoxUsageObserver::used()) | 259 if (!OmniBoxUsageObserver::used()) |
| 337 new OmniBoxUsageObserver(); | 260 new OmniBoxUsageObserver(); |
| 338 | 261 |
| 339 // Schedule the delayed init items. | 262 // Schedule the delayed init items. |
| 340 MessageLoop::current()->PostDelayedTask(FROM_HERE, | 263 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
| 341 new DelayedInitTask(directory_key, first_run), delay); | 264 new DelayedInitTask(first_run), delay); |
| 342 return true; | 265 return true; |
| 343 } | 266 } |
| 344 | 267 |
| 345 bool RLZTracker::RecordProductEvent(Product product, AccessPoint point, | 268 bool RLZTracker::RecordProductEvent(rlz_lib::Product product, |
| 346 Event event) { | 269 rlz_lib::AccessPoint point, |
| 347 return (record_event) ? record_event(product, point, event, NULL) : false; | 270 rlz_lib::Event event_id) { |
| 271 return rlz_lib::RecordProductEvent(product, point, event_id); |
| 348 } | 272 } |
| 349 | 273 |
| 350 bool RLZTracker::ClearAllProductEvents(Product product) { | 274 bool RLZTracker::ClearAllProductEvents(rlz_lib::Product product) { |
| 351 return (clear_all_events) ? clear_all_events(product, NULL) : false; | 275 return rlz_lib::ClearAllProductEvents(product); |
| 352 } | 276 } |
| 353 | 277 |
| 354 // We implement caching of the answer of get_access_point() if the request | 278 // We implement caching of the answer of get_access_point() if the request |
| 355 // is for CHROME_OMNIBOX. If we had a successful ping, then we update the | 279 // is for CHROME_OMNIBOX. If we had a successful ping, then we update the |
| 356 // cached value. | 280 // cached value. |
| 357 | 281 |
| 358 bool RLZTracker::GetAccessPointRlz(AccessPoint point, std::wstring* rlz) { | 282 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point, |
| 283 std::wstring* rlz) { |
| 359 static std::wstring cached_ommibox_rlz; | 284 static std::wstring cached_ommibox_rlz; |
| 360 if (!get_access_point) | 285 if ((rlz_lib::CHROME_OMNIBOX == point) && |
| 361 return false; | |
| 362 if ((CHROME_OMNIBOX == point) && | |
| 363 (access_values_state == ACCESS_VALUES_FRESH)) { | 286 (access_values_state == ACCESS_VALUES_FRESH)) { |
| 364 *rlz = cached_ommibox_rlz; | 287 *rlz = cached_ommibox_rlz; |
| 365 return true; | 288 return true; |
| 366 } | 289 } |
| 367 wchar_t str_rlz[kMaxRlzLength]; | 290 char str_rlz[kMaxRlzLength + 1]; |
| 368 if (!get_access_point(point, str_rlz, kMaxRlzLength, NULL)) | 291 if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL)) |
| 369 return false; | 292 return false; |
| 370 if (CHROME_OMNIBOX == point) { | 293 *rlz = ASCIIToWide(std::string(str_rlz)); |
| 294 if (rlz_lib::CHROME_OMNIBOX == point) { |
| 371 access_values_state = ACCESS_VALUES_FRESH; | 295 access_values_state = ACCESS_VALUES_FRESH; |
| 372 cached_ommibox_rlz.assign(str_rlz); | 296 cached_ommibox_rlz.assign(*rlz); |
| 373 } | 297 } |
| 374 *rlz = str_rlz; | |
| 375 return true; | 298 return true; |
| 376 } | 299 } |
| 377 | 300 |
| 378 // static | 301 // static |
| 379 void RLZTracker::CleanupRlz() { | 302 void RLZTracker::CleanupRlz() { |
| 380 OmniBoxUsageObserver::DeleteInstance(); | 303 OmniBoxUsageObserver::DeleteInstance(); |
| 381 } | 304 } |
| OLD | NEW |