1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/activity_log/uma_policy.h"
7 #include "base/metrics/histogram.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
11 #include "chrome/browser/extensions/activity_log/ad_network_database.h"
12 #include "chrome/browser/sessions/session_id.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_list.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/common/url_constants.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/common/url_constants.h"
19 #include "extensions/common/dom_action_types.h"
21 namespace extensions
{
26 const int kNoStatus
= UmaPolicy::NONE
;
27 const int kContentScript
= 1 << UmaPolicy::CONTENT_SCRIPT
;
28 const int kReadDom
= 1 << UmaPolicy::READ_DOM
;
29 const int kModifiedDom
= 1 << UmaPolicy::MODIFIED_DOM
;
30 const int kDomMethod
= 1 << UmaPolicy::DOM_METHOD
;
31 const int kDocumentWrite
= 1 << UmaPolicy::DOCUMENT_WRITE
;
32 const int kInnerHtml
= 1 << UmaPolicy::INNER_HTML
;
33 const int kCreatedScript
= 1 << UmaPolicy::CREATED_SCRIPT
;
34 const int kCreatedIframe
= 1 << UmaPolicy::CREATED_IFRAME
;
35 const int kCreatedDiv
= 1 << UmaPolicy::CREATED_DIV
;
36 const int kCreatedLink
= 1 << UmaPolicy::CREATED_LINK
;
37 const int kCreatedInput
= 1 << UmaPolicy::CREATED_INPUT
;
38 const int kCreatedEmbed
= 1 << UmaPolicy::CREATED_EMBED
;
39 const int kCreatedObject
= 1 << UmaPolicy::CREATED_OBJECT
;
40 const int kAdInjected
= 1 << UmaPolicy::AD_INJECTED
;
41 const int kAdRemoved
= 1 << UmaPolicy::AD_REMOVED
;
42 const int kAdReplaced
= 1 << UmaPolicy::AD_REPLACED
;
46 // Class constants, also used in testing. --------------------------------------
48 const char UmaPolicy::kNumberOfTabs
[] = "num_tabs";
49 const size_t UmaPolicy::kMaxTabsTracked
= 50;
51 // Setup and shutdown. ---------------------------------------------------------
53 UmaPolicy::UmaPolicy(Profile
* profile
)
54 : ActivityLogPolicy(profile
), profile_(profile
) {
55 DCHECK(!profile
->IsOffTheRecord());
56 BrowserList::AddObserver(this);
59 UmaPolicy::~UmaPolicy() {
60 BrowserList::RemoveObserver(this);
63 // Unlike the other policies, UmaPolicy can commit suicide directly because it
64 // doesn't have a dependency on a database.
65 void UmaPolicy::Close() {
69 // Process actions. ------------------------------------------------------------
71 void UmaPolicy::ProcessAction(scoped_refptr
<Action
> action
) {
72 if (!action
->page_url().is_valid() && !action
->arg_url().is_valid())
74 if (action
->page_incognito() || action
->arg_incognito())
77 int status
= MatchActionToStatus(action
);
78 if (action
->page_url().is_valid()) {
79 url
= CleanURL(action
->page_url());
80 } else if (status
& kContentScript
) {
81 // This is for the tabs.executeScript case.
82 url
= CleanURL(action
->arg_url());
87 SiteMap::iterator site_lookup
= url_status_
.find(url
);
88 if (site_lookup
!= url_status_
.end())
89 site_lookup
->second
[action
->extension_id()] |= status
;
92 int UmaPolicy::MatchActionToStatus(scoped_refptr
<Action
> action
) {
93 if (action
->action_type() == Action::ACTION_CONTENT_SCRIPT
) {
94 return kContentScript
;
95 } else if (action
->action_type() == Action::ACTION_API_CALL
&&
96 action
->api_name() == "tabs.executeScript") {
97 return kContentScript
;
98 } else if (action
->action_type() != Action::ACTION_DOM_ACCESS
) {
103 if (!action
->other() ||
104 !action
->other()->GetIntegerWithoutPathExpansion(
105 activity_log_constants::kActionDomVerb
, &dom_verb
)) {
109 int ret_bit
= kNoStatus
;
110 DomActionType::Type dom_type
= static_cast<DomActionType::Type
>(dom_verb
);
111 if (dom_type
== DomActionType::GETTER
)
113 if (dom_type
== DomActionType::SETTER
) {
114 ret_bit
|= kModifiedDom
;
115 } else if (dom_type
== DomActionType::METHOD
) {
116 ret_bit
|= kDomMethod
;
121 if (action
->api_name() == "HTMLDocument.write" ||
122 action
->api_name() == "HTMLDocument.writeln") {
123 ret_bit
|= kDocumentWrite
;
124 } else if (action
->api_name() == "Element.innerHTML") {
125 ret_bit
|= kInnerHtml
;
126 } else if (action
->api_name() == "Document.createElement") {
128 action
->args()->GetString(0, &arg
);
129 if (arg
== "script") {
130 ret_bit
|= kCreatedScript
;
131 } else if (arg
== "iframe") {
132 ret_bit
|= kCreatedIframe
;
133 } else if (arg
== "div") {
134 ret_bit
|= kCreatedDiv
;
135 } else if (arg
== "a") {
136 ret_bit
|= kCreatedLink
;
137 } else if (arg
== "input") {
138 ret_bit
|= kCreatedInput
;
139 } else if (arg
== "embed") {
140 ret_bit
|= kCreatedEmbed
;
141 } else if (arg
== "object") {
142 ret_bit
|= kCreatedObject
;
146 const Action::InjectionType ad_injection
=
147 action
->DidInjectAd(g_browser_process
->rappor_service());
148 switch (ad_injection
) {
149 case Action::INJECTION_NEW_AD
:
150 ret_bit
|= kAdInjected
;
152 case Action::INJECTION_REMOVED_AD
:
153 ret_bit
|= kAdRemoved
;
155 case Action::INJECTION_REPLACED_AD
:
156 ret_bit
|= kAdReplaced
;
158 case Action::NO_AD_INJECTION
:
160 case Action::NUM_INJECTION_TYPES
:
167 void UmaPolicy::HistogramOnClose(const std::string
& url
) {
168 // Let's try to avoid histogramming useless URLs.
169 if (url
.empty() || url
== content::kAboutBlankURL
||
170 url
== chrome::kChromeUINewTabURL
)
173 int statuses
[MAX_STATUS
- 1];
174 std::memset(statuses
, 0, sizeof(statuses
));
176 SiteMap::iterator site_lookup
= url_status_
.find(url
);
177 ExtensionMap exts
= site_lookup
->second
;
178 ExtensionMap::iterator ext_iter
;
179 for (ext_iter
= exts
.begin(); ext_iter
!= exts
.end(); ++ext_iter
) {
180 if (ext_iter
->first
== kNumberOfTabs
)
182 for (int i
= NONE
+ 1; i
< MAX_STATUS
; ++i
) {
183 if (ext_iter
->second
& (1 << i
))
188 std::string prefix
= "ExtensionActivity.";
189 if (GURL(url
).host() != "www.google.com") {
190 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CONTENT_SCRIPT
),
191 statuses
[CONTENT_SCRIPT
- 1]);
192 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(READ_DOM
),
193 statuses
[READ_DOM
- 1]);
194 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(MODIFIED_DOM
),
195 statuses
[MODIFIED_DOM
- 1]);
196 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(DOM_METHOD
),
197 statuses
[DOM_METHOD
- 1]);
198 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(DOCUMENT_WRITE
),
199 statuses
[DOCUMENT_WRITE
- 1]);
200 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(INNER_HTML
),
201 statuses
[INNER_HTML
- 1]);
202 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_SCRIPT
),
203 statuses
[CREATED_SCRIPT
- 1]);
204 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_IFRAME
),
205 statuses
[CREATED_IFRAME
- 1]);
206 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_DIV
),
207 statuses
[CREATED_DIV
- 1]);
208 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_LINK
),
209 statuses
[CREATED_LINK
- 1]);
210 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_INPUT
),
211 statuses
[CREATED_INPUT
- 1]);
212 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_EMBED
),
213 statuses
[CREATED_EMBED
- 1]);
214 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_OBJECT
),
215 statuses
[CREATED_OBJECT
- 1]);
216 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(AD_INJECTED
),
217 statuses
[AD_INJECTED
- 1]);
218 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(AD_REMOVED
),
219 statuses
[AD_REMOVED
- 1]);
220 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(AD_REPLACED
),
221 statuses
[AD_REPLACED
- 1]);
224 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CONTENT_SCRIPT
),
225 statuses
[CONTENT_SCRIPT
- 1]);
226 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(READ_DOM
),
227 statuses
[READ_DOM
- 1]);
228 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(MODIFIED_DOM
),
229 statuses
[MODIFIED_DOM
- 1]);
230 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(DOM_METHOD
),
231 statuses
[DOM_METHOD
- 1]);
232 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(DOCUMENT_WRITE
),
233 statuses
[DOCUMENT_WRITE
- 1]);
234 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(INNER_HTML
),
235 statuses
[INNER_HTML
- 1]);
236 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_SCRIPT
),
237 statuses
[CREATED_SCRIPT
- 1]);
238 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_IFRAME
),
239 statuses
[CREATED_IFRAME
- 1]);
240 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_DIV
),
241 statuses
[CREATED_DIV
- 1]);
242 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_LINK
),
243 statuses
[CREATED_LINK
- 1]);
244 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_INPUT
),
245 statuses
[CREATED_INPUT
- 1]);
246 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_EMBED
),
247 statuses
[CREATED_EMBED
- 1]);
248 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(CREATED_OBJECT
),
249 statuses
[CREATED_OBJECT
- 1]);
250 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(AD_INJECTED
),
251 statuses
[AD_INJECTED
- 1]);
252 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(AD_REMOVED
),
253 statuses
[AD_REMOVED
- 1]);
254 UMA_HISTOGRAM_COUNTS_100(prefix
+ GetHistogramName(AD_REPLACED
),
255 statuses
[AD_REPLACED
- 1]);
259 // Handle tab tracking. --------------------------------------------------------
261 void UmaPolicy::OnBrowserAdded(Browser
* browser
) {
262 if (!profile_
->IsSameProfile(browser
->profile()))
264 browser
->tab_strip_model()->AddObserver(this);
267 void UmaPolicy::OnBrowserRemoved(Browser
* browser
) {
268 if (!profile_
->IsSameProfile(browser
->profile()))
270 browser
->tab_strip_model()->RemoveObserver(this);
273 // Use the value from SessionID::IdForTab, *not* |index|. |index| will be
274 // duplicated across tabs in a session, whereas IdForTab uniquely identifies
276 void UmaPolicy::TabChangedAt(content::WebContents
* contents
,
278 TabChangeType change_type
) {
279 if (change_type
!= TabStripModelObserver::LOADING_ONLY
)
284 std::string url
= CleanURL(contents
->GetLastCommittedURL());
285 int32 tab_id
= SessionID::IdForTab(contents
);
287 std::map
<int32
, std::string
>::iterator tab_it
= tab_list_
.find(tab_id
);
289 // Ignore tabs that haven't changed status.
290 if (tab_it
!= tab_list_
.end() && tab_it
->second
== url
)
293 // Is this an existing tab whose URL has changed.
294 if (tab_it
!= tab_list_
.end()) {
295 CleanupClosedPage(tab_it
->second
);
296 tab_list_
.erase(tab_id
);
299 // Check that tab_list_ isn't over the kMaxTabsTracked budget.
300 if (tab_list_
.size() >= kMaxTabsTracked
)
303 // Set up the new entries.
304 tab_list_
[tab_id
] = url
;
305 SetupOpenedPage(url
);
308 // Use the value from SessionID::IdForTab, *not* |index|. |index| will be
309 // duplicated across tabs in a session, whereas IdForTab uniquely identifies
311 void UmaPolicy::TabClosingAt(TabStripModel
* tab_strip_model
,
312 content::WebContents
* contents
,
316 std::string url
= CleanURL(contents
->GetLastCommittedURL());
317 int32 tab_id
= SessionID::IdForTab(contents
);
318 std::map
<int, std::string
>::iterator tab_it
= tab_list_
.find(tab_id
);
319 if (tab_it
!= tab_list_
.end())
320 tab_list_
.erase(tab_id
);
322 CleanupClosedPage(url
);
325 void UmaPolicy::SetupOpenedPage(const std::string
& url
) {
326 url_status_
[url
][kNumberOfTabs
]++;
329 void UmaPolicy::CleanupClosedPage(const std::string
& url
) {
330 SiteMap::iterator old_site_lookup
= url_status_
.find(url
);
331 if (old_site_lookup
== url_status_
.end())
333 old_site_lookup
->second
[kNumberOfTabs
]--;
334 if (old_site_lookup
->second
[kNumberOfTabs
] == 0) {
335 HistogramOnClose(url
);
336 url_status_
.erase(url
);
340 // Helpers. --------------------------------------------------------------------
342 // We don't want to treat # ref navigations as if they were new pageloads.
343 // So we get rid of the ref if it has it.
344 // We convert to a string in the hopes that this is faster than Replacements.
345 std::string
UmaPolicy::CleanURL(const GURL
& gurl
) {
346 if (gurl
.spec().empty())
347 return GURL(content::kAboutBlankURL
).spec();
348 if (!gurl
.is_valid())
352 std::string port
= "";
354 port
= ":" + gurl
.port();
355 std::string query
= "";
356 if (gurl
.has_query())
357 query
= "?" + gurl
.query();
358 return base::StringPrintf("%s://%s%s%s%s",
359 gurl
.scheme().c_str(),
366 const char* UmaPolicy::GetHistogramName(PageStatus status
) {
369 return "ContentScript";
373 return "ModifiedDom";
375 return "InvokedDomMethod";
377 return "DocumentWrite";
381 return "CreatedScript";
383 return "CreatedIframe";
387 return "CreatedLink";
389 return "CreatedInput";
391 return "CreatedEmbed";
393 return "CreatedObject";
408 } // namespace extensions