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