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

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

Issue 11421192: Save extension activity log to a file. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: something about lkgr Created 7 years, 11 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 | Annotate | Revision Log
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 "chrome/browser/extensions/activity_log.h" 5 #include "chrome/browser/extensions/activity_log.h"
6 6
7 #include <set>
7 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/json/json_string_value_serializer.h"
8 #include "base/logging.h" 10 #include "base/logging.h"
9 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "base/threading/thread_checker.h"
13 #include "chrome/browser/extensions/api_actions.h"
14 #include "chrome/browser/extensions/blocked_actions.h"
10 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/extension_system.h" 16 #include "chrome/browser/extensions/extension_system.h"
12 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/common/chrome_constants.h"
13 #include "chrome/common/chrome_switches.h" 18 #include "chrome/common/chrome_switches.h"
14 #include "chrome/common/extensions/extension.h" 19 #include "chrome/common/extensions/extension.h"
15 #include "content/public/browser/web_contents.h" 20 #include "content/public/browser/web_contents.h"
16 #include "googleurl/src/gurl.h" 21 #include "googleurl/src/gurl.h"
22 #include "sql/error_delegate_util.h"
23 #include "third_party/re2/re2/re2.h"
24
25 namespace {
26
27 // Concatenate an API call with its arguments.
28 std::string MakeCallSignature(const std::string& name, const ListValue* args) {
29 std::string call_signature = name + "(";
30 ListValue::const_iterator it = args->begin();
31 for (; it != args->end(); ++it) {
32 std::string arg;
33 JSONStringValueSerializer serializer(&arg);
34 if (serializer.SerializeAndOmitBinaryValues(**it)) {
35 if (it != args->begin())
36 call_signature += ", ";
37 call_signature += arg;
38 }
39 }
40 call_signature += ")";
41 return call_signature;
42 }
43
44 } // namespace
17 45
18 namespace extensions { 46 namespace extensions {
19 47
20 ActivityLog::ActivityLog() { 48 // This handles errors from the database.
49 class KillActivityDatabaseErrorDelegate : public sql::ErrorDelegate {
50 public:
51 explicit KillActivityDatabaseErrorDelegate(ActivityLog* backend)
52 : backend_(backend),
53 scheduled_death_(false) {}
54
55 virtual int OnError(int error,
56 sql::Connection* connection,
57 sql::Statement* stmt) OVERRIDE {
58 if (!scheduled_death_ && sql::IsErrorCatastrophic(error)) {
59 ScheduleDeath();
60 }
61 return error;
62 }
63
64 // Schedules death if an error wasn't already reported.
65 void ScheduleDeath() {
66 if (!scheduled_death_) {
67 scheduled_death_ = true;
68 backend_->KillActivityLogDatabase();
69 }
70 }
71
72 bool scheduled_death() const {
73 return scheduled_death_;
74 }
75
76 private:
77 ActivityLog* backend_;
78 bool scheduled_death_;
79
80 DISALLOW_COPY_AND_ASSIGN(KillActivityDatabaseErrorDelegate);
81 };
82
83 // ActivityLogFactory
84
85 ActivityLogFactory* ActivityLogFactory::GetInstance() {
86 return Singleton<ActivityLogFactory>::get();
87 }
88
89 ProfileKeyedService* ActivityLogFactory::BuildServiceInstanceFor(
90 Profile* profile) const {
91 return new ActivityLog(profile);
92 }
93
94 bool ActivityLogFactory::ServiceRedirectedInIncognito() const {
95 return true;
96 }
97
98 // ActivityLog
99
100 // Use GetInstance instead of directly creating an ActivityLog.
101 ActivityLog::ActivityLog(Profile* profile) {
21 log_activity_to_stdout_ = CommandLine::ForCurrentProcess()-> 102 log_activity_to_stdout_ = CommandLine::ForCurrentProcess()->
22 HasSwitch(switches::kEnableExtensionActivityLogging); 103 HasSwitch(switches::kEnableExtensionActivityLogging);
104
105 // If the database cannot be initialized for some reason, we keep
106 // chugging along but nothing will get recorded. If the UI is
107 // available, things will still get sent to the UI even if nothing
108 // is being written to the database.
109 db_ = new ActivityDatabase();
110 #if defined(ENABLE_EXTENSIONS)
111 FilePath base_dir = profile->GetPath();
112 FilePath database_name = base_dir.Append(
113 chrome::kExtensionActivityLogFilename);
114 KillActivityDatabaseErrorDelegate* error_delegate =
115 new KillActivityDatabaseErrorDelegate(this);
116 db_->SetErrorDelegate(error_delegate);
117 ScheduleAndForget(&ActivityDatabase::Init,
118 database_name);
119 #endif
23 } 120 }
24 121
25 ActivityLog::~ActivityLog() { 122 ActivityLog::~ActivityLog() {
26 } 123 }
27 124
28 // static 125 // static
29 ActivityLog* ActivityLog::GetInstance() { 126 ActivityLog* ActivityLog::GetInstance(Profile* profile) {
30 return Singleton<ActivityLog>::get(); 127 return ActivityLogFactory::GetForProfile(profile);
31 } 128 }
32 129
33 void ActivityLog::AddObserver(const Extension* extension, 130 void ActivityLog::AddObserver(const Extension* extension,
34 ActivityLog::Observer* observer) { 131 ActivityLog::Observer* observer) {
35 base::AutoLock scoped_lock(lock_);
36
37 if (observers_.count(extension) == 0) { 132 if (observers_.count(extension) == 0) {
38 observers_[extension] = new ObserverListThreadSafe<Observer>; 133 observers_[extension] = new ObserverListThreadSafe<Observer>;
39 } 134 }
40 135
41 observers_[extension]->AddObserver(observer); 136 observers_[extension]->AddObserver(observer);
42 } 137 }
43 138
44 void ActivityLog::RemoveObserver(const Extension* extension, 139 void ActivityLog::RemoveObserver(const Extension* extension,
45 ActivityLog::Observer* observer) { 140 ActivityLog::Observer* observer) {
46 base::AutoLock scoped_lock(lock_);
47
48 if (observers_.count(extension) == 1) { 141 if (observers_.count(extension) == 1) {
49 observers_[extension]->RemoveObserver(observer); 142 observers_[extension]->RemoveObserver(observer);
50 } 143 }
51 } 144 }
52 145
53 // Extension*
54 bool ActivityLog::HasObservers(const Extension* extension) const { 146 bool ActivityLog::HasObservers(const Extension* extension) const {
55 base::AutoLock scoped_lock(lock_);
56
57 // We also return true if extension activity logging is enabled since in that 147 // We also return true if extension activity logging is enabled since in that
58 // case this class is observing all extensions. 148 // case this class is observing all extensions.
59 return observers_.count(extension) > 0 || log_activity_to_stdout_; 149 return observers_.count(extension) > 0 || log_activity_to_stdout_;
60 } 150 }
61 151
62 void ActivityLog::Log(const Extension* extension, 152 void ActivityLog::LogAPIAction(const Extension* extension,
63 Activity activity, 153 const std::string& name,
64 const std::string& message) const { 154 const ListValue* args,
65 std::vector<std::string> messages(1, message); 155 const std::string& extra) {
66 Log(extension, activity, messages); 156 std::string verb, manager;
67 } 157 bool matches = RE2::FullMatch(name, "(.*?)\\.(.*)", &manager, &verb);
158 if (matches) {
159 std::string call_signature = MakeCallSignature(name, args);
160 scoped_refptr<APIAction> action = new APIAction(
161 extension->id(),
162 base::Time::Now(),
163 APIAction::StringAsActionType(verb),
164 APIAction::StringAsTargetType(manager),
165 call_signature,
166 extra);
167 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
68 168
69 void ActivityLog::Log(const Extension* extension, 169 // Display the action.
70 Activity activity, 170 ObserverMap::const_iterator iter = observers_.find(extension);
71 const std::vector<std::string>& messages) const { 171 if (iter != observers_.end()) {
72 base::AutoLock scoped_lock(lock_); 172 iter->second->Notify(&Observer::OnExtensionActivity,
73 173 extension,
74 ObserverMap::const_iterator iter = observers_.find(extension); 174 ActivityLog::ACTIVITY_EXTENSION_API_CALL,
75 if (iter != observers_.end()) { 175 call_signature);
76 iter->second->Notify(&Observer::OnExtensionActivity, extension, activity, 176 }
77 messages); 177 if (log_activity_to_stdout_) {
78 } 178 LOG(INFO) << action->PrettyPrintForDebug();
79 179 }
80 if (log_activity_to_stdout_) { 180 } else {
81 LOG(INFO) << extension->id() << ":" << ActivityToString(activity) << ":" << 181 LOG(ERROR) << "Unknown API call! " << name;
82 JoinString(messages, ' ');
83 } 182 }
84 } 183 }
85 184
185 void ActivityLog::LogBlockedAction(const Extension* extension,
186 const std::string& blocked_name,
187 const ListValue* args,
188 const char* reason,
189 const std::string& extra) {
190 std::string blocked_call = MakeCallSignature(blocked_name, args);
191 scoped_refptr<BlockedAction> action = new BlockedAction(extension->id(),
192 base::Time::Now(),
193 blocked_call,
194 std::string(reason),
195 extra);
196 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
197 // Display the action.
198 ObserverMap::const_iterator iter = observers_.find(extension);
199 if (iter != observers_.end()) {
200 iter->second->Notify(&Observer::OnExtensionActivity,
201 extension,
202 ActivityLog::ACTIVITY_EXTENSION_API_BLOCK,
203 blocked_call);
204 }
205 if (log_activity_to_stdout_) {
206 LOG(INFO) << action->PrettyPrintForDebug();
207 }
208 }
209
210 void ActivityLog::LogUrlAction(const Extension* extension,
211 const UrlAction::UrlActionType verb,
212 const GURL& url,
213 const string16& url_title,
214 const std::string& technical_message,
215 const std::string& extra) {
216 scoped_refptr<UrlAction> action = new UrlAction(
217 extension->id(),
218 base::Time::Now(),
219 verb,
220 url,
221 url_title,
222 technical_message,
223 extra);
224 ScheduleAndForget(&ActivityDatabase::RecordAction, action);
225
226 // Display the action.
227 ObserverMap::const_iterator iter = observers_.find(extension);
228 if (iter != observers_.end()) {
229 iter->second->Notify(&Observer::OnExtensionActivity,
230 extension,
231 ActivityLog::ACTIVITY_CONTENT_SCRIPT,
232 action->PrettyPrintForDebug());
233 }
234 if (log_activity_to_stdout_) {
235 LOG(INFO) << action->PrettyPrintForDebug();
236 }
237 }
238
86 void ActivityLog::OnScriptsExecuted( 239 void ActivityLog::OnScriptsExecuted(
87 const content::WebContents* web_contents, 240 const content::WebContents* web_contents,
88 const ExecutingScriptsMap& extension_ids, 241 const ExecutingScriptsMap& extension_ids,
89 int32 on_page_id, 242 int32 on_page_id,
90 const GURL& on_url) { 243 const GURL& on_url) {
91 Profile* profile = 244 Profile* profile =
92 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 245 Profile::FromBrowserContext(web_contents->GetBrowserContext());
93 const ExtensionService* extension_service = 246 const ExtensionService* extension_service =
94 ExtensionSystem::Get(profile)->extension_service(); 247 ExtensionSystem::Get(profile)->extension_service();
95 const ExtensionSet* extensions = extension_service->extensions(); 248 const ExtensionSet* extensions = extension_service->extensions();
96 249
97 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin(); 250 for (ExecutingScriptsMap::const_iterator it = extension_ids.begin();
98 it != extension_ids.end(); ++it) { 251 it != extension_ids.end(); ++it) {
99 const Extension* extension = extensions->GetByID(it->first); 252 const Extension* extension = extensions->GetByID(it->first);
100 if (!extension || !HasObservers(extension)) 253 if (!extension || !HasObservers(extension))
101 continue; 254 continue;
102 255
103 for (std::set<std::string>::const_iterator it2 = it->second.begin(); 256 // If OnScriptsExecuted is fired because of tabs.executeScript, the list
104 it2 != it->second.end(); ++it2) { 257 // of content scripts will be empty. We don't want to log it because
105 std::vector<std::string> messages; 258 // the call to tabs.executeScript will have already been logged anyway.
106 messages.push_back(on_url.spec()); 259 if (!it->second.empty()) {
107 messages.push_back(*it2); 260 std::string ext_scripts_str = "";
108 Log(extension, ActivityLog::ACTIVITY_CONTENT_SCRIPT, messages); 261 for (std::set<std::string>::const_iterator it2 = it->second.begin();
262 it2 != it->second.end(); ++it2) {
263 ext_scripts_str += *it2;
264 ext_scripts_str += " ";
265 }
266 LogUrlAction(extension,
267 UrlAction::INSERTED,
268 on_url,
269 web_contents->GetTitle(),
270 ext_scripts_str,
271 "");
109 } 272 }
110 } 273 }
111 } 274 }
112 275
276 void ActivityLog::KillActivityLogDatabase() {
277 if (db_.get()) {
278 ScheduleAndForget(&ActivityDatabase::KillDatabase);
279 }
280 }
281
113 // static 282 // static
114 const char* ActivityLog::ActivityToString(Activity activity) { 283 const char* ActivityLog::ActivityToString(Activity activity) {
115 switch (activity) { 284 switch (activity) {
116 case ActivityLog::ACTIVITY_EXTENSION_API_CALL: 285 case ActivityLog::ACTIVITY_EXTENSION_API_CALL:
117 return "api_call"; 286 return "api_call";
118 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK: 287 case ActivityLog::ACTIVITY_EXTENSION_API_BLOCK:
119 return "api_block"; 288 return "api_block";
120 case ActivityLog::ACTIVITY_CONTENT_SCRIPT: 289 case ActivityLog::ACTIVITY_CONTENT_SCRIPT:
121 return "content_script"; 290 return "content_script";
122 default: 291 default:
123 NOTREACHED(); 292 NOTREACHED();
124 return ""; 293 return "";
125 } 294 }
126 } 295 }
127 296
128 } // namespace extensions 297 } // namespace extensions
298
OLDNEW
« no previous file with comments | « chrome/browser/extensions/activity_log.h ('k') | chrome/browser/extensions/activity_log_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698