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 |