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 // TODO(felt): This is a kludge, planning to update this when new |
297 extension, | 302 // UI is in place. |
298 ActivityLog::ACTIVITY_CONTENT_SCRIPT, | 303 if (verb == DOMAction::INSERTED) { |
299 action->PrettyPrintForDebug()); | 304 iter->second->Notify(&Observer::OnExtensionActivity, |
| 305 extension, |
| 306 ActivityLog::ACTIVITY_CONTENT_SCRIPT, |
| 307 action->PrettyPrintForDebug()); |
| 308 } else { |
| 309 iter->second->Notify(&Observer::OnExtensionActivity, |
| 310 extension, |
| 311 ActivityLog::ACTIVITY_CONTENT_SCRIPT, |
| 312 MakeCallSignature(api_call, args)); |
| 313 } |
300 } | 314 } |
301 if (log_activity_to_stdout_) | 315 if (log_activity_to_stdout_) |
302 LOG(INFO) << action->PrettyPrintForDebug(); | 316 LOG(INFO) << action->PrettyPrintForDebug(); |
303 } | 317 } |
304 | 318 |
| 319 void ActivityLog::LogDOMAction(const Extension* extension, |
| 320 const GURL& url, |
| 321 const string16& url_title, |
| 322 const std::string& api_call, |
| 323 const ListValue* args, |
| 324 const std::string& extra) { |
| 325 if (!IsLogEnabled()) return; |
| 326 LogDOMActionInternal(extension, |
| 327 url, |
| 328 url_title, |
| 329 api_call, |
| 330 args, |
| 331 extra, |
| 332 DOMAction::MODIFIED); |
| 333 } |
| 334 |
305 void ActivityLog::OnScriptsExecuted( | 335 void ActivityLog::OnScriptsExecuted( |
306 const content::WebContents* web_contents, | 336 const content::WebContents* web_contents, |
307 const ExecutingScriptsMap& extension_ids, | 337 const ExecutingScriptsMap& extension_ids, |
308 int32 on_page_id, | 338 int32 on_page_id, |
309 const GURL& on_url) { | 339 const GURL& on_url) { |
310 if (!IsLogEnabled()) return; | 340 if (!IsLogEnabled()) return; |
311 Profile* profile = | 341 Profile* profile = |
312 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 342 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
313 const ExtensionService* extension_service = | 343 const ExtensionService* extension_service = |
314 ExtensionSystem::Get(profile)->extension_service(); | 344 ExtensionSystem::Get(profile)->extension_service(); |
315 const ExtensionSet* extensions = extension_service->extensions(); | 345 const ExtensionSet* extensions = extension_service->extensions(); |
316 | 346 |
317 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin(); | 347 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin(); |
318 it != extension_ids.end(); ++it) { | 348 it != extension_ids.end(); ++it) { |
319 const Extension* extension = extensions->GetByID(it->first); | 349 const Extension* extension = extensions->GetByID(it->first); |
320 if (!extension) | 350 if (!extension) |
321 continue; | 351 continue; |
322 | 352 |
323 // If OnScriptsExecuted is fired because of tabs.executeScript, the list | 353 // 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 | 354 // 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. | 355 // the call to tabs.executeScript will have already been logged anyway. |
326 if (!it->second.empty()) { | 356 if (!it->second.empty()) { |
327 std::string ext_scripts_str = ""; | 357 std::string ext_scripts_str = ""; |
328 for (std::set<std::string>::const_iterator it2 = it->second.begin(); | 358 for (std::set<std::string>::const_iterator it2 = it->second.begin(); |
329 it2 != it->second.end(); ++it2) { | 359 it2 != it->second.end(); ++it2) { |
330 ext_scripts_str += *it2; | 360 ext_scripts_str += *it2; |
331 ext_scripts_str += " "; | 361 ext_scripts_str += " "; |
332 } | 362 } |
333 LogUrlAction(extension, | 363 scoped_ptr<ListValue> script_names(new ListValue()); |
334 UrlAction::INSERTED, | 364 script_names->Set(0, new StringValue(ext_scripts_str)); |
335 on_url, | 365 LogDOMActionInternal(extension, |
336 web_contents->GetTitle(), | 366 on_url, |
337 ext_scripts_str, | 367 web_contents->GetTitle(), |
338 ""); | 368 "", // no api call here |
| 369 script_names.get(), |
| 370 "", // no extras either |
| 371 DOMAction::INSERTED); |
339 } | 372 } |
340 } | 373 } |
341 } | 374 } |
342 | 375 |
343 void ActivityLog::KillActivityLogDatabase() { | 376 void ActivityLog::KillActivityLogDatabase() { |
344 if (db_.get()) { | 377 if (db_.get()) { |
345 ScheduleAndForget(&ActivityDatabase::KillDatabase); | 378 ScheduleAndForget(&ActivityDatabase::KillDatabase); |
346 } | 379 } |
347 } | 380 } |
348 | 381 |
349 // static | 382 // static |
350 const char* ActivityLog::ActivityToString(Activity activity) { | 383 const char* ActivityLog::ActivityToString(Activity activity) { |
351 switch (activity) { | 384 switch (activity) { |
352 case ActivityLog::ACTIVITY_EXTENSION_API_CALL: | 385 case ActivityLog::ACTIVITY_EXTENSION_API_CALL: |
353 return "api_call"; | 386 return "api_call"; |
354 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK: | 387 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK: |
355 return "api_block"; | 388 return "api_block"; |
356 case ActivityLog::ACTIVITY_CONTENT_SCRIPT: | 389 case ActivityLog::ACTIVITY_CONTENT_SCRIPT: |
357 return "content_script"; | 390 return "content_script"; |
358 case ActivityLog::ACTIVITY_EVENT_DISPATCH: | 391 case ActivityLog::ACTIVITY_EVENT_DISPATCH: |
359 return "event_dispatch"; | 392 return "event_dispatch"; |
360 default: | 393 default: |
361 NOTREACHED(); | 394 NOTREACHED(); |
362 return ""; | 395 return ""; |
363 } | 396 } |
364 } | 397 } |
365 | 398 |
366 } // namespace extensions | 399 } // namespace extensions |
OLD | NEW |