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 #include "chrome/browser/extensions/activity_log.h" | 5 #include "chrome/browser/extensions/activity_log.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/json/json_string_value_serializer.h" | 9 #include "base/json/json_string_value_serializer.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
12 #include "base/threading/thread_checker.h" | 12 #include "base/threading/thread_checker.h" |
13 #include "chrome/browser/extensions/api_actions.h" | 13 #include "chrome/browser/extensions/api_actions.h" |
14 #include "chrome/browser/extensions/blocked_actions.h" | 14 #include "chrome/browser/extensions/blocked_actions.h" |
15 #include "chrome/browser/extensions/extension_service.h" | 15 #include "chrome/browser/extensions/extension_service.h" |
16 #include "chrome/browser/extensions/extension_system.h" | 16 #include "chrome/browser/extensions/extension_system.h" |
17 #include "chrome/common/chrome_constants.h" | 17 #include "chrome/common/chrome_constants.h" |
18 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" |
19 #include "chrome/common/extensions/extension.h" | 19 #include "chrome/common/extensions/extension.h" |
20 #include "content/public/browser/web_contents.h" | 20 #include "content/public/browser/web_contents.h" |
21 #include "googleurl/src/gurl.h" | 21 #include "googleurl/src/gurl.h" |
22 #include "sql/error_delegate_util.h" | 22 #include "sql/error_delegate_util.h" |
23 #include "third_party/re2/re2/re2.h" | 23 #include "third_party/re2/re2/re2.h" |
24 | 24 |
25 namespace { | 25 namespace { |
26 | 26 |
27 // Concatenate an API call with its arguments. | 27 // Concatenate arguments. |
28 std::string MakeCallSignature(const std::string& name, const ListValue* args) { | 28 std::string MakeArgList(const ListValue* args) { |
29 std::string call_signature = name + "("; | 29 std::string call_signature = ""; |
30 ListValue::const_iterator it = args->begin(); | 30 ListValue::const_iterator it = args->begin(); |
31 for (; it != args->end(); ++it) { | 31 for (; it != args->end(); ++it) { |
32 std::string arg; | 32 std::string arg; |
33 JSONStringValueSerializer serializer(&arg); | 33 JSONStringValueSerializer serializer(&arg); |
34 if (serializer.SerializeAndOmitBinaryValues(**it)) { | 34 if (serializer.SerializeAndOmitBinaryValues(**it)) { |
35 if (it != args->begin()) | 35 if (it != args->begin()) |
36 call_signature += ", "; | 36 call_signature += ", "; |
37 call_signature += arg; | 37 call_signature += arg; |
38 } | 38 } |
39 } | 39 } |
40 return call_signature; | |
41 } | |
42 | |
43 // Concatenate an API call with its arguments. | |
44 std::string MakeCallSignature(const std::string& name, const ListValue* args) { | |
45 std::string call_signature = name + "("; | |
46 call_signature += MakeArgList(args); | |
40 call_signature += ")"; | 47 call_signature += ")"; |
41 return call_signature; | 48 return call_signature; |
42 } | 49 } |
43 | 50 |
44 // Computes whether the activity log is enabled in this browser (controlled by | 51 // Computes whether the activity log is enabled in this browser (controlled by |
45 // command-line flags) and caches the value (which is assumed never to change). | 52 // command-line flags) and caches the value (which is assumed never to change). |
46 class LogIsEnabled { | 53 class LogIsEnabled { |
47 public: | 54 public: |
48 LogIsEnabled() { | 55 LogIsEnabled() { |
49 ComputeIsEnabled(); | 56 ComputeIsEnabled(); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
160 } | 167 } |
161 | 168 |
162 // static | 169 // static |
163 ActivityLog* ActivityLog::GetInstance(Profile* profile) { | 170 ActivityLog* ActivityLog::GetInstance(Profile* profile) { |
164 return ActivityLogFactory::GetForProfile(profile); | 171 return ActivityLogFactory::GetForProfile(profile); |
165 } | 172 } |
166 | 173 |
167 void ActivityLog::AddObserver(const Extension* extension, | 174 void ActivityLog::AddObserver(const Extension* extension, |
168 ActivityLog::Observer* observer) { | 175 ActivityLog::Observer* observer) { |
169 if (!IsLogEnabled()) return; | 176 if (!IsLogEnabled()) return; |
170 if (observers_.count(extension) == 0) { | 177 if (observers_.count(extension) == 0) |
171 observers_[extension] = new ObserverListThreadSafe<Observer>; | 178 observers_[extension] = new ObserverListThreadSafe<Observer>; |
172 } | |
173 observers_[extension]->AddObserver(observer); | 179 observers_[extension]->AddObserver(observer); |
174 } | 180 } |
175 | 181 |
176 void ActivityLog::RemoveObserver(const Extension* extension, | 182 void ActivityLog::RemoveObserver(const Extension* extension, |
177 ActivityLog::Observer* observer) { | 183 ActivityLog::Observer* observer) { |
178 if (observers_.count(extension) == 1) { | 184 if (observers_.count(extension) == 1) |
179 observers_[extension]->RemoveObserver(observer); | 185 observers_[extension]->RemoveObserver(observer); |
180 } | |
181 } | 186 } |
182 | 187 |
183 void ActivityLog::LogAPIAction(const Extension* extension, | 188 void ActivityLog::LogAPIActionInternal(const Extension* extension, |
184 const std::string& name, | 189 const std::string& api_call, |
185 const ListValue* args, | 190 const ListValue* args, |
186 const std::string& extra) { | 191 const std::string& extra, |
187 if (!IsLogEnabled()) return; | 192 const APIAction::Type type) { |
188 std::string verb, manager; | 193 std::string verb, manager; |
189 bool matches = RE2::FullMatch(name, "(.*?)\\.(.*)", &manager, &verb); | 194 bool matches = RE2::FullMatch(api_call, "(.*?)\\.(.*)", &manager, &verb); |
190 if (matches) { | 195 if (matches) { |
191 std::string call_signature = MakeCallSignature(name, args); | |
192 scoped_refptr<APIAction> action = new APIAction( | 196 scoped_refptr<APIAction> action = new APIAction( |
193 extension->id(), | 197 extension->id(), |
194 base::Time::Now(), | 198 base::Time::Now(), |
195 APIAction::CALL, | 199 type, |
196 APIAction::StringAsVerb(verb), | 200 APIAction::StringAsVerb(verb), |
197 APIAction::StringAsTarget(manager), | 201 APIAction::StringAsTarget(manager), |
198 call_signature, | 202 api_call, |
203 MakeArgList(args), | |
199 extra); | 204 extra); |
200 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | 205 ScheduleAndForget(&ActivityDatabase::RecordAction, action); |
201 | 206 |
202 // Display the action. | 207 // Display the action. |
203 ObserverMap::const_iterator iter = observers_.find(extension); | 208 ObserverMap::const_iterator iter = observers_.find(extension); |
204 if (iter != observers_.end()) { | 209 if (iter != observers_.end()) { |
205 iter->second->Notify(&Observer::OnExtensionActivity, | 210 if (type == APIAction::CALL) { |
206 extension, | 211 iter->second->Notify(&Observer::OnExtensionActivity, |
207 ActivityLog::ACTIVITY_EXTENSION_API_CALL, | 212 extension, |
208 call_signature); | 213 ActivityLog::ACTIVITY_EXTENSION_API_CALL, |
209 } | 214 MakeCallSignature(api_call, args)); |
210 if (log_activity_to_stdout_) { | 215 } else if (type == APIAction::EVENT_CALLBACK) { |
211 LOG(INFO) << action->PrettyPrintForDebug(); | 216 iter->second->Notify(&Observer::OnExtensionActivity, |
212 } | 217 extension, |
213 } else { | 218 ActivityLog::ACTIVITY_EVENT_DISPATCH, |
214 LOG(ERROR) << "Unknown API call! " << name; | 219 MakeCallSignature(api_call, args)); |
215 } | 220 } |
216 } | |
217 | |
218 void ActivityLog::LogEventAction(const Extension* extension, | |
219 const std::string& name, | |
220 const ListValue* args, | |
221 const std::string& extra) { | |
222 std::string verb, manager; | |
223 bool matches = RE2::FullMatch(name, "(.*?)\\.(.*)", &manager, &verb); | |
224 if (matches) { | |
225 std::string call_signature = MakeCallSignature(name, args); | |
226 scoped_refptr<APIAction> action = new APIAction( | |
227 extension->id(), | |
228 base::Time::Now(), | |
229 APIAction::EVENT_CALLBACK, | |
230 APIAction::StringAsVerb(verb), | |
231 APIAction::StringAsTarget(manager), | |
232 call_signature, | |
233 extra); | |
234 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | |
235 | |
236 // Display the action. | |
237 ObserverMap::const_iterator iter = observers_.find(extension); | |
238 if (iter != observers_.end()) { | |
239 iter->second->Notify(&Observer::OnExtensionActivity, | |
240 extension, | |
241 ActivityLog::ACTIVITY_EVENT_DISPATCH, | |
242 call_signature); | |
243 } | 221 } |
244 if (log_activity_to_stdout_) | 222 if (log_activity_to_stdout_) |
245 LOG(INFO) << action->PrettyPrintForDebug(); | 223 LOG(INFO) << action->PrettyPrintForDebug(); |
246 } else { | 224 } else { |
247 LOG(ERROR) << "Unknown event type! " << name; | 225 LOG(ERROR) << "Unknown API call! " << api_call; |
248 } | 226 } |
249 } | 227 } |
250 | 228 |
229 // A wrapper around LogAPIActionInternal, but we know it's an API call. | |
230 void ActivityLog::LogAPIAction(const Extension* extension, | |
231 const std::string& api_call, | |
232 const ListValue* args, | |
233 const std::string& extra) { | |
234 if (!IsLogEnabled()) return; | |
235 LogAPIActionInternal(extension, api_call, args, extra, APIAction::CALL); | |
236 } | |
237 | |
238 // A wrapper around LogAPIActionInternal, but we know it's actually an event | |
239 // being fired and triggering extension code. Having the two separate methods | |
240 // (LogAPIAction vs LogEventAction) lets us hide how we actually choose to | |
241 // handle them. Right now they're being handled almost the same. | |
242 void ActivityLog::LogEventAction(const Extension* extension, | |
243 const std::string& api_call, | |
244 const ListValue* args, | |
245 const std::string& extra) { | |
246 if (!IsLogEnabled()) return; | |
247 LogAPIActionInternal(extension, | |
248 api_call, | |
249 args, | |
250 extra, | |
251 APIAction::EVENT_CALLBACK); | |
252 } | |
253 | |
251 void ActivityLog::LogBlockedAction(const Extension* extension, | 254 void ActivityLog::LogBlockedAction(const Extension* extension, |
252 const std::string& blocked_name, | 255 const std::string& blocked_call, |
253 const ListValue* args, | 256 const ListValue* args, |
254 const char* reason, | 257 const char* reason, |
255 const std::string& extra) { | 258 const std::string& extra) { |
256 if (!IsLogEnabled()) return; | 259 if (!IsLogEnabled()) return; |
257 std::string blocked_call = MakeCallSignature(blocked_name, args); | |
258 scoped_refptr<BlockedAction> action = new BlockedAction(extension->id(), | 260 scoped_refptr<BlockedAction> action = new BlockedAction(extension->id(), |
259 base::Time::Now(), | 261 base::Time::Now(), |
260 blocked_call, | 262 blocked_call, |
263 MakeArgList(args), | |
261 std::string(reason), | 264 std::string(reason), |
262 extra); | 265 extra); |
263 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | 266 ScheduleAndForget(&ActivityDatabase::RecordAction, action); |
264 // Display the action. | 267 // Display the action. |
265 ObserverMap::const_iterator iter = observers_.find(extension); | 268 ObserverMap::const_iterator iter = observers_.find(extension); |
266 if (iter != observers_.end()) { | 269 if (iter != observers_.end()) { |
270 std::string blocked_str = MakeCallSignature(blocked_call, args); | |
267 iter->second->Notify(&Observer::OnExtensionActivity, | 271 iter->second->Notify(&Observer::OnExtensionActivity, |
268 extension, | 272 extension, |
269 ActivityLog::ACTIVITY_EXTENSION_API_BLOCK, | 273 ActivityLog::ACTIVITY_EXTENSION_API_BLOCK, |
270 blocked_call); | 274 blocked_str); |
271 } | 275 } |
272 if (log_activity_to_stdout_) | 276 if (log_activity_to_stdout_) |
273 LOG(INFO) << action->PrettyPrintForDebug(); | 277 LOG(INFO) << action->PrettyPrintForDebug(); |
274 } | 278 } |
275 | 279 |
276 void ActivityLog::LogUrlAction(const Extension* extension, | 280 void ActivityLog::LogDOMActionInternal(const Extension* extension, |
277 const UrlAction::UrlActionType verb, | 281 const GURL& url, |
278 const GURL& url, | 282 const string16& url_title, |
279 const string16& url_title, | 283 const std::string& api_call, |
280 const std::string& technical_message, | 284 const ListValue* args, |
281 const std::string& extra) { | 285 const std::string& extra, |
282 if (!IsLogEnabled()) return; | 286 DOMAction::DOMActionType verb) { |
283 scoped_refptr<UrlAction> action = new UrlAction( | 287 scoped_refptr<DOMAction> action = new DOMAction( |
284 extension->id(), | 288 extension->id(), |
285 base::Time::Now(), | 289 base::Time::Now(), |
286 verb, | 290 verb, |
287 url, | 291 url, |
288 url_title, | 292 url_title, |
289 technical_message, | 293 api_call, |
290 extra); | 294 MakeArgList(args), |
295 extra); | |
291 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | 296 ScheduleAndForget(&ActivityDatabase::RecordAction, action); |
292 | 297 |
293 // Display the action. | 298 // Display the action. |
294 ObserverMap::const_iterator iter = observers_.find(extension); | 299 ObserverMap::const_iterator iter = observers_.find(extension); |
295 if (iter != observers_.end()) { | 300 if (iter != observers_.end()) { |
296 iter->second->Notify(&Observer::OnExtensionActivity, | 301 // This is a kludge, planning to update this when new UI is in place. |
Matt Perry
2013/02/12 22:01:26
nit: add TODO(felt):
| |
297 extension, | 302 if (verb == DOMAction::INSERTED) { |
298 ActivityLog::ACTIVITY_CONTENT_SCRIPT, | 303 iter->second->Notify(&Observer::OnExtensionActivity, |
299 action->PrettyPrintForDebug()); | 304 extension, |
305 ActivityLog::ACTIVITY_CONTENT_SCRIPT, | |
306 action->PrettyPrintForDebug()); | |
307 } else { | |
308 iter->second->Notify(&Observer::OnExtensionActivity, | |
309 extension, | |
310 ActivityLog::ACTIVITY_CONTENT_SCRIPT, | |
311 MakeCallSignature(api_call, args)); | |
312 } | |
300 } | 313 } |
301 if (log_activity_to_stdout_) | 314 if (log_activity_to_stdout_) |
302 LOG(INFO) << action->PrettyPrintForDebug(); | 315 LOG(INFO) << action->PrettyPrintForDebug(); |
303 } | 316 } |
304 | 317 |
318 void ActivityLog::LogDOMAction(const Extension* extension, | |
319 const GURL& url, | |
320 const string16& url_title, | |
321 const std::string& api_call, | |
322 const ListValue* args, | |
323 const std::string& extra) { | |
324 if (!IsLogEnabled()) return; | |
325 LogDOMActionInternal(extension, | |
326 url, | |
327 url_title, | |
328 api_call, | |
329 args, | |
330 extra, | |
331 DOMAction::MODIFIED); | |
332 } | |
333 | |
305 void ActivityLog::OnScriptsExecuted( | 334 void ActivityLog::OnScriptsExecuted( |
306 const content::WebContents* web_contents, | 335 const content::WebContents* web_contents, |
307 const ExecutingScriptsMap& extension_ids, | 336 const ExecutingScriptsMap& extension_ids, |
308 int32 on_page_id, | 337 int32 on_page_id, |
309 const GURL& on_url) { | 338 const GURL& on_url) { |
310 if (!IsLogEnabled()) return; | 339 if (!IsLogEnabled()) return; |
311 Profile* profile = | 340 Profile* profile = |
312 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 341 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
313 const ExtensionService* extension_service = | 342 const ExtensionService* extension_service = |
314 ExtensionSystem::Get(profile)->extension_service(); | 343 ExtensionSystem::Get(profile)->extension_service(); |
315 const ExtensionSet* extensions = extension_service->extensions(); | 344 const ExtensionSet* extensions = extension_service->extensions(); |
316 | 345 |
317 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin(); | 346 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin(); |
318 it != extension_ids.end(); ++it) { | 347 it != extension_ids.end(); ++it) { |
319 const Extension* extension = extensions->GetByID(it->first); | 348 const Extension* extension = extensions->GetByID(it->first); |
320 if (!extension) | 349 if (!extension) |
321 continue; | 350 continue; |
322 | 351 |
323 // If OnScriptsExecuted is fired because of tabs.executeScript, the list | 352 // If OnScriptsExecuted is fired because of tabs.executeScript, the list |
324 // of content scripts will be empty. We don't want to log it because | 353 // of content scripts will be empty. We don't want to log it because |
325 // the call to tabs.executeScript will have already been logged anyway. | 354 // the call to tabs.executeScript will have already been logged anyway. |
326 if (!it->second.empty()) { | 355 if (!it->second.empty()) { |
327 std::string ext_scripts_str = ""; | 356 std::string ext_scripts_str = ""; |
328 for (std::set<std::string>::const_iterator it2 = it->second.begin(); | 357 for (std::set<std::string>::const_iterator it2 = it->second.begin(); |
329 it2 != it->second.end(); ++it2) { | 358 it2 != it->second.end(); ++it2) { |
330 ext_scripts_str += *it2; | 359 ext_scripts_str += *it2; |
331 ext_scripts_str += " "; | 360 ext_scripts_str += " "; |
332 } | 361 } |
333 LogUrlAction(extension, | 362 scoped_ptr<ListValue> script_names(new ListValue()); |
334 UrlAction::INSERTED, | 363 script_names->Set(0, new StringValue(ext_scripts_str)); |
335 on_url, | 364 LogDOMActionInternal(extension, |
336 web_contents->GetTitle(), | 365 on_url, |
337 ext_scripts_str, | 366 web_contents->GetTitle(), |
338 ""); | 367 "", // no api call here |
368 script_names.get(), | |
369 "", // no extras either | |
370 DOMAction::INSERTED); | |
339 } | 371 } |
340 } | 372 } |
341 } | 373 } |
342 | 374 |
343 void ActivityLog::KillActivityLogDatabase() { | 375 void ActivityLog::KillActivityLogDatabase() { |
344 if (db_.get()) { | 376 if (db_.get()) { |
345 ScheduleAndForget(&ActivityDatabase::KillDatabase); | 377 ScheduleAndForget(&ActivityDatabase::KillDatabase); |
346 } | 378 } |
347 } | 379 } |
348 | 380 |
349 // static | 381 // static |
350 const char* ActivityLog::ActivityToString(Activity activity) { | 382 const char* ActivityLog::ActivityToString(Activity activity) { |
351 switch (activity) { | 383 switch (activity) { |
352 case ActivityLog::ACTIVITY_EXTENSION_API_CALL: | 384 case ActivityLog::ACTIVITY_EXTENSION_API_CALL: |
353 return "api_call"; | 385 return "api_call"; |
354 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK: | 386 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK: |
355 return "api_block"; | 387 return "api_block"; |
356 case ActivityLog::ACTIVITY_CONTENT_SCRIPT: | 388 case ActivityLog::ACTIVITY_CONTENT_SCRIPT: |
357 return "content_script"; | 389 return "content_script"; |
358 case ActivityLog::ACTIVITY_EVENT_DISPATCH: | 390 case ActivityLog::ACTIVITY_EVENT_DISPATCH: |
359 return "event_dispatch"; | 391 return "event_dispatch"; |
360 default: | 392 default: |
361 NOTREACHED(); | 393 NOTREACHED(); |
362 return ""; | 394 return ""; |
363 } | 395 } |
364 } | 396 } |
365 | 397 |
366 } // namespace extensions | 398 } // namespace extensions |
OLD | NEW |