Chromium Code Reviews| 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 <set> | 5 #include <set> |
| 6 #include <vector> | 6 #include <vector> |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/json/json_string_value_serializer.h" | 8 #include "base/json/json_string_value_serializer.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/threading/thread_checker.h" | 11 #include "base/threading/thread_checker.h" |
| 12 #include "chrome/browser/extensions/activity_log/activity_log.h" | 12 #include "chrome/browser/extensions/activity_log/activity_log.h" |
| 13 #include "chrome/browser/extensions/activity_log/api_actions.h" | 13 #include "chrome/browser/extensions/activity_log/api_actions.h" |
| 14 #include "chrome/browser/extensions/activity_log/blocked_actions.h" | 14 #include "chrome/browser/extensions/activity_log/blocked_actions.h" |
| 15 #include "chrome/browser/extensions/activity_log/stream_noargs_ui_policy.h" | |
| 15 #include "chrome/browser/extensions/extension_service.h" | 16 #include "chrome/browser/extensions/extension_service.h" |
| 16 #include "chrome/browser/extensions/extension_system.h" | 17 #include "chrome/browser/extensions/extension_system.h" |
| 17 #include "chrome/browser/profiles/incognito_helpers.h" | 18 #include "chrome/browser/profiles/incognito_helpers.h" |
| 18 #include "chrome/common/chrome_constants.h" | 19 #include "chrome/common/chrome_constants.h" |
| 19 #include "chrome/common/chrome_switches.h" | 20 #include "chrome/common/chrome_switches.h" |
| 20 #include "chrome/common/extensions/extension.h" | 21 #include "chrome/common/extensions/extension.h" |
| 21 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
| 22 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
| 23 #include "sql/error_delegate_util.h" | 24 #include "sql/error_delegate_util.h" |
| 24 #include "third_party/re2/re2/re2.h" | 25 #include "third_party/re2/re2/re2.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 // static | 82 // static |
| 82 bool ActivityLog::IsLogEnabled() { | 83 bool ActivityLog::IsLogEnabled() { |
| 83 return LogIsEnabled::GetInstance()->enabled(); | 84 return LogIsEnabled::GetInstance()->enabled(); |
| 84 } | 85 } |
| 85 | 86 |
| 86 // static | 87 // static |
| 87 void ActivityLog::RecomputeLoggingIsEnabled() { | 88 void ActivityLog::RecomputeLoggingIsEnabled() { |
| 88 return LogIsEnabled::GetInstance()->ComputeIsEnabled(); | 89 return LogIsEnabled::GetInstance()->ComputeIsEnabled(); |
| 89 } | 90 } |
| 90 | 91 |
| 91 // This handles errors from the database. | |
| 92 class KillActivityDatabaseErrorDelegate : public sql::ErrorDelegate { | |
| 93 public: | |
| 94 explicit KillActivityDatabaseErrorDelegate(ActivityLog* backend) | |
| 95 : backend_(backend), | |
| 96 scheduled_death_(false) {} | |
| 97 | |
| 98 virtual int OnError(int error, | |
| 99 sql::Connection* connection, | |
| 100 sql::Statement* stmt) OVERRIDE { | |
| 101 if (!scheduled_death_ && sql::IsErrorCatastrophic(error)) { | |
| 102 ScheduleDeath(); | |
| 103 } | |
| 104 return error; | |
| 105 } | |
| 106 | |
| 107 // Schedules death if an error wasn't already reported. | |
| 108 void ScheduleDeath() { | |
| 109 if (!scheduled_death_) { | |
| 110 scheduled_death_ = true; | |
| 111 backend_->KillActivityLogDatabase(); | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 bool scheduled_death() const { | |
| 116 return scheduled_death_; | |
| 117 } | |
| 118 | |
| 119 private: | |
| 120 ActivityLog* backend_; | |
| 121 bool scheduled_death_; | |
| 122 | |
| 123 DISALLOW_COPY_AND_ASSIGN(KillActivityDatabaseErrorDelegate); | |
| 124 }; | |
| 125 | |
| 126 // ActivityLogFactory | 92 // ActivityLogFactory |
| 127 | 93 |
| 128 ActivityLogFactory* ActivityLogFactory::GetInstance() { | 94 ActivityLogFactory* ActivityLogFactory::GetInstance() { |
| 129 return Singleton<ActivityLogFactory>::get(); | 95 return Singleton<ActivityLogFactory>::get(); |
| 130 } | 96 } |
| 131 | 97 |
| 132 ProfileKeyedService* ActivityLogFactory::BuildServiceInstanceFor( | 98 ProfileKeyedService* ActivityLogFactory::BuildServiceInstanceFor( |
| 133 content::BrowserContext* profile) const { | 99 content::BrowserContext* profile) const { |
| 134 return new ActivityLog(static_cast<Profile*>(profile)); | 100 return new ActivityLog(static_cast<Profile*>(profile)); |
| 135 } | 101 } |
| 136 | 102 |
| 137 content::BrowserContext* ActivityLogFactory::GetBrowserContextToUse( | 103 content::BrowserContext* ActivityLogFactory::GetBrowserContextToUse( |
| 138 content::BrowserContext* context) const { | 104 content::BrowserContext* context) const { |
| 139 return chrome::GetBrowserContextRedirectedInIncognito(context); | 105 return chrome::GetBrowserContextRedirectedInIncognito(context); |
| 140 } | 106 } |
| 141 | 107 |
| 142 // ActivityLog | 108 // ActivityLog |
| 143 | 109 |
| 144 // Use GetInstance instead of directly creating an ActivityLog. | 110 // Use GetInstance instead of directly creating an ActivityLog. |
| 145 ActivityLog::ActivityLog(Profile* profile) : profile_(profile) { | 111 ActivityLog::ActivityLog(Profile* profile) : policy_(NULL), profile_(profile) { |
| 146 // enable-extension-activity-logging and enable-extension-activity-ui | 112 // enable-extension-activity-logging and enable-extension-activity-ui |
| 147 log_activity_to_stdout_ = CommandLine::ForCurrentProcess()->HasSwitch( | 113 log_activity_to_stdout_ = CommandLine::ForCurrentProcess()->HasSwitch( |
| 148 switches::kEnableExtensionActivityLogging); | 114 switches::kEnableExtensionActivityLogging); |
| 149 log_activity_to_ui_ = CommandLine::ForCurrentProcess()->HasSwitch( | 115 log_activity_to_ui_ = CommandLine::ForCurrentProcess()->HasSwitch( |
| 150 switches::kEnableExtensionActivityUI); | 116 switches::kEnableExtensionActivityUI); |
| 151 | 117 |
| 152 // enable-extension-activity-log-testing | |
| 153 // This controls whether arguments are collected. | |
| 154 testing_mode_ = CommandLine::ForCurrentProcess()->HasSwitch( | |
| 155 switches::kEnableExtensionActivityLogTesting); | |
| 156 if (!testing_mode_) { | |
| 157 for (int i = 0; i < APIAction::kSizeAlwaysLog; i++) { | |
| 158 arg_whitelist_api_.insert(std::string(APIAction::kAlwaysLog[i])); | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 // We normally dispatch DB requests to the DB thread, but the thread might | 118 // We normally dispatch DB requests to the DB thread, but the thread might |
| 163 // not exist if we are under test conditions. Substitute the UI thread for | 119 // not exist if we are under test conditions. Substitute the UI thread for |
| 164 // this case. | 120 // this case. |
| 121 content::BrowserThread::ID dispatch_thread; | |
| 165 if (BrowserThread::IsMessageLoopValid(BrowserThread::DB)) { | 122 if (BrowserThread::IsMessageLoopValid(BrowserThread::DB)) { |
| 166 dispatch_thread_ = BrowserThread::DB; | 123 dispatch_thread = BrowserThread::DB; |
| 167 } else { | 124 } else { |
| 168 LOG(ERROR) << "BrowserThread::DB does not exist, running on UI thread!"; | 125 LOG(ERROR) << "BrowserThread::DB does not exist, running on UI thread!"; |
| 169 dispatch_thread_ = BrowserThread::UI; | 126 dispatch_thread = BrowserThread::UI; |
| 170 } | 127 } |
| 171 | 128 |
| 172 // If the database cannot be initialized for some reason, we keep | 129 // TODO(dbabic) In the next iteration, we should support multiple policies, |
| 173 // chugging along but nothing will get recorded. If the UI is | 130 // which are then polled by the ActivityLog object |
| 174 // available, things will still get sent to the UI even if nothing | 131 if (IsLogEnabled()) { |
| 175 // is being written to the database. | 132 switch (policy_type_) { |
|
felt
2013/05/24 18:43:38
Where is policy_type_ set?
dbabic
2013/05/28 21:11:49
There's a static constructor at the end of this fi
felt
2013/05/29 03:41:15
Ah, didn't see it. Cool.
On 2013/05/28 21:11:49,
| |
| 176 db_ = new ActivityDatabase(); | 133 case ActivityLogPolicy::POLICY_FULLSTREAM: |
| 177 if (!IsLogEnabled()) return; | 134 policy_ = new FullStreamUIPolicy(profile, dispatch_thread); |
| 178 base::FilePath base_dir = profile->GetPath(); | 135 break; |
| 179 base::FilePath database_name = base_dir.Append( | 136 case ActivityLogPolicy::POLICY_NOARGS: |
| 180 chrome::kExtensionActivityLogFilename); | 137 policy_ = new StreamWithoutArgsUIPolicy(profile, dispatch_thread); |
| 181 KillActivityDatabaseErrorDelegate* error_delegate = | 138 break; |
| 182 new KillActivityDatabaseErrorDelegate(this); | 139 } |
| 183 db_->SetErrorDelegate(error_delegate); | 140 } |
| 184 ScheduleAndForget(&ActivityDatabase::Init, database_name); | |
| 185 } | 141 } |
| 186 | 142 |
| 187 ActivityLog::~ActivityLog() { | 143 ActivityLog::~ActivityLog() { |
| 188 ScheduleAndForget(&ActivityDatabase::Close); | 144 delete policy_; |
| 189 } | |
| 190 | |
| 191 void ActivityLog::SetArgumentLoggingForTesting(bool log_arguments) { | |
| 192 testing_mode_ = log_arguments; | |
| 193 } | 145 } |
| 194 | 146 |
| 195 // static | 147 // static |
| 196 ActivityLog* ActivityLog::GetInstance(Profile* profile) { | 148 ActivityLog* ActivityLog::GetInstance(Profile* profile) { |
| 197 return ActivityLogFactory::GetForProfile(profile); | 149 return ActivityLogFactory::GetForProfile(profile); |
| 198 } | 150 } |
| 199 | 151 |
| 200 void ActivityLog::AddObserver(const Extension* extension, | 152 void ActivityLog::AddObserver(const Extension* extension, |
| 201 ActivityLog::Observer* observer) { | 153 ActivityLog::Observer* observer) { |
| 202 if (!IsLogEnabled()) return; | 154 if (!IsLogEnabled()) return; |
| 203 if (observers_.count(extension) == 0) | 155 if (observers_.count(extension) == 0) |
| 204 observers_[extension] = new ObserverListThreadSafe<Observer>; | 156 observers_[extension] = new ObserverListThreadSafe<Observer>; |
| 205 observers_[extension]->AddObserver(observer); | 157 observers_[extension]->AddObserver(observer); |
| 206 } | 158 } |
| 207 | 159 |
| 208 void ActivityLog::RemoveObserver(const Extension* extension, | 160 void ActivityLog::RemoveObserver(const Extension* extension, |
| 209 ActivityLog::Observer* observer) { | 161 ActivityLog::Observer* observer) { |
| 210 if (observers_.count(extension) == 1) | 162 if (observers_.count(extension) == 1) |
| 211 observers_[extension]->RemoveObserver(observer); | 163 observers_[extension]->RemoveObserver(observer); |
| 212 } | 164 } |
| 213 | 165 |
| 214 void ActivityLog::LogAPIActionInternal(const Extension* extension, | 166 void ActivityLog::LogAPIActionInternal(const Extension* extension, |
| 215 const std::string& api_call, | 167 const std::string& api_call, |
| 216 ListValue* args, | 168 ListValue* args, |
| 217 const std::string& extra, | 169 const std::string& extra, |
| 218 const APIAction::Type type) { | 170 const APIAction::Type type) { |
| 171 if (!extension) | |
|
felt
2013/05/24 18:43:38
Note that these checks help with but still don't s
dbabic
2013/05/28 21:11:49
Sorry, I didn't understand why this doesn't fix th
felt
2013/05/29 03:41:15
Yup, if the extension is uninstalled, the extensio
| |
| 172 return; | |
| 173 | |
| 219 std::string verb, manager; | 174 std::string verb, manager; |
| 220 bool matches = RE2::FullMatch(api_call, "(.*?)\\.(.*)", &manager, &verb); | 175 bool matches = RE2::FullMatch(api_call, "(.*?)\\.(.*)", &manager, &verb); |
| 221 if (matches) { | 176 if (matches) { |
| 222 if (!args->empty() && manager == "tabs") { | 177 if (!args->empty() && manager == "tabs") { |
| 223 APIAction::LookupTabId(api_call, args, profile_); | 178 APIAction::LookupTabId(api_call, args, profile_); |
| 224 } | 179 } |
| 180 | |
| 181 if (policy_) { | |
| 182 DCHECK((type == APIAction::CALL || type == APIAction::EVENT_CALLBACK) && | |
| 183 "Unexpected APIAction call type."); | |
| 184 policy_->ProcessAction( | |
| 185 type == APIAction::CALL ? ActivityLogPolicy::ACTION_API : | |
| 186 ActivityLogPolicy::ACTION_EVENT, | |
| 187 *extension, | |
| 188 api_call, | |
| 189 NULL, | |
| 190 args, | |
| 191 NULL); | |
| 192 } | |
| 193 | |
| 194 // TODO(felt) Logging should be done more efficiently, so that it | |
| 195 // doesn't require construction of the action object. | |
| 225 scoped_refptr<APIAction> action = new APIAction( | 196 scoped_refptr<APIAction> action = new APIAction( |
| 226 extension->id(), | 197 extension->id(), |
| 227 base::Time::Now(), | 198 base::Time::Now(), |
| 228 type, | 199 type, |
| 229 api_call, | 200 api_call, |
| 230 MakeArgList(args), | 201 MakeArgList(args), |
| 231 extra); | 202 extra); |
| 232 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | |
| 233 | 203 |
| 234 // Display the action. | 204 // Display the action. |
| 235 ObserverMap::const_iterator iter = observers_.find(extension); | 205 ObserverMap::const_iterator iter = observers_.find(extension); |
| 236 if (iter != observers_.end()) { | 206 if (iter != observers_.end()) { |
| 237 if (type == APIAction::CALL) { | 207 if (type == APIAction::CALL) { |
| 238 iter->second->Notify(&Observer::OnExtensionActivity, | 208 iter->second->Notify(&Observer::OnExtensionActivity, |
| 239 extension, | 209 extension, |
| 240 ActivityLog::ACTIVITY_EXTENSION_API_CALL, | 210 ActivityLog::ACTIVITY_EXTENSION_API_CALL, |
| 241 MakeCallSignature(api_call, args)); | 211 MakeCallSignature(api_call, args)); |
| 242 } else if (type == APIAction::EVENT_CALLBACK) { | 212 } else if (type == APIAction::EVENT_CALLBACK) { |
| 243 iter->second->Notify(&Observer::OnExtensionActivity, | 213 iter->second->Notify(&Observer::OnExtensionActivity, |
| 244 extension, | 214 extension, |
| 245 ActivityLog::ACTIVITY_EVENT_DISPATCH, | 215 ActivityLog::ACTIVITY_EVENT_DISPATCH, |
| 246 MakeCallSignature(api_call, args)); | 216 MakeCallSignature(api_call, args)); |
| 247 } | 217 } |
| 248 } | 218 } |
| 249 if (log_activity_to_stdout_) | 219 if (log_activity_to_stdout_) |
| 250 LOG(INFO) << action->PrintForDebug(); | 220 LOG(INFO) << action->PrintForDebug(); |
| 251 } else { | 221 } else { |
| 252 LOG(ERROR) << "Unknown API call! " << api_call; | 222 LOG(ERROR) << "Unknown API call! " << api_call; |
| 253 } | 223 } |
| 254 } | 224 } |
| 255 | 225 |
| 256 // A wrapper around LogAPIActionInternal, but we know it's an API call. | 226 // A wrapper around LogAPIActionInternal, but we know it's an API call. |
| 257 void ActivityLog::LogAPIAction(const Extension* extension, | 227 void ActivityLog::LogAPIAction(const Extension* extension, |
| 258 const std::string& api_call, | 228 const std::string& api_call, |
| 259 ListValue* args, | 229 ListValue* args, |
| 260 const std::string& extra) { | 230 const std::string& extra) { |
| 261 if (!IsLogEnabled()) return; | 231 if (!IsLogEnabled() || !extension) |
| 262 if (!testing_mode_ && | 232 return; |
| 263 arg_whitelist_api_.find(api_call) == arg_whitelist_api_.end()) | 233 |
| 264 args->Clear(); | |
| 265 LogAPIActionInternal(extension, | 234 LogAPIActionInternal(extension, |
| 266 api_call, | 235 api_call, |
| 267 args, | 236 args, |
| 268 extra, | 237 extra, |
| 269 APIAction::CALL); | 238 APIAction::CALL); |
| 270 } | 239 } |
| 271 | 240 |
| 272 // A wrapper around LogAPIActionInternal, but we know it's actually an event | 241 // A wrapper around LogAPIActionInternal, but we know it's actually an event |
| 273 // being fired and triggering extension code. Having the two separate methods | 242 // being fired and triggering extension code. Having the two separate methods |
| 274 // (LogAPIAction vs LogEventAction) lets us hide how we actually choose to | 243 // (LogAPIAction vs LogEventAction) lets us hide how we actually choose to |
| 275 // handle them. Right now they're being handled almost the same. | 244 // handle them. Right now they're being handled almost the same. |
| 276 void ActivityLog::LogEventAction(const Extension* extension, | 245 void ActivityLog::LogEventAction(const Extension* extension, |
| 277 const std::string& api_call, | 246 const std::string& api_call, |
| 278 ListValue* args, | 247 ListValue* args, |
| 279 const std::string& extra) { | 248 const std::string& extra) { |
| 280 if (!IsLogEnabled()) return; | 249 if (!IsLogEnabled() || !extension) |
| 281 if (!testing_mode_ && | 250 return; |
| 282 arg_whitelist_api_.find(api_call) == arg_whitelist_api_.end()) | 251 |
| 283 args->Clear(); | |
| 284 LogAPIActionInternal(extension, | 252 LogAPIActionInternal(extension, |
| 285 api_call, | 253 api_call, |
| 286 args, | 254 args, |
| 287 extra, | 255 extra, |
| 288 APIAction::EVENT_CALLBACK); | 256 APIAction::EVENT_CALLBACK); |
| 289 } | 257 } |
| 290 | 258 |
| 291 void ActivityLog::LogBlockedAction(const Extension* extension, | 259 void ActivityLog::LogBlockedAction(const Extension* extension, |
| 292 const std::string& blocked_call, | 260 const std::string& blocked_call, |
| 293 ListValue* args, | 261 ListValue* args, |
| 294 BlockedAction::Reason reason, | 262 BlockedAction::Reason reason, |
| 295 const std::string& extra) { | 263 const std::string& extra) { |
| 296 if (!IsLogEnabled()) return; | 264 if (!IsLogEnabled() || !extension) |
| 297 if (!testing_mode_ && | 265 return; |
| 298 arg_whitelist_api_.find(blocked_call) == arg_whitelist_api_.end()) | 266 |
| 299 args->Clear(); | 267 if (policy_) { |
| 268 scoped_ptr<base::DictionaryValue> details(new DictionaryValue()); | |
| 269 std::string key; | |
| 270 policy_->GetKey(ActivityLogPolicy::PARAM_KEY_REASON, key); | |
| 271 details->SetInteger(key, static_cast<int>(reason)); | |
| 272 policy_->ProcessAction( | |
| 273 ActivityLogPolicy::ACTION_BLOCKED, | |
| 274 *extension, | |
| 275 blocked_call, | |
| 276 NULL, | |
| 277 args, | |
| 278 details.get()); | |
| 279 } | |
| 280 | |
| 281 // TODO(felt) Logging should be done more efficiently, so that it | |
| 282 // doesn't require construction of the action object. | |
| 300 scoped_refptr<BlockedAction> action = new BlockedAction(extension->id(), | 283 scoped_refptr<BlockedAction> action = new BlockedAction(extension->id(), |
| 301 base::Time::Now(), | 284 base::Time::Now(), |
| 302 blocked_call, | 285 blocked_call, |
| 303 MakeArgList(args), | 286 MakeArgList(args), |
| 304 reason, | 287 reason, |
| 305 extra); | 288 extra); |
| 306 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | |
| 307 // Display the action. | 289 // Display the action. |
| 308 ObserverMap::const_iterator iter = observers_.find(extension); | 290 ObserverMap::const_iterator iter = observers_.find(extension); |
| 309 if (iter != observers_.end()) { | 291 if (iter != observers_.end()) { |
| 310 std::string blocked_str = MakeCallSignature(blocked_call, args); | 292 std::string blocked_str = MakeCallSignature(blocked_call, args); |
| 311 iter->second->Notify(&Observer::OnExtensionActivity, | 293 iter->second->Notify(&Observer::OnExtensionActivity, |
| 312 extension, | 294 extension, |
| 313 ActivityLog::ACTIVITY_EXTENSION_API_BLOCK, | 295 ActivityLog::ACTIVITY_EXTENSION_API_BLOCK, |
| 314 blocked_str); | 296 blocked_str); |
| 315 } | 297 } |
| 316 if (log_activity_to_stdout_) | 298 if (log_activity_to_stdout_) |
| 317 LOG(INFO) << action->PrintForDebug(); | 299 LOG(INFO) << action->PrintForDebug(); |
| 318 } | 300 } |
| 319 | 301 |
| 320 void ActivityLog::LogDOMActionInternal(const Extension* extension, | 302 void ActivityLog::LogDOMActionInternal(const Extension* extension, |
| 321 const GURL& url, | 303 const GURL& url, |
| 322 const string16& url_title, | 304 const string16& url_title, |
| 323 const std::string& api_call, | 305 const std::string& api_call, |
| 324 const ListValue* args, | 306 const ListValue* args, |
| 325 const std::string& extra, | 307 const std::string& extra, |
| 326 DOMAction::DOMActionType verb) { | 308 DOMAction::DOMActionType verb) { |
| 309 | |
|
felt
2013/05/24 18:43:38
Delete the extra vertical spaces at the beginning
dbabic
2013/05/28 21:11:49
Done.
| |
| 310 if (!extension) | |
| 311 return; | |
| 312 | |
| 313 if (policy_) { | |
| 314 scoped_ptr<base::DictionaryValue> details(new DictionaryValue()); | |
| 315 std::string key; | |
| 316 policy_->GetKey(ActivityLogPolicy::PARAM_KEY_DOM_ACTION, key); | |
| 317 details->SetInteger(key, static_cast<int>(verb)); | |
| 318 policy_->GetKey(ActivityLogPolicy::PARAM_KEY_URL_TITLE, key); | |
| 319 details->SetString(key, url_title); | |
| 320 policy_->ProcessAction( | |
| 321 ActivityLogPolicy::ACTION_DOM, | |
| 322 *extension, | |
| 323 api_call, | |
| 324 &url, | |
| 325 args, | |
| 326 details.get()); | |
| 327 } | |
| 328 | |
| 329 | |
| 330 // TODO(felt) Logging should be done more efficiently, so that it | |
| 331 // doesn't require construction of the action object. | |
| 327 scoped_refptr<DOMAction> action = new DOMAction( | 332 scoped_refptr<DOMAction> action = new DOMAction( |
| 328 extension->id(), | 333 extension->id(), |
| 329 base::Time::Now(), | 334 base::Time::Now(), |
| 330 verb, | 335 verb, |
| 331 url, | 336 url, |
| 332 url_title, | 337 url_title, |
| 333 api_call, | 338 api_call, |
| 334 MakeArgList(args), | 339 MakeArgList(args), |
| 335 extra); | 340 extra); |
| 336 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | |
| 337 | 341 |
| 338 // Display the action. | 342 // Display the action. |
| 339 ObserverMap::const_iterator iter = observers_.find(extension); | 343 ObserverMap::const_iterator iter = observers_.find(extension); |
| 340 if (iter != observers_.end()) { | 344 if (iter != observers_.end()) { |
| 341 // TODO(felt): This is a kludge, planning to update this when new | 345 // TODO(felt): This is a kludge, planning to update this when new |
| 342 // UI is in place. | 346 // UI is in place. |
| 343 if (verb == DOMAction::INSERTED) { | 347 if (verb == DOMAction::INSERTED) { |
| 344 iter->second->Notify(&Observer::OnExtensionActivity, | 348 iter->second->Notify(&Observer::OnExtensionActivity, |
| 345 extension, | 349 extension, |
| 346 ActivityLog::ACTIVITY_CONTENT_SCRIPT, | 350 ActivityLog::ACTIVITY_CONTENT_SCRIPT, |
| 347 action->PrintForDebug()); | 351 action->PrintForDebug()); |
| 348 } else { | 352 } else { |
| 349 iter->second->Notify(&Observer::OnExtensionActivity, | 353 iter->second->Notify(&Observer::OnExtensionActivity, |
| 350 extension, | 354 extension, |
| 351 ActivityLog::ACTIVITY_CONTENT_SCRIPT, | 355 ActivityLog::ACTIVITY_CONTENT_SCRIPT, |
| 352 MakeCallSignature(api_call, args)); | 356 MakeCallSignature(api_call, args)); |
| 353 } | 357 } |
| 354 } | 358 } |
| 355 if (log_activity_to_stdout_) | 359 if (log_activity_to_stdout_) |
| 356 LOG(INFO) << action->PrintForDebug(); | 360 LOG(INFO) << action->PrintForDebug(); |
| 357 } | 361 } |
| 358 | 362 |
| 359 void ActivityLog::LogDOMAction(const Extension* extension, | 363 void ActivityLog::LogDOMAction(const Extension* extension, |
| 360 const GURL& url, | 364 const GURL& url, |
| 361 const string16& url_title, | 365 const string16& url_title, |
| 362 const std::string& api_call, | 366 const std::string& api_call, |
| 363 const ListValue* args, | 367 const ListValue* args, |
| 364 const std::string& extra) { | 368 const std::string& extra) { |
| 365 if (!IsLogEnabled()) return; | 369 if (!IsLogEnabled() || !extension) |
| 370 return; | |
| 371 | |
| 366 DOMAction::DOMActionType action = DOMAction::MODIFIED; | 372 DOMAction::DOMActionType action = DOMAction::MODIFIED; |
| 367 if (extra == "Getter") { | 373 if (extra == "Getter") { |
| 368 action = DOMAction::GETTER; | 374 action = DOMAction::GETTER; |
| 369 } else if (extra == "Setter") { | 375 } else if (extra == "Setter") { |
| 370 action = DOMAction::SETTER; | 376 action = DOMAction::SETTER; |
| 371 } else if (api_call == "XMLHttpRequest.open") { | 377 } else if (api_call == "XMLHttpRequest.open") { |
| 372 // Has to come before the Method check because XHR is also a Method. | 378 // Has to come before the Method check because XHR is also a Method. |
| 373 action = DOMAction::XHR; | 379 action = DOMAction::XHR; |
| 374 } else if (extra == "Method") { | 380 } else if (extra == "Method") { |
| 375 action = DOMAction::METHOD; | 381 action = DOMAction::METHOD; |
| 376 } | 382 } |
| 383 | |
| 377 LogDOMActionInternal(extension, | 384 LogDOMActionInternal(extension, |
| 378 url, | 385 url, |
| 379 url_title, | 386 url_title, |
| 380 api_call, | 387 api_call, |
| 381 args, | 388 args, |
| 382 extra, | 389 extra, |
| 383 action); | 390 action); |
| 384 } | 391 } |
| 385 | 392 |
| 386 void ActivityLog::LogWebRequestAction(const Extension* extension, | 393 void ActivityLog::LogWebRequestAction(const Extension* extension, |
| 387 const GURL& url, | 394 const GURL& url, |
| 388 const std::string& api_call, | 395 const std::string& api_call, |
| 389 scoped_ptr<DictionaryValue> details, | 396 scoped_ptr<DictionaryValue> details, |
| 390 const std::string& extra) { | 397 const std::string& extra) { |
| 391 string16 null_title; | 398 string16 null_title; |
| 392 if (!IsLogEnabled()) return; | 399 if (!IsLogEnabled() || !extension) |
| 400 return; | |
| 393 | 401 |
| 394 // Strip details of the web request modifications (for privacy reasons), | 402 std::string details_string; |
| 395 // unless testing is enabled. | 403 if (policy_) { |
| 396 if (!testing_mode_) { | 404 scoped_ptr<base::DictionaryValue> details(new DictionaryValue()); |
| 397 DictionaryValue::Iterator details_iterator(*details); | 405 std::string key; |
| 398 while (!details_iterator.IsAtEnd()) { | 406 policy_->GetKey(ActivityLogPolicy::PARAM_KEY_DETAILS_STRING, key); |
| 399 details->SetBoolean(details_iterator.key(), true); | 407 details->SetString(key, details_string); |
| 400 details_iterator.Advance(); | 408 policy_->ProcessAction( |
| 401 } | 409 ActivityLogPolicy::ACTION_WEB_REQUEST, |
| 410 *extension, | |
| 411 api_call, | |
| 412 &url, | |
| 413 NULL, | |
| 414 details.get()); | |
| 402 } | 415 } |
| 403 std::string details_string; | 416 |
| 404 JSONStringValueSerializer serializer(&details_string); | 417 JSONStringValueSerializer serializer(&details_string); |
| 405 serializer.SerializeAndOmitBinaryValues(*details); | 418 serializer.SerializeAndOmitBinaryValues(*details); |
| 406 | 419 |
| 420 // TODO(felt) Logging should be done more efficiently, so that it | |
| 421 // doesn't require construction of the action object. | |
| 407 scoped_refptr<DOMAction> action = new DOMAction( | 422 scoped_refptr<DOMAction> action = new DOMAction( |
| 408 extension->id(), | 423 extension->id(), |
| 409 base::Time::Now(), | 424 base::Time::Now(), |
| 410 DOMAction::WEBREQUEST, | 425 DOMAction::WEBREQUEST, |
| 411 url, | 426 url, |
| 412 null_title, | 427 null_title, |
| 413 api_call, | 428 api_call, |
| 414 details_string, | 429 details_string, |
| 415 extra); | 430 extra); |
| 416 ScheduleAndForget(&ActivityDatabase::RecordAction, action); | |
| 417 | 431 |
| 418 // Display the action. | 432 // Display the action. |
| 419 ObserverMap::const_iterator iter = observers_.find(extension); | 433 ObserverMap::const_iterator iter = observers_.find(extension); |
| 420 if (iter != observers_.end()) { | 434 if (iter != observers_.end()) { |
| 421 iter->second->Notify(&Observer::OnExtensionActivity, | 435 iter->second->Notify(&Observer::OnExtensionActivity, |
| 422 extension, | 436 extension, |
| 423 ActivityLog::ACTIVITY_CONTENT_SCRIPT, | 437 ActivityLog::ACTIVITY_CONTENT_SCRIPT, |
| 424 action->PrintForDebug()); | 438 action->PrintForDebug()); |
| 425 } | 439 } |
| 426 if (log_activity_to_stdout_) | 440 if (log_activity_to_stdout_) |
| 427 LOG(INFO) << action->PrintForDebug(); | 441 LOG(INFO) << action->PrintForDebug(); |
| 428 } | 442 } |
| 429 | 443 |
| 430 void ActivityLog::GetActions( | 444 void ActivityLog::GetActions( |
| 431 const std::string& extension_id, | 445 const std::string& extension_id, |
| 432 const int day, | 446 const int day, |
| 433 const base::Callback | 447 const base::Callback |
| 434 <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>& callback) { | 448 <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>& callback) { |
| 435 BrowserThread::PostTaskAndReplyWithResult( | 449 if (policy_) { |
| 436 dispatch_thread_, | 450 policy_->ReadData(extension_id, day, callback); |
| 437 FROM_HERE, | 451 } |
| 438 base::Bind(&ActivityDatabase::GetActions, | |
| 439 base::Unretained(db_), | |
| 440 extension_id, | |
| 441 day), | |
| 442 callback); | |
| 443 } | 452 } |
| 444 | 453 |
| 445 void ActivityLog::OnScriptsExecuted( | 454 void ActivityLog::OnScriptsExecuted( |
| 446 const content::WebContents* web_contents, | 455 const content::WebContents* web_contents, |
| 447 const ExecutingScriptsMap& extension_ids, | 456 const ExecutingScriptsMap& extension_ids, |
| 448 int32 on_page_id, | 457 int32 on_page_id, |
| 449 const GURL& on_url) { | 458 const GURL& on_url) { |
| 450 if (!IsLogEnabled()) return; | 459 if (!IsLogEnabled()) return; |
| 451 Profile* profile = | 460 Profile* profile = |
| 452 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 461 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 471 ext_scripts_str += *it2; | 480 ext_scripts_str += *it2; |
| 472 ext_scripts_str += " "; | 481 ext_scripts_str += " "; |
| 473 } | 482 } |
| 474 scoped_ptr<ListValue> script_names(new ListValue()); | 483 scoped_ptr<ListValue> script_names(new ListValue()); |
| 475 script_names->Set(0, new StringValue(ext_scripts_str)); | 484 script_names->Set(0, new StringValue(ext_scripts_str)); |
| 476 LogDOMActionInternal(extension, | 485 LogDOMActionInternal(extension, |
| 477 on_url, | 486 on_url, |
| 478 web_contents->GetTitle(), | 487 web_contents->GetTitle(), |
| 479 std::string(), // no api call here | 488 std::string(), // no api call here |
| 480 script_names.get(), | 489 script_names.get(), |
| 481 std::string(), // no extras either | 490 std::string(), |
| 482 DOMAction::INSERTED); | 491 DOMAction::INSERTED); // no extras either |
| 483 } | 492 } |
| 484 } | 493 } |
| 485 } | 494 } |
| 486 | 495 |
| 487 void ActivityLog::KillActivityLogDatabase() { | |
| 488 ScheduleAndForget(&ActivityDatabase::KillDatabase); | |
| 489 } | |
| 490 | |
| 491 // static | 496 // static |
| 492 const char* ActivityLog::ActivityToString(Activity activity) { | 497 const char* ActivityLog::ActivityToString(Activity activity) { |
| 493 switch (activity) { | 498 switch (activity) { |
| 494 case ActivityLog::ACTIVITY_EXTENSION_API_CALL: | 499 case ActivityLog::ACTIVITY_EXTENSION_API_CALL: |
| 495 return "api_call"; | 500 return "api_call"; |
| 496 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK: | 501 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK: |
| 497 return "api_block"; | 502 return "api_block"; |
| 498 case ActivityLog::ACTIVITY_CONTENT_SCRIPT: | 503 case ActivityLog::ACTIVITY_CONTENT_SCRIPT: |
| 499 return "content_script"; | 504 return "content_script"; |
| 500 case ActivityLog::ACTIVITY_EVENT_DISPATCH: | 505 case ActivityLog::ACTIVITY_EVENT_DISPATCH: |
| 501 return "event_dispatch"; | 506 return "event_dispatch"; |
| 502 default: | 507 default: |
| 503 NOTREACHED(); | 508 NOTREACHED(); |
| 504 return ""; | 509 return ""; |
| 505 } | 510 } |
| 506 } | 511 } |
| 507 | 512 |
| 513 ActivityLogPolicy::PolicyType ActivityLog::policy_type_( | |
| 514 ActivityLogPolicy::POLICY_NOARGS); | |
| 515 | |
| 508 } // namespace extensions | 516 } // namespace extensions |
| OLD | NEW |