Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: chrome/browser/extensions/activity_log/activity_log.cc

Issue 15573003: New architecture of the activity logging: Policies for summarization (and compression) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adressed Matt and Adrienne's comments. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/strings/string_util.h" 10 #include "base/strings/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/api/activity_log_private/activity_log_privat e_api.h" 16 #include "chrome/browser/extensions/api/activity_log_private/activity_log_privat e_api.h"
16 #include "chrome/browser/extensions/extension_service.h" 17 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/extension_system.h" 18 #include "chrome/browser/extensions/extension_system.h"
18 #include "chrome/browser/extensions/extension_system_factory.h" 19 #include "chrome/browser/extensions/extension_system_factory.h"
19 #include "chrome/browser/extensions/install_tracker_factory.h" 20 #include "chrome/browser/extensions/install_tracker_factory.h"
20 #include "chrome/browser/prerender/prerender_manager.h" 21 #include "chrome/browser/prerender/prerender_manager.h"
21 #include "chrome/browser/prerender/prerender_manager_factory.h" 22 #include "chrome/browser/prerender/prerender_manager_factory.h"
22 #include "chrome/browser/profiles/incognito_helpers.h" 23 #include "chrome/browser/profiles/incognito_helpers.h"
23 #include "chrome/common/chrome_constants.h" 24 #include "chrome/common/chrome_constants.h"
24 #include "chrome/common/chrome_switches.h" 25 #include "chrome/common/chrome_switches.h"
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 BrowserContextDependencyManager::GetInstance()) { 122 BrowserContextDependencyManager::GetInstance()) {
122 DependsOn(ExtensionSystemFactory::GetInstance()); 123 DependsOn(ExtensionSystemFactory::GetInstance());
123 DependsOn(InstallTrackerFactory::GetInstance()); 124 DependsOn(InstallTrackerFactory::GetInstance());
124 } 125 }
125 126
126 ActivityLogFactory::~ActivityLogFactory() { 127 ActivityLogFactory::~ActivityLogFactory() {
127 } 128 }
128 129
129 // ActivityLog 130 // ActivityLog
130 131
132 void ActivityLog::SetDefaultPolicy(ActivityLogPolicy::PolicyType policy_type) {
133 if (policy_type != policy_type_ && IsLogEnabled()) {
134 delete policy_;
135 switch (policy_type) {
136 case ActivityLogPolicy::POLICY_FULLSTREAM:
137 policy_ = new FullStreamUIPolicy(profile_);
138 break;
139 case ActivityLogPolicy::POLICY_NOARGS:
140 policy_ = new StreamWithoutArgsUIPolicy(profile_);
141 break;
142 default:
143 if (testing_mode_)
144 LOG(INFO) << "Calling SetDefaultPolicy with invalid policy type?";
145 }
146 policy_type_ = policy_type;
147 }
148 }
149
131 // Use GetInstance instead of directly creating an ActivityLog. 150 // Use GetInstance instead of directly creating an ActivityLog.
132 ActivityLog::ActivityLog(Profile* profile) 151 ActivityLog::ActivityLog(Profile* profile)
133 : profile_(profile), 152 : policy_type_(ActivityLogPolicy::POLICY_INVALID),
153 profile_(profile),
134 first_time_checking_(true), 154 first_time_checking_(true),
135 tracker_(NULL), 155 has_threads_(true),
136 has_threads_(true) { 156 tracker_(NULL) {
137 enabled_ = IsLogEnabledOnAnyProfile(); 157 enabled_ = IsLogEnabledOnAnyProfile();
138 158
139 // enable-extension-activity-log-testing
140 // This controls whether arguments are collected.
141 // It also controls whether logging statements are printed.
142 testing_mode_ = CommandLine::ForCurrentProcess()->HasSwitch(
143 switches::kEnableExtensionActivityLogTesting);
144 if (!testing_mode_) {
145 for (int i = 0; i < APIAction::kSizeAlwaysLog; i++) {
146 arg_whitelist_api_.insert(std::string(APIAction::kAlwaysLog[i]));
147 }
148 }
149
150 // Check that the right threads exist. If not, we shouldn't try to do things 159 // Check that the right threads exist. If not, we shouldn't try to do things
151 // that require them. 160 // that require them.
152 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) || 161 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) ||
153 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) || 162 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) ||
154 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { 163 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
155 LOG(ERROR) << "Missing threads, disabling Activity Logging!"; 164 LOG(ERROR) << "Missing threads, disabling Activity Logging!";
156 has_threads_ = false; 165 has_threads_ = false;
157 } 166 }
158 167
168 // enable-extension-activity-log-testing
169 // This controls whether arguments are collected.
170 // It also controls whether logging statements are printed.
171 testing_mode_ = CommandLine::ForCurrentProcess()->HasSwitch(
172 switches::kEnableExtensionActivityLogTesting);
173 if (!testing_mode_) {
174 SetDefaultPolicy(ActivityLogPolicy::POLICY_NOARGS);
175 } else {
176 SetDefaultPolicy(ActivityLogPolicy::POLICY_FULLSTREAM);
177 }
178
159 observers_ = new ObserverListThreadSafe<Observer>; 179 observers_ = new ObserverListThreadSafe<Observer>;
160
161 // We initialize the database whether or not the AL is enabled, since we might
162 // be enabled later on. If the database cannot be initialized for some
163 // reason, we keep chugging along but nothing will get recorded. If the UI is
164 // available, things will still get sent to the UI even if nothing
165 // is being written to the database.
166 db_ = new ActivityDatabase();
167 if (!has_threads_) return;
168 base::FilePath base_dir = profile->GetPath();
169 base::FilePath database_name = base_dir.Append(
170 chrome::kExtensionActivityLogFilename);
171 ScheduleAndForget(&ActivityDatabase::Init, database_name);
172 } 180 }
173 181
174 void ActivityLog::Shutdown() { 182 void ActivityLog::Shutdown() {
175 if (!first_time_checking_ && tracker_) tracker_->RemoveObserver(this); 183 if (!first_time_checking_ && tracker_) tracker_->RemoveObserver(this);
176 } 184 }
177 185
178 ActivityLog::~ActivityLog() { 186 ActivityLog::~ActivityLog() {
179 if (has_threads_) 187 delete policy_;
180 ScheduleAndForget(&ActivityDatabase::Close);
181 else
182 db_->Close();
183 } 188 }
184 189
185 // We can't register for the InstallTrackerFactory events or talk to the 190 // We can't register for the InstallTrackerFactory events or talk to the
186 // extension service in the constructor, so we do that here the first time 191 // extension service in the constructor, so we do that here the first time
187 // this is called (as identified by first_time_checking_). 192 // this is called (as identified by first_time_checking_).
188 bool ActivityLog::IsLogEnabled() { 193 bool ActivityLog::IsLogEnabled() {
189 if (!first_time_checking_) return enabled_; 194 if (!first_time_checking_) return enabled_;
190 if (!has_threads_) return false; 195 if (!has_threads_) return false;
191 tracker_ = InstallTrackerFactory::GetForProfile(profile_); 196 tracker_ = InstallTrackerFactory::GetForProfile(profile_);
192 tracker_->AddObserver(this); 197 tracker_->AddObserver(this);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 const std::string& api_call, 250 const std::string& api_call,
246 ListValue* args, 251 ListValue* args,
247 const std::string& extra, 252 const std::string& extra,
248 const APIAction::Type type) { 253 const APIAction::Type type) {
249 std::string verb, manager; 254 std::string verb, manager;
250 bool matches = RE2::FullMatch(api_call, "(.*?)\\.(.*)", &manager, &verb); 255 bool matches = RE2::FullMatch(api_call, "(.*?)\\.(.*)", &manager, &verb);
251 if (matches) { 256 if (matches) {
252 if (!args->empty() && manager == "tabs") { 257 if (!args->empty() && manager == "tabs") {
253 APIAction::LookupTabId(api_call, args, profile_); 258 APIAction::LookupTabId(api_call, args, profile_);
254 } 259 }
260
261 if (policy_) {
262 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
263 std::string key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
264 details->SetString(key, extra);
265 DCHECK((type == APIAction::CALL || type == APIAction::EVENT_CALLBACK) &&
266 "Unexpected APIAction call type.");
267 policy_->ProcessAction(
268 type == APIAction::CALL ? ActivityLogPolicy::ACTION_API :
269 ActivityLogPolicy::ACTION_EVENT,
270 extension_id,
271 api_call,
272 GURL(),
273 args,
274 details.get());
275 }
276
277 // TODO(felt) Logging should be done more efficiently, so that it
278 // doesn't require construction of the action object.
255 scoped_refptr<APIAction> action = new APIAction( 279 scoped_refptr<APIAction> action = new APIAction(
256 extension_id, 280 extension_id,
257 base::Time::Now(), 281 base::Time::Now(),
258 type, 282 type,
259 api_call, 283 api_call,
260 MakeArgList(args), 284 MakeArgList(args),
261 extra); 285 extra);
262 ScheduleAndForget(&ActivityDatabase::RecordAction, action); 286
263 observers_->Notify(&Observer::OnExtensionActivity, action); 287 observers_->Notify(&Observer::OnExtensionActivity, action);
264 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 288 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
265 } else { 289 } else {
266 LOG(ERROR) << "Unknown API call! " << api_call; 290 LOG(ERROR) << "Unknown API call! " << api_call;
267 } 291 }
268 } 292 }
269 293
270 // A wrapper around LogAPIActionInternal, but we know it's an API call. 294 // A wrapper around LogAPIActionInternal, but we know it's an API call.
271 void ActivityLog::LogAPIAction(const std::string& extension_id, 295 void ActivityLog::LogAPIAction(const std::string& extension_id,
272 const std::string& api_call, 296 const std::string& api_call,
273 ListValue* args, 297 ListValue* args,
274 const std::string& extra) { 298 const std::string& extra) {
275 if (!IsLogEnabled() || 299 if (!IsLogEnabled() ||
276 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 300 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
277 if (!testing_mode_ &&
278 arg_whitelist_api_.find(api_call) == arg_whitelist_api_.end())
279 args->Clear();
280 LogAPIActionInternal(extension_id, 301 LogAPIActionInternal(extension_id,
281 api_call, 302 api_call,
282 args, 303 args,
283 extra, 304 extra,
284 APIAction::CALL); 305 APIAction::CALL);
285 } 306 }
286 307
287 // A wrapper around LogAPIActionInternal, but we know it's actually an event 308 // A wrapper around LogAPIActionInternal, but we know it's actually an event
288 // being fired and triggering extension code. Having the two separate methods 309 // being fired and triggering extension code. Having the two separate methods
289 // (LogAPIAction vs LogEventAction) lets us hide how we actually choose to 310 // (LogAPIAction vs LogEventAction) lets us hide how we actually choose to
290 // handle them. Right now they're being handled almost the same. 311 // handle them. Right now they're being handled almost the same.
291 void ActivityLog::LogEventAction(const std::string& extension_id, 312 void ActivityLog::LogEventAction(const std::string& extension_id,
292 const std::string& api_call, 313 const std::string& api_call,
293 ListValue* args, 314 ListValue* args,
294 const std::string& extra) { 315 const std::string& extra) {
295 if (!IsLogEnabled() || 316 if (!IsLogEnabled() ||
296 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 317 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
297 if (!testing_mode_ &&
298 arg_whitelist_api_.find(api_call) == arg_whitelist_api_.end())
299 args->Clear();
300 LogAPIActionInternal(extension_id, 318 LogAPIActionInternal(extension_id,
301 api_call, 319 api_call,
302 args, 320 args,
303 extra, 321 extra,
304 APIAction::EVENT_CALLBACK); 322 APIAction::EVENT_CALLBACK);
305 } 323 }
306 324
307 void ActivityLog::LogBlockedAction(const std::string& extension_id, 325 void ActivityLog::LogBlockedAction(const std::string& extension_id,
308 const std::string& blocked_call, 326 const std::string& blocked_call,
309 ListValue* args, 327 ListValue* args,
310 BlockedAction::Reason reason, 328 BlockedAction::Reason reason,
311 const std::string& extra) { 329 const std::string& extra) {
312 if (!IsLogEnabled() || 330 if (!IsLogEnabled() ||
313 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 331 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
314 if (!testing_mode_ && 332
315 arg_whitelist_api_.find(blocked_call) == arg_whitelist_api_.end()) 333 if (policy_) {
316 args->Clear(); 334 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
335 std::string key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_REASON);
336 details->SetInteger(key, static_cast<int>(reason));
337 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
338 details->SetString(key, extra);
339 policy_->ProcessAction(
340 ActivityLogPolicy::ACTION_BLOCKED,
341 extension_id,
342 blocked_call,
343 GURL(),
344 args,
345 details.get());
346 }
347
317 scoped_refptr<BlockedAction> action = new BlockedAction(extension_id, 348 scoped_refptr<BlockedAction> action = new BlockedAction(extension_id,
318 base::Time::Now(), 349 base::Time::Now(),
319 blocked_call, 350 blocked_call,
320 MakeArgList(args), 351 MakeArgList(args),
321 reason, 352 reason,
322 extra); 353 extra);
323 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
324 observers_->Notify(&Observer::OnExtensionActivity, action); 354 observers_->Notify(&Observer::OnExtensionActivity, action);
325 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 355 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
326 } 356 }
327 357
328 void ActivityLog::LogDOMAction(const std::string& extension_id, 358 void ActivityLog::LogDOMAction(const std::string& extension_id,
329 const GURL& url, 359 const GURL& url,
330 const string16& url_title, 360 const string16& url_title,
331 const std::string& api_call, 361 const std::string& api_call,
332 const ListValue* args, 362 const ListValue* args,
333 DomActionType::Type call_type, 363 DomActionType::Type call_type,
334 const std::string& extra) { 364 const std::string& extra) {
335 if (!IsLogEnabled() || 365 if (!IsLogEnabled() ||
336 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 366 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
337 if (call_type == DomActionType::METHOD && api_call == "XMLHttpRequest.open") 367 if (call_type == DomActionType::METHOD && api_call == "XMLHttpRequest.open")
338 call_type = DomActionType::XHR; 368 call_type = DomActionType::XHR;
369
370 if (policy_) {
371 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
372 std::string key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_DOM_ACTION);
373 details->SetInteger(key, static_cast<int>(call_type));
374 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_URL_TITLE);
375 details->SetString(key, url_title);
376 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
377 details->SetString(key, extra);
378 policy_->ProcessAction(
379 ActivityLogPolicy::ACTION_DOM,
380 extension_id,
381 api_call,
382 url,
383 args,
384 details.get());
385 }
386
387
388 // TODO(felt) Logging should be done more efficiently, so that it
389 // doesn't require construction of the action object.
339 scoped_refptr<DOMAction> action = new DOMAction( 390 scoped_refptr<DOMAction> action = new DOMAction(
340 extension_id, 391 extension_id,
341 base::Time::Now(), 392 base::Time::Now(),
342 call_type, 393 call_type,
343 url, 394 url,
344 url_title, 395 url_title,
345 api_call, 396 api_call,
346 MakeArgList(args), 397 MakeArgList(args),
347 extra); 398 extra);
348 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
349 observers_->Notify(&Observer::OnExtensionActivity, action); 399 observers_->Notify(&Observer::OnExtensionActivity, action);
350 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 400 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
351 } 401 }
352 402
353 void ActivityLog::LogWebRequestAction(const std::string& extension_id, 403 void ActivityLog::LogWebRequestAction(const std::string& extension_id,
354 const GURL& url, 404 const GURL& url,
355 const std::string& api_call, 405 const std::string& api_call,
356 scoped_ptr<DictionaryValue> details, 406 scoped_ptr<DictionaryValue> details,
357 const std::string& extra) { 407 const std::string& extra) {
358 string16 null_title; 408 string16 null_title;
359 if (!IsLogEnabled() || 409 if (!IsLogEnabled() ||
360 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 410 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
361 411
362 // Strip details of the web request modifications (for privacy reasons), 412 std::string details_string;
363 // unless testing is enabled. 413 if (policy_) {
364 if (!testing_mode_) { 414 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
365 DictionaryValue::Iterator details_iterator(*details); 415 std::string key = policy_->GetKey(
366 while (!details_iterator.IsAtEnd()) { 416 ActivityLogPolicy::PARAM_KEY_DETAILS_STRING);
367 details->SetBoolean(details_iterator.key(), true); 417 details->SetString(key, details_string);
368 details_iterator.Advance(); 418 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
369 } 419 details->SetString(key, extra);
420 policy_->ProcessAction(
421 ActivityLogPolicy::ACTION_WEB_REQUEST,
422 extension_id,
423 api_call,
424 url,
425 NULL,
426 details.get());
370 } 427 }
371 std::string details_string; 428
372 JSONStringValueSerializer serializer(&details_string); 429 JSONStringValueSerializer serializer(&details_string);
373 serializer.SerializeAndOmitBinaryValues(*details); 430 serializer.SerializeAndOmitBinaryValues(*details);
374 431
432 // TODO(felt) Logging should be done more efficiently, so that it
433 // doesn't require construction of the action object.
375 scoped_refptr<DOMAction> action = new DOMAction( 434 scoped_refptr<DOMAction> action = new DOMAction(
376 extension_id, 435 extension_id,
377 base::Time::Now(), 436 base::Time::Now(),
378 DomActionType::WEBREQUEST, 437 DomActionType::WEBREQUEST,
379 url, 438 url,
380 null_title, 439 null_title,
381 api_call, 440 api_call,
382 details_string, 441 details_string,
383 extra); 442 extra);
384 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
385 observers_->Notify(&Observer::OnExtensionActivity, action); 443 observers_->Notify(&Observer::OnExtensionActivity, action);
386 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 444 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
387 } 445 }
388 446
389 void ActivityLog::GetActions( 447 void ActivityLog::GetActions(
390 const std::string& extension_id, 448 const std::string& extension_id,
391 const int day, 449 const int day,
392 const base::Callback 450 const base::Callback
393 <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>& callback) { 451 <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>& callback) {
394 if (!has_threads_) return; 452 if (policy_) {
395 BrowserThread::PostTaskAndReplyWithResult( 453 policy_->ReadData(extension_id, day, callback);
396 BrowserThread::DB, 454 }
397 FROM_HERE,
398 base::Bind(&ActivityDatabase::GetActions,
399 base::Unretained(db_),
400 extension_id,
401 day),
402 callback);
403 } 455 }
404 456
405 void ActivityLog::OnScriptsExecuted( 457 void ActivityLog::OnScriptsExecuted(
406 const content::WebContents* web_contents, 458 const content::WebContents* web_contents,
407 const ExecutingScriptsMap& extension_ids, 459 const ExecutingScriptsMap& extension_ids,
408 int32 on_page_id, 460 int32 on_page_id,
409 const GURL& on_url) { 461 const GURL& on_url) {
410 if (!IsLogEnabled()) return; 462 if (!IsLogEnabled()) return;
411 Profile* profile = 463 Profile* profile =
412 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 464 Profile::FromBrowserContext(web_contents->GetBrowserContext());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 web_contents->GetTitle(), 498 web_contents->GetTitle(),
447 std::string(), // no api call here 499 std::string(), // no api call here
448 script_names.get(), 500 script_names.get(),
449 DomActionType::INSERTED, 501 DomActionType::INSERTED,
450 extra); 502 extra);
451 } 503 }
452 } 504 }
453 } 505 }
454 506
455 } // namespace extensions 507 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698