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

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: Fixed browser test. 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_(NULL),
153 policy_type_(ActivityLogPolicy::POLICY_INVALID),
154 profile_(profile),
134 first_time_checking_(true), 155 first_time_checking_(true),
135 tracker_(NULL), 156 has_threads_(true),
136 has_threads_(true) { 157 tracker_(NULL) {
137 enabled_ = IsLogEnabledOnAnyProfile(); 158 enabled_ = IsLogEnabledOnAnyProfile();
138 159
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 160 // Check that the right threads exist. If not, we shouldn't try to do things
151 // that require them. 161 // that require them.
152 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) || 162 if (!BrowserThread::IsMessageLoopValid(BrowserThread::DB) ||
153 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) || 163 !BrowserThread::IsMessageLoopValid(BrowserThread::FILE) ||
154 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { 164 !BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
155 LOG(ERROR) << "Missing threads, disabling Activity Logging!"; 165 LOG(ERROR) << "Missing threads, disabling Activity Logging!";
156 has_threads_ = false; 166 has_threads_ = false;
157 } 167 }
158 168
159 observers_ = new ObserverListThreadSafe<Observer>; 169 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 } 170 }
173 171
174 void ActivityLog::Shutdown() { 172 void ActivityLog::Shutdown() {
175 if (!first_time_checking_ && tracker_) tracker_->RemoveObserver(this); 173 if (!first_time_checking_ && tracker_) tracker_->RemoveObserver(this);
176 } 174 }
177 175
178 ActivityLog::~ActivityLog() { 176 ActivityLog::~ActivityLog() {
179 if (has_threads_) 177 delete policy_;
180 ScheduleAndForget(&ActivityDatabase::Close);
181 else
182 db_->Close();
183 } 178 }
184 179
185 // We can't register for the InstallTrackerFactory events or talk to the 180 // 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 181 // extension service in the constructor, so we do that here the first time
187 // this is called (as identified by first_time_checking_). 182 // this is called (as identified by first_time_checking_).
188 bool ActivityLog::IsLogEnabled() { 183 bool ActivityLog::IsLogEnabled() {
189 if (!first_time_checking_) return enabled_; 184 if (!first_time_checking_) return enabled_;
190 if (!has_threads_) return false; 185 if (!has_threads_) return false;
191 tracker_ = InstallTrackerFactory::GetForProfile(profile_); 186 tracker_ = InstallTrackerFactory::GetForProfile(profile_);
192 tracker_->AddObserver(this); 187 tracker_->AddObserver(this);
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 const std::string& api_call, 238 const std::string& api_call,
244 ListValue* args, 239 ListValue* args,
245 const std::string& extra, 240 const std::string& extra,
246 const APIAction::Type type) { 241 const APIAction::Type type) {
247 std::string verb, manager; 242 std::string verb, manager;
248 bool matches = RE2::FullMatch(api_call, "(.*?)\\.(.*)", &manager, &verb); 243 bool matches = RE2::FullMatch(api_call, "(.*?)\\.(.*)", &manager, &verb);
249 if (matches) { 244 if (matches) {
250 if (!args->empty() && manager == "tabs") { 245 if (!args->empty() && manager == "tabs") {
251 APIAction::LookupTabId(api_call, args, profile_); 246 APIAction::LookupTabId(api_call, args, profile_);
252 } 247 }
248
249 if (policy_) {
250 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
251 std::string key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
252 details->SetString(key, extra);
253 DCHECK((type == APIAction::CALL || type == APIAction::EVENT_CALLBACK) &&
254 "Unexpected APIAction call type.");
255 policy_->ProcessAction(
256 type == APIAction::CALL ? ActivityLogPolicy::ACTION_API :
257 ActivityLogPolicy::ACTION_EVENT,
258 extension_id,
259 api_call,
260 GURL(),
261 args,
262 details.get());
263 }
264
265 // TODO(felt) Logging should be done more efficiently, so that it
266 // doesn't require construction of the action object.
253 scoped_refptr<APIAction> action = new APIAction( 267 scoped_refptr<APIAction> action = new APIAction(
254 extension_id, 268 extension_id,
255 base::Time::Now(), 269 base::Time::Now(),
256 type, 270 type,
257 api_call, 271 api_call,
258 MakeArgList(args), 272 MakeArgList(args),
259 extra); 273 extra);
260 ScheduleAndForget(&ActivityDatabase::RecordAction, action); 274
261 observers_->Notify(&Observer::OnExtensionActivity, action); 275 observers_->Notify(&Observer::OnExtensionActivity, action);
262 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 276 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
263 } else { 277 } else {
264 LOG(ERROR) << "Unknown API call! " << api_call; 278 LOG(ERROR) << "Unknown API call! " << api_call;
265 } 279 }
266 } 280 }
267 281
268 // A wrapper around LogAPIActionInternal, but we know it's an API call. 282 // A wrapper around LogAPIActionInternal, but we know it's an API call.
269 void ActivityLog::LogAPIAction(const std::string& extension_id, 283 void ActivityLog::LogAPIAction(const std::string& extension_id,
270 const std::string& api_call, 284 const std::string& api_call,
271 ListValue* args, 285 ListValue* args,
272 const std::string& extra) { 286 const std::string& extra) {
273 if (!IsLogEnabled() || 287 if (!IsLogEnabled() ||
274 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 288 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
275 if (!testing_mode_ &&
276 arg_whitelist_api_.find(api_call) == arg_whitelist_api_.end())
277 args->Clear();
278 LogAPIActionInternal(extension_id, 289 LogAPIActionInternal(extension_id,
279 api_call, 290 api_call,
280 args, 291 args,
281 extra, 292 extra,
282 APIAction::CALL); 293 APIAction::CALL);
283 } 294 }
284 295
285 // A wrapper around LogAPIActionInternal, but we know it's actually an event 296 // A wrapper around LogAPIActionInternal, but we know it's actually an event
286 // being fired and triggering extension code. Having the two separate methods 297 // being fired and triggering extension code. Having the two separate methods
287 // (LogAPIAction vs LogEventAction) lets us hide how we actually choose to 298 // (LogAPIAction vs LogEventAction) lets us hide how we actually choose to
288 // handle them. Right now they're being handled almost the same. 299 // handle them. Right now they're being handled almost the same.
289 void ActivityLog::LogEventAction(const std::string& extension_id, 300 void ActivityLog::LogEventAction(const std::string& extension_id,
290 const std::string& api_call, 301 const std::string& api_call,
291 ListValue* args, 302 ListValue* args,
292 const std::string& extra) { 303 const std::string& extra) {
293 if (!IsLogEnabled() || 304 if (!IsLogEnabled() ||
294 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 305 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
295 if (!testing_mode_ &&
296 arg_whitelist_api_.find(api_call) == arg_whitelist_api_.end())
297 args->Clear();
298 LogAPIActionInternal(extension_id, 306 LogAPIActionInternal(extension_id,
299 api_call, 307 api_call,
300 args, 308 args,
301 extra, 309 extra,
302 APIAction::EVENT_CALLBACK); 310 APIAction::EVENT_CALLBACK);
303 } 311 }
304 312
305 void ActivityLog::LogBlockedAction(const std::string& extension_id, 313 void ActivityLog::LogBlockedAction(const std::string& extension_id,
306 const std::string& blocked_call, 314 const std::string& blocked_call,
307 ListValue* args, 315 ListValue* args,
308 BlockedAction::Reason reason, 316 BlockedAction::Reason reason,
309 const std::string& extra) { 317 const std::string& extra) {
310 if (!IsLogEnabled() || 318 if (!IsLogEnabled() ||
311 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 319 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
312 if (!testing_mode_ && 320
313 arg_whitelist_api_.find(blocked_call) == arg_whitelist_api_.end()) 321 if (policy_) {
314 args->Clear(); 322 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
323 std::string key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_REASON);
324 details->SetInteger(key, static_cast<int>(reason));
325 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
326 details->SetString(key, extra);
327 policy_->ProcessAction(
328 ActivityLogPolicy::ACTION_BLOCKED,
329 extension_id,
330 blocked_call,
331 GURL(),
332 args,
333 details.get());
334 }
335
315 scoped_refptr<BlockedAction> action = new BlockedAction(extension_id, 336 scoped_refptr<BlockedAction> action = new BlockedAction(extension_id,
316 base::Time::Now(), 337 base::Time::Now(),
317 blocked_call, 338 blocked_call,
318 MakeArgList(args), 339 MakeArgList(args),
319 reason, 340 reason,
320 extra); 341 extra);
321 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
322 observers_->Notify(&Observer::OnExtensionActivity, action); 342 observers_->Notify(&Observer::OnExtensionActivity, action);
323 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 343 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
324 } 344 }
325 345
326 void ActivityLog::LogDOMAction(const std::string& extension_id, 346 void ActivityLog::LogDOMAction(const std::string& extension_id,
327 const GURL& url, 347 const GURL& url,
328 const string16& url_title, 348 const string16& url_title,
329 const std::string& api_call, 349 const std::string& api_call,
330 const ListValue* args, 350 const ListValue* args,
331 DomActionType::Type call_type, 351 DomActionType::Type call_type,
332 const std::string& extra) { 352 const std::string& extra) {
333 if (!IsLogEnabled() || 353 if (!IsLogEnabled() ||
334 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 354 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
335 if (call_type == DomActionType::METHOD && api_call == "XMLHttpRequest.open") 355 if (call_type == DomActionType::METHOD && api_call == "XMLHttpRequest.open")
336 call_type = DomActionType::XHR; 356 call_type = DomActionType::XHR;
357
358 if (policy_) {
359 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
360 std::string key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_DOM_ACTION);
361 details->SetInteger(key, static_cast<int>(call_type));
362 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_URL_TITLE);
363 details->SetString(key, url_title);
364 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
365 details->SetString(key, extra);
366 policy_->ProcessAction(
367 ActivityLogPolicy::ACTION_DOM,
368 extension_id,
369 api_call,
370 url,
371 args,
372 details.get());
373 }
374
375
376 // TODO(felt) Logging should be done more efficiently, so that it
377 // doesn't require construction of the action object.
337 scoped_refptr<DOMAction> action = new DOMAction( 378 scoped_refptr<DOMAction> action = new DOMAction(
338 extension_id, 379 extension_id,
339 base::Time::Now(), 380 base::Time::Now(),
340 call_type, 381 call_type,
341 url, 382 url,
342 url_title, 383 url_title,
343 api_call, 384 api_call,
344 MakeArgList(args), 385 MakeArgList(args),
345 extra); 386 extra);
346 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
347 observers_->Notify(&Observer::OnExtensionActivity, action); 387 observers_->Notify(&Observer::OnExtensionActivity, action);
348 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 388 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
349 } 389 }
350 390
351 void ActivityLog::LogWebRequestAction(const std::string& extension_id, 391 void ActivityLog::LogWebRequestAction(const std::string& extension_id,
352 const GURL& url, 392 const GURL& url,
353 const std::string& api_call, 393 const std::string& api_call,
354 scoped_ptr<DictionaryValue> details, 394 scoped_ptr<DictionaryValue> details,
355 const std::string& extra) { 395 const std::string& extra) {
356 string16 null_title; 396 string16 null_title;
357 if (!IsLogEnabled() || 397 if (!IsLogEnabled() ||
358 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return; 398 ActivityLogAPI::IsExtensionWhitelisted(extension_id)) return;
359 399
360 // Strip details of the web request modifications (for privacy reasons), 400 std::string details_string;
361 // unless testing is enabled. 401 if (policy_) {
362 if (!testing_mode_) { 402 scoped_ptr<base::DictionaryValue> details(new DictionaryValue());
363 DictionaryValue::Iterator details_iterator(*details); 403 std::string key = policy_->GetKey(
364 while (!details_iterator.IsAtEnd()) { 404 ActivityLogPolicy::PARAM_KEY_DETAILS_STRING);
365 details->SetBoolean(details_iterator.key(), true); 405 details->SetString(key, details_string);
366 details_iterator.Advance(); 406 key = policy_->GetKey(ActivityLogPolicy::PARAM_KEY_EXTRA);
367 } 407 details->SetString(key, extra);
408 policy_->ProcessAction(
409 ActivityLogPolicy::ACTION_WEB_REQUEST,
410 extension_id,
411 api_call,
412 url,
413 NULL,
414 details.get());
368 } 415 }
369 std::string details_string; 416
370 JSONStringValueSerializer serializer(&details_string); 417 JSONStringValueSerializer serializer(&details_string);
371 serializer.SerializeAndOmitBinaryValues(*details); 418 serializer.SerializeAndOmitBinaryValues(*details);
372 419
420 // TODO(felt) Logging should be done more efficiently, so that it
421 // doesn't require construction of the action object.
373 scoped_refptr<DOMAction> action = new DOMAction( 422 scoped_refptr<DOMAction> action = new DOMAction(
374 extension_id, 423 extension_id,
375 base::Time::Now(), 424 base::Time::Now(),
376 DomActionType::WEBREQUEST, 425 DomActionType::WEBREQUEST,
377 url, 426 url,
378 null_title, 427 null_title,
379 api_call, 428 api_call,
380 details_string, 429 details_string,
381 extra); 430 extra);
382 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
383 observers_->Notify(&Observer::OnExtensionActivity, action); 431 observers_->Notify(&Observer::OnExtensionActivity, action);
384 if (testing_mode_) LOG(INFO) << action->PrintForDebug(); 432 if (testing_mode_) LOG(INFO) << action->PrintForDebug();
385 } 433 }
386 434
387 void ActivityLog::GetActions( 435 void ActivityLog::GetActions(
388 const std::string& extension_id, 436 const std::string& extension_id,
389 const int day, 437 const int day,
390 const base::Callback 438 const base::Callback
391 <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>& callback) { 439 <void(scoped_ptr<std::vector<scoped_refptr<Action> > >)>& callback) {
392 if (!has_threads_) return; 440 if (policy_) {
393 BrowserThread::PostTaskAndReplyWithResult( 441 policy_->ReadData(extension_id, day, callback);
394 BrowserThread::DB, 442 }
395 FROM_HERE,
396 base::Bind(&ActivityDatabase::GetActions,
397 base::Unretained(db_),
398 extension_id,
399 day),
400 callback);
401 } 443 }
402 444
403 void ActivityLog::OnScriptsExecuted( 445 void ActivityLog::OnScriptsExecuted(
404 const content::WebContents* web_contents, 446 const content::WebContents* web_contents,
405 const ExecutingScriptsMap& extension_ids, 447 const ExecutingScriptsMap& extension_ids,
406 int32 on_page_id, 448 int32 on_page_id,
407 const GURL& on_url) { 449 const GURL& on_url) {
408 if (!IsLogEnabled()) return; 450 if (!IsLogEnabled()) return;
409 Profile* profile = 451 Profile* profile =
410 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 452 Profile::FromBrowserContext(web_contents->GetBrowserContext());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 web_contents->GetTitle(), 486 web_contents->GetTitle(),
445 std::string(), // no api call here 487 std::string(), // no api call here
446 script_names.get(), 488 script_names.get(),
447 DomActionType::INSERTED, 489 DomActionType::INSERTED,
448 extra); 490 extra);
449 } 491 }
450 } 492 }
451 } 493 }
452 494
453 } // namespace extensions 495 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698