| 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 |