OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 13 matching lines...) Expand all Loading... | |
24 #include "base/utf_string_conversions.h" | 24 #include "base/utf_string_conversions.h" |
25 #include "chrome/browser/browser_process.h" | 25 #include "chrome/browser/browser_process.h" |
26 #include "chrome/browser/search_engines/template_url.h" | 26 #include "chrome/browser/search_engines/template_url.h" |
27 #include "chrome/browser/search_engines/template_url_service.h" | 27 #include "chrome/browser/search_engines/template_url_service.h" |
28 #include "chrome/browser/search_engines/template_url_service_factory.h" | 28 #include "chrome/browser/search_engines/template_url_service_factory.h" |
29 #include "chrome/common/chrome_notification_types.h" | 29 #include "chrome/common/chrome_notification_types.h" |
30 #include "chrome/common/chrome_paths.h" | 30 #include "chrome/common/chrome_paths.h" |
31 #include "chrome/common/env_vars.h" | 31 #include "chrome/common/env_vars.h" |
32 #include "chrome/installer/util/google_update_settings.h" | 32 #include "chrome/installer/util/google_update_settings.h" |
33 #include "content/browser/browser_thread.h" | 33 #include "content/browser/browser_thread.h" |
34 #include "content/common/notification_registrar.h" | 34 #include "content/browser/tab_contents/navigation_entry.h" |
35 #include "content/common/notification_service.h" | 35 #include "content/common/notification_service.h" |
36 | 36 |
37 namespace { | 37 namespace { |
38 | 38 |
39 enum { | 39 // Organic brands all start with GG, such as GGCM. |
40 ACCESS_VALUES_STALE, // Possibly new values available. | 40 static bool is_organic(const std::wstring& brand) { |
41 ACCESS_VALUES_FRESH // The cached values are current. | 41 return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG"); |
42 }; | 42 } |
43 | 43 |
44 // Tracks if we have tried and succeeded sending the ping. This helps us | 44 void RecordProductEvents(bool first_run, bool google_default_search, |
45 // decide if we need to refresh the cached RLZ string. | 45 bool google_default_homepage, bool already_ran, |
46 volatile int access_values_state = ACCESS_VALUES_STALE; | 46 bool omnibox_used, bool homepage_used) { |
47 base::Lock rlz_lock; | 47 // Record the installation of chrome. We call this all the time but the rlz |
48 // lib should ingore all but the first one. | |
49 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
50 rlz_lib::CHROME_OMNIBOX, | |
51 rlz_lib::INSTALL); | |
52 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
53 rlz_lib::CHROME_HOME_PAGE, | |
54 rlz_lib::INSTALL); | |
48 | 55 |
49 bool SendFinancialPing(const std::wstring& brand, const std::wstring& lang, | 56 if (!already_ran) { |
50 const std::wstring& referral, bool exclude_id) { | 57 // Do the initial event recording if is the first run or if we have an |
58 // empty rlz which means we haven't got a chance to do it. | |
59 char omnibox_rlz[rlz_lib::kMaxRlzLength + 1]; | |
60 if (!rlz_lib::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, omnibox_rlz, | |
61 rlz_lib::kMaxRlzLength, NULL)) { | |
62 omnibox_rlz[0] = 0; | |
63 } | |
64 | |
65 // Record if google is the initial search provider and/or home page. | |
66 if ((first_run || omnibox_rlz[0] == 0) && google_default_search) { | |
67 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
68 rlz_lib::CHROME_OMNIBOX, | |
69 rlz_lib::SET_TO_GOOGLE); | |
70 } | |
71 | |
72 char homepage_rlz[rlz_lib::kMaxRlzLength + 1]; | |
73 if (!rlz_lib::GetAccessPointRlz(rlz_lib::CHROME_HOME_PAGE, homepage_rlz, | |
74 rlz_lib::kMaxRlzLength, NULL)) { | |
75 homepage_rlz[0] = 0; | |
76 } | |
77 | |
78 if ((first_run || homepage_rlz[0] == 0) && google_default_homepage) { | |
79 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
80 rlz_lib::CHROME_HOME_PAGE, | |
81 rlz_lib::SET_TO_GOOGLE); | |
82 } | |
83 } | |
84 | |
85 // Record first user interaction with the omnibox. We call this all the | |
86 // time but the rlz lib should ingore all but the first one. | |
87 if (omnibox_used) { | |
88 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
89 rlz_lib::CHROME_OMNIBOX, | |
90 rlz_lib::FIRST_SEARCH); | |
91 } | |
92 | |
93 // Record first user interaction with the home page. We call this all the | |
94 // time but the rlz lib should ingore all but the first one. | |
95 if (homepage_used) { | |
96 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
97 rlz_lib::CHROME_HOME_PAGE, | |
98 rlz_lib::FIRST_SEARCH); | |
99 } | |
100 } | |
101 | |
102 bool SendFinancialPing(const std::wstring& brand, | |
103 const std::wstring& lang, | |
104 const std::wstring& referral, | |
105 bool exclude_id) { | |
51 rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, | 106 rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, |
52 rlz_lib::CHROME_HOME_PAGE, | 107 rlz_lib::CHROME_HOME_PAGE, |
53 rlz_lib::NO_ACCESS_POINT}; | 108 rlz_lib::NO_ACCESS_POINT}; |
54 std::string brand_ascii(WideToASCII(brand)); | 109 std::string brand_ascii(WideToASCII(brand)); |
55 std::string lang_ascii(WideToASCII(lang)); | 110 std::string lang_ascii(WideToASCII(lang)); |
56 std::string referral_ascii(WideToASCII(referral)); | 111 std::string referral_ascii(WideToASCII(referral)); |
57 | 112 |
58 // If chrome has been reactivated, send a ping for this brand as well. | 113 // If chrome has been reactivated, send a ping for this brand as well. |
59 // We ignore the return value of SendFinancialPing() since we'll try again | 114 // We ignore the return value of SendFinancialPing() since we'll try again |
60 // later anyway. Callers of this function are only interested in whether | 115 // later anyway. Callers of this function are only interested in whether |
61 // the ping for the main brand succeeded or not. | 116 // the ping for the main brand succeeded or not. |
62 std::wstring reactivation_brand; | 117 std::wstring reactivation_brand; |
63 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { | 118 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { |
64 std::string reactivation_brand_ascii(WideToASCII(reactivation_brand)); | 119 std::string reactivation_brand_ascii(WideToASCII(reactivation_brand)); |
65 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 120 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
66 rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", | 121 rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", |
67 reactivation_brand_ascii.c_str(), | 122 reactivation_brand_ascii.c_str(), |
68 referral_ascii.c_str(), lang_ascii.c_str(), | 123 referral_ascii.c_str(), lang_ascii.c_str(), |
69 exclude_id, NULL, true); | 124 exclude_id, NULL, true); |
70 } | 125 } |
71 | 126 |
72 return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", | 127 return rlz_lib::SendFinancialPing(rlz_lib::CHROME, points, "chrome", |
73 brand_ascii.c_str(), referral_ascii.c_str(), | 128 brand_ascii.c_str(), referral_ascii.c_str(), |
74 lang_ascii.c_str(), exclude_id, NULL, true); | 129 lang_ascii.c_str(), exclude_id, NULL, true); |
75 } | 130 } |
76 | 131 |
77 // This class leverages the AutocompleteEditModel notification to know when | |
78 // the user first interacted with the omnibox and set a global accordingly. | |
79 class OmniBoxUsageObserver : public NotificationObserver { | |
80 public: | |
81 OmniBoxUsageObserver(bool first_run, bool send_ping_immediately, | |
82 bool google_default_search) | |
83 : first_run_(first_run), | |
84 send_ping_immediately_(send_ping_immediately), | |
85 google_default_search_(google_default_search) { | |
86 registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, | |
87 NotificationService::AllSources()); | |
88 // If instant is enabled we'll start searching as soon as the user starts | |
89 // typing in the omnibox (which triggers INSTANT_CONTROLLER_UPDATED). | |
90 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | |
91 NotificationService::AllSources()); | |
92 omnibox_used_ = false; | |
93 DCHECK(!instance_); | |
94 instance_ = this; | |
95 } | |
96 | |
97 virtual void Observe(int type, | |
98 const NotificationSource& source, | |
99 const NotificationDetails& details); | |
100 | |
101 static bool used() { | |
102 return omnibox_used_; | |
103 } | |
104 | |
105 // Deletes the single instance of OmniBoxUsageObserver. | |
106 static void DeleteInstance() { | |
107 delete instance_; | |
108 } | |
109 | |
110 private: | |
111 // Dtor is private so the object cannot be created on the stack. | |
112 ~OmniBoxUsageObserver() { | |
113 instance_ = NULL; | |
114 } | |
115 | |
116 static bool omnibox_used_; | |
117 | |
118 // There should only be one instance created at a time, and instance_ points | |
119 // to that instance. | |
120 // NOTE: this is only non-null for the amount of time it is needed. Once the | |
121 // instance_ is no longer needed (or Chrome is exiting), this is null. | |
122 static OmniBoxUsageObserver* instance_; | |
123 | |
124 NotificationRegistrar registrar_; | |
125 bool first_run_; | |
126 bool send_ping_immediately_; | |
127 bool google_default_search_; | |
128 }; | |
129 | |
130 bool OmniBoxUsageObserver::omnibox_used_ = false; | |
131 OmniBoxUsageObserver* OmniBoxUsageObserver::instance_ = NULL; | |
132 | |
133 // This task is run in the file thread, so to not block it for a long time | |
134 // we use a throwaway thread to do the blocking url request. | |
135 class DailyPingTask : public Task { | |
136 public: | |
137 virtual ~DailyPingTask() { | |
138 } | |
139 virtual void Run() { | |
140 // We use a transient thread because we have no guarantees about | |
141 // how long the RLZ lib can block us. | |
142 _beginthread(PingNow, 0, NULL); | |
143 } | |
144 | |
145 private: | |
146 // Causes a ping to the server using WinInet. | |
147 static void _cdecl PingNow(void*) { | |
148 // Needs to be evaluated. See http://crbug.com/62328. | |
149 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
150 | |
151 std::wstring lang; | |
152 GoogleUpdateSettings::GetLanguage(&lang); | |
153 if (lang.empty()) | |
154 lang = L"en"; | |
155 std::wstring brand; | |
156 GoogleUpdateSettings::GetBrand(&brand); | |
157 std::wstring referral; | |
158 GoogleUpdateSettings::GetReferral(&referral); | |
159 if (SendFinancialPing(brand, lang, referral, is_organic(brand))) { | |
160 base::AutoLock lock(rlz_lock); | |
161 access_values_state = ACCESS_VALUES_STALE; | |
162 GoogleUpdateSettings::ClearReferral(); | |
163 } | |
164 } | |
165 | |
166 // Organic brands all start with GG, such as GGCM. | |
167 static bool is_organic(const std::wstring& brand) { | |
168 return (brand.size() < 2) ? false : (brand.substr(0, 2) == L"GG"); | |
169 } | |
170 }; | |
171 | |
172 // Performs late RLZ initialization and RLZ event recording for chrome. | |
173 // This task needs to run on the UI thread. | |
174 class DelayedInitTask : public Task { | |
175 public: | |
176 DelayedInitTask(bool first_run, bool google_default_search) | |
177 : first_run_(first_run), | |
178 google_default_search_(google_default_search) { | |
179 } | |
180 virtual ~DelayedInitTask() { | |
181 } | |
182 virtual void Run() { | |
183 // For non-interactive tests we don't do the rest of the initialization | |
184 // because sometimes the very act of loading the dll causes QEMU to crash. | |
185 if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(), | |
186 NULL, 0)) { | |
187 return; | |
188 } | |
189 // For organic brandcodes do not use rlz at all. Empty brandcode usually | |
190 // means a chromium install. This is ok. | |
191 std::wstring brand; | |
192 if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() || | |
193 GoogleUpdateSettings::IsOrganic(brand)) | |
194 return; | |
195 | |
196 RecordProductEvents(first_run_, google_default_search_, already_ran_); | |
197 | |
198 // If chrome has been reactivated, record the events for this brand | |
199 // as well. | |
200 std::wstring reactivation_brand; | |
201 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { | |
202 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | |
203 RecordProductEvents(first_run_, google_default_search_, already_ran_); | |
204 } | |
205 | |
206 already_ran_ = true; | |
207 | |
208 // Schedule the daily RLZ ping. | |
209 MessageLoop::current()->PostTask(FROM_HERE, new DailyPingTask()); | |
210 } | |
211 | |
212 private: | |
213 static void RecordProductEvents(bool first_run, bool google_default_search, | |
214 bool already_ran) { | |
215 // Record the installation of chrome. We call this all the time but the rlz | |
216 // lib should ingore all but the first one. | |
217 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
218 rlz_lib::CHROME_OMNIBOX, | |
219 rlz_lib::INSTALL); | |
220 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
221 rlz_lib::CHROME_HOME_PAGE, | |
222 rlz_lib::INSTALL); | |
223 | |
224 // Do the initial event recording if is the first run or if we have an | |
225 // empty rlz which means we haven't got a chance to do it. | |
226 char omnibox_rlz[rlz_lib::kMaxRlzLength + 1]; | |
227 if (!rlz_lib::GetAccessPointRlz(rlz_lib::CHROME_OMNIBOX, omnibox_rlz, | |
228 rlz_lib::kMaxRlzLength, NULL)) { | |
229 omnibox_rlz[0] = 0; | |
230 } | |
231 | |
232 // Record if google is the initial search provider. | |
233 if ((first_run || omnibox_rlz[0] == 0) && google_default_search && | |
234 !already_ran) { | |
235 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
236 rlz_lib::CHROME_OMNIBOX, | |
237 rlz_lib::SET_TO_GOOGLE); | |
238 } | |
239 | |
240 // Record first user interaction with the omnibox. We call this all the | |
241 // time but the rlz lib should ingore all but the first one. | |
242 if (OmniBoxUsageObserver::used()) { | |
243 rlz_lib::RecordProductEvent(rlz_lib::CHROME, | |
244 rlz_lib::CHROME_OMNIBOX, | |
245 rlz_lib::FIRST_SEARCH); | |
246 } | |
247 } | |
248 | |
249 // Flag that remembers if the delayed task already ran or not. This is | |
250 // needed only in the first_run case, since we don't want to record the | |
251 // set-to-google event more than once. We need to worry about this event | |
252 // (and not the others) because it is not a stateful RLZ event. | |
253 static bool already_ran_; | |
254 | |
255 bool first_run_; | |
256 | |
257 // True if Google is the default search engine for the first profile starting | |
258 // in a browser during first run. | |
259 bool google_default_search_; | |
260 | |
261 }; | |
262 | |
263 bool DelayedInitTask::already_ran_ = false; | |
264 | |
265 void OmniBoxUsageObserver::Observe(int type, | |
266 const NotificationSource& source, | |
267 const NotificationDetails& details) { | |
268 // Needs to be evaluated. See http://crbug.com/62328. | |
269 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
270 | |
271 // Try to record event now, else set the flag to try later when we | |
272 // attempt the ping. | |
273 if (!RLZTracker::RecordProductEvent(rlz_lib::CHROME, | |
274 rlz_lib::CHROME_OMNIBOX, | |
275 rlz_lib::FIRST_SEARCH)) | |
276 omnibox_used_ = true; | |
277 else if (send_ping_immediately_) { | |
278 BrowserThread::PostTask( | |
279 BrowserThread::FILE, FROM_HERE, new DelayedInitTask(first_run_, | |
280 google_default_search_)); | |
281 } | |
282 | |
283 delete this; | |
284 } | |
285 | |
286 } // namespace | 132 } // namespace |
287 | 133 |
134 RLZTracker* RLZTracker::tracker_ = NULL; | |
135 | |
136 // static | |
137 RLZTracker* RLZTracker::GetInstance() { | |
138 return tracker_ ? tracker_ : Singleton<RLZTracker>::get(); | |
139 } | |
140 | |
141 RLZTracker::RLZTracker() | |
142 : first_run_(false), | |
143 send_ping_immediately_(false), | |
144 google_default_search_(false), | |
145 already_ran_(false), | |
146 omnibox_used_(false), | |
147 homepage_used_(false) { | |
148 } | |
149 | |
150 RLZTracker::~RLZTracker() { | |
151 } | |
152 | |
288 bool RLZTracker::InitRlzDelayed(bool first_run, int delay, | 153 bool RLZTracker::InitRlzDelayed(bool first_run, int delay, |
289 bool google_default_search) { | 154 bool google_default_search, |
155 bool google_default_homepage) { | |
156 return GetInstance()->Init(first_run, delay, google_default_search, | |
157 google_default_homepage); | |
158 } | |
159 | |
160 bool RLZTracker::Init(bool first_run, int delay, bool google_default_search, | |
161 bool google_default_homepage) { | |
162 first_run_ = first_run; | |
163 google_default_search_ = google_default_search; | |
164 google_default_homepage_ = google_default_homepage; | |
165 | |
290 // A negative delay means that a financial ping should be sent immediately | 166 // A negative delay means that a financial ping should be sent immediately |
291 // after a first search is recorded, without waiting for the next restart | 167 // after a first search is recorded, without waiting for the next restart |
292 // of chrome. However, we only want this behaviour on first run. | 168 // of chrome. However, we only want this behaviour on first run. |
293 bool send_ping_immediately = false; | 169 send_ping_immediately_ = false; |
294 if (delay < 0) { | 170 if (delay < 0) { |
295 send_ping_immediately = true; | 171 send_ping_immediately_ = true; |
296 delay = -delay; | 172 delay = -delay; |
297 } | 173 } |
298 | 174 |
299 // Maximum and minimum delay we would allow to be set through master | 175 // Maximum and minimum delay we would allow to be set through master |
300 // preferences. Somewhat arbitrary, may need to be adjusted in future. | 176 // preferences. Somewhat arbitrary, may need to be adjusted in future. |
301 const int kMaxDelay = 200 * 1000; | 177 const int kMaxDelay = 200 * 1000; |
302 const int kMinDelay = 20 * 1000; | 178 const int kMinDelay = 20 * 1000; |
303 | 179 |
304 delay *= 1000; | 180 delay *= 1000; |
305 delay = (delay < kMinDelay) ? kMinDelay : delay; | 181 delay = (delay < kMinDelay) ? kMinDelay : delay; |
306 delay = (delay > kMaxDelay) ? kMaxDelay : delay; | 182 delay = (delay > kMaxDelay) ? kMaxDelay : delay; |
307 | 183 |
308 if (!OmniBoxUsageObserver::used()) | 184 // Register for notifications from the omnibox so that we can record when |
309 new OmniBoxUsageObserver(first_run, send_ping_immediately, | 185 // the user performs a first search. |
310 google_default_search); | 186 registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, |
311 | 187 NotificationService::AllSources()); |
312 // Schedule the delayed init items. | 188 // If instant is enabled we'll start searching as soon as the user starts |
189 // typing in the omnibox (which triggers INSTANT_CONTROLLER_UPDATED). | |
190 registrar_.Add(this, chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | |
191 NotificationService::AllSources()); | |
192 | |
193 // Register for notifications from navigations, to see if the user has used | |
194 // the home page. | |
195 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | |
196 NotificationService::AllSources()); | |
197 | |
198 ScheduleDelayedInit(delay); | |
199 return true; | |
200 } | |
201 | |
202 void RLZTracker::ScheduleDelayedInit(int delay) { | |
313 BrowserThread::PostDelayedTask( | 203 BrowserThread::PostDelayedTask( |
314 BrowserThread::FILE, | 204 BrowserThread::FILE, |
315 FROM_HERE, | 205 FROM_HERE, |
316 new DelayedInitTask(first_run, google_default_search), | 206 NewRunnableMethod(this, &RLZTracker::DelayedInit), |
317 delay); | 207 delay); |
318 return true; | 208 } |
209 | |
210 void RLZTracker::DelayedInit() { | |
211 // For non-interactive tests we don't do the rest of the initialization | |
212 // because sometimes the very act of loading the dll causes QEMU to crash. | |
cpu_(ooo_6.6-7.5)
2011/08/29 19:51:30
I don't think this is true anymore. I believe you
Roger Tawa OOO till Jul 10th
2011/08/30 03:26:42
Done.
| |
213 if (::GetEnvironmentVariableW(ASCIIToWide(env_vars::kHeadless).c_str(), | |
214 NULL, 0)) { | |
215 return; | |
216 } | |
217 | |
218 // For organic brandcodes do not use rlz at all. Empty brandcode usually | |
219 // means a chromium install. This is ok. | |
220 std::wstring brand; | |
221 if (!GoogleUpdateSettings::GetBrand(&brand) || brand.empty() || | |
222 GoogleUpdateSettings::IsOrganic(brand)) | |
223 return; | |
224 | |
225 RecordProductEvents(first_run_, google_default_search_, | |
226 google_default_homepage_, already_ran_, | |
227 omnibox_used_, homepage_used_); | |
228 | |
229 // If chrome has been reactivated, record the events for this brand | |
230 // as well. | |
231 std::wstring reactivation_brand; | |
232 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { | |
233 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | |
234 RecordProductEvents(first_run_, google_default_search_, | |
235 google_default_homepage_, already_ran_, | |
236 omnibox_used_, homepage_used_); | |
237 } | |
238 | |
239 already_ran_ = true; | |
240 | |
241 ScheduleFinancialPing(); | |
242 } | |
243 | |
244 void RLZTracker::ScheduleFinancialPing() { | |
245 _beginthread(PingNow, 0, this); | |
246 } | |
247 | |
248 // static | |
249 void _cdecl RLZTracker::PingNow(void* arg) { | |
250 RLZTracker* tracker = reinterpret_cast<RLZTracker*>(arg); | |
251 tracker->PingNowImpl(); | |
252 } | |
253 | |
254 void RLZTracker::PingNowImpl() { | |
255 // Needs to be evaluated. See http://crbug.com/62328. | |
256 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
257 | |
258 std::wstring lang; | |
259 GoogleUpdateSettings::GetLanguage(&lang); | |
260 if (lang.empty()) | |
261 lang = L"en"; | |
262 std::wstring brand; | |
263 GoogleUpdateSettings::GetBrand(&brand); | |
264 std::wstring referral; | |
265 GoogleUpdateSettings::GetReferral(&referral); | |
266 if (SendFinancialPing(brand, lang, referral, is_organic(brand))) { | |
267 GoogleUpdateSettings::ClearReferral(); | |
268 base::AutoLock lock(cache_lock_); | |
269 rlz_cache_.clear(); | |
270 } | |
271 } | |
272 | |
273 bool RLZTracker::SendFinancialPing(const std::wstring& brand, | |
274 const std::wstring& lang, | |
275 const std::wstring& referral, | |
276 bool exclude_id) { | |
277 return ::SendFinancialPing(brand, lang, referral, exclude_id); | |
278 } | |
279 | |
280 void RLZTracker::Observe(int type, | |
281 const NotificationSource& source, | |
282 const NotificationDetails& details) { | |
283 // Needs to be evaluated. See http://crbug.com/62328. | |
284 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
285 | |
286 rlz_lib::AccessPoint point; | |
287 bool* record_used = NULL; | |
288 bool call_record = false; | |
289 | |
290 switch (type) { | |
291 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: | |
292 case chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED: | |
293 point = rlz_lib::CHROME_OMNIBOX; | |
294 record_used = &omnibox_used_; | |
295 call_record = true; | |
296 | |
297 registrar_.Remove(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, | |
298 NotificationService::AllSources()); | |
299 registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | |
300 NotificationService::AllSources()); | |
301 break; | |
302 case content::NOTIFICATION_NAV_ENTRY_PENDING: { | |
303 const NavigationEntry* entry = Details<NavigationEntry>(details).ptr(); | |
304 if (entry != NULL && | |
305 ((entry->transition_type() & RLZ_PAGETRANSITION_HOME_PAGE) != 0)) { | |
306 point = rlz_lib::CHROME_HOME_PAGE; | |
307 record_used = &homepage_used_; | |
308 call_record = true; | |
309 | |
310 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING, | |
311 NotificationService::AllSources()); | |
312 } | |
313 break; | |
314 } | |
315 default: | |
316 NOTREACHED(); | |
317 break; | |
318 } | |
319 | |
320 if (call_record) { | |
321 // Try to record event now, else set the flag to try later when we | |
322 // attempt the ping. | |
323 if (!RecordProductEvent(rlz_lib::CHROME, point, rlz_lib::FIRST_SEARCH)) | |
324 *record_used = true; | |
325 else if (send_ping_immediately_ && point == rlz_lib::CHROME_OMNIBOX) { | |
326 ScheduleDelayedInit(0); | |
327 } | |
328 } | |
319 } | 329 } |
320 | 330 |
321 bool RLZTracker::RecordProductEvent(rlz_lib::Product product, | 331 bool RLZTracker::RecordProductEvent(rlz_lib::Product product, |
322 rlz_lib::AccessPoint point, | 332 rlz_lib::AccessPoint point, |
323 rlz_lib::Event event_id) { | 333 rlz_lib::Event event_id) { |
324 bool ret = rlz_lib::RecordProductEvent(product, point, event_id); | 334 bool ret = rlz_lib::RecordProductEvent(product, point, event_id); |
325 | 335 |
326 // If chrome has been reactivated, record the event for this brand as well. | 336 // If chrome has been reactivated, record the event for this brand as well. |
327 std::wstring reactivation_brand; | 337 std::wstring reactivation_brand; |
328 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { | 338 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand)) { |
329 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 339 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
330 ret &= rlz_lib::RecordProductEvent(product, point, event_id); | 340 ret &= rlz_lib::RecordProductEvent(product, point, event_id); |
331 } | 341 } |
332 | 342 |
333 return ret; | 343 return ret; |
334 } | 344 } |
335 | 345 |
336 // We implement caching of the answer of get_access_point() if the request | 346 // GetAccessPointRlz() caches RLZ strings for all access points. If we had |
337 // is for CHROME_OMNIBOX. If we had a successful ping, then we update the | 347 // a successful ping, then we update the cached value. |
338 // cached value. | |
339 | |
340 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point, | 348 bool RLZTracker::GetAccessPointRlz(rlz_lib::AccessPoint point, |
341 std::wstring* rlz) { | 349 std::wstring* rlz) { |
342 static std::wstring cached_ommibox_rlz; | 350 return GetInstance()->GetAccessPointRlzImpl(point, rlz); |
343 if (rlz_lib::CHROME_OMNIBOX == point) { | 351 } |
344 base::AutoLock lock(rlz_lock); | 352 |
345 if (access_values_state == ACCESS_VALUES_FRESH) { | 353 // GetAccessPointRlz() caches RLZ strings for all access points. If we had |
346 *rlz = cached_ommibox_rlz; | 354 // a successful ping, then we update the cached value. |
355 bool RLZTracker::GetAccessPointRlzImpl(rlz_lib::AccessPoint point, | |
356 std::wstring* rlz) { | |
357 // If the RLZ string for the specified access point is already cached, | |
358 // simply return its value. | |
359 { | |
360 base::AutoLock lock(cache_lock_); | |
361 if (rlz_cache_.find(point) != rlz_cache_.end()) { | |
362 if (rlz) | |
363 *rlz = rlz_cache_[point]; | |
347 return true; | 364 return true; |
348 } | 365 } |
349 } | 366 } |
350 | 367 |
351 // Make sure we don't access disk outside of the file context. | 368 // Make sure we don't access disk outside of the I/O thread. |
352 // In such case we repost the task on the right thread and return error. | 369 // In such case we repost the task on the right thread and return error. |
353 if (!BrowserThread::CurrentlyOn(BrowserThread::FILE)) { | 370 if (ScheduleGetAccessPointRlz(point)) |
354 // Caching of access points is now only implemented for the CHROME_OMNIBOX. | 371 return false; |
355 // Thus it is not possible to call this function on another thread for | |
356 // other access points until proper caching for these has been implemented | |
357 // and the code that calls this function can handle synchronous fetching | |
358 // of the access point. | |
359 DCHECK_EQ(rlz_lib::CHROME_OMNIBOX, point); | |
360 | |
361 BrowserThread::PostTask( | |
362 BrowserThread::FILE, FROM_HERE, | |
363 NewRunnableFunction(&RLZTracker::GetAccessPointRlz, | |
364 point, &cached_ommibox_rlz)); | |
365 rlz->erase(); | |
366 return false; | |
367 } | |
368 | 372 |
369 char str_rlz[rlz_lib::kMaxRlzLength + 1]; | 373 char str_rlz[rlz_lib::kMaxRlzLength + 1]; |
370 if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL)) | 374 if (!rlz_lib::GetAccessPointRlz(point, str_rlz, rlz_lib::kMaxRlzLength, NULL)) |
371 return false; | 375 return false; |
372 *rlz = ASCIIToWide(std::string(str_rlz)); | 376 |
373 if (rlz_lib::CHROME_OMNIBOX == point) { | 377 std::wstring rlz_local(ASCIIToWide(std::string(str_rlz))); |
374 base::AutoLock lock(rlz_lock); | 378 if (rlz) |
375 cached_ommibox_rlz.assign(*rlz); | 379 *rlz = rlz_local; |
376 access_values_state = ACCESS_VALUES_FRESH; | 380 |
377 } | 381 base::AutoLock lock(cache_lock_); |
382 rlz_cache_[point] = rlz_local; | |
383 return true; | |
384 } | |
385 | |
386 bool RLZTracker::ScheduleGetAccessPointRlz(rlz_lib::AccessPoint point) { | |
387 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) | |
388 return false; | |
389 | |
390 std::wstring* not_used = NULL; | |
391 BrowserThread::PostTask( | |
392 BrowserThread::FILE, FROM_HERE, | |
393 NewRunnableFunction(&RLZTracker::GetAccessPointRlz, point, not_used)); | |
378 return true; | 394 return true; |
379 } | 395 } |
380 | 396 |
381 // static | 397 // static |
382 void RLZTracker::CleanupRlz() { | 398 void RLZTracker::CleanupRlz() { |
383 OmniBoxUsageObserver::DeleteInstance(); | 399 GetInstance()->rlz_cache_.clear(); |
400 GetInstance()->registrar_.RemoveAll(); | |
384 } | 401 } |
OLD | NEW |