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

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

Issue 19690003: Extension activity log database refactoring (step 3) (Closed) Base URL: http://git.chromium.org/chromium/src.git@refactor2
Patch Set: Do not set bad BlockedChromeActivityDetail::Reason values Created 7 years, 5 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) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 <string> 5 #include <string>
6 #include "base/command_line.h"
6 #include "base/json/json_string_value_serializer.h" 7 #include "base/json/json_string_value_serializer.h"
7 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/singleton.h"
10 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/extensions/activity_log/activity_actions.h" 12 #include "chrome/browser/extensions/activity_log/activity_actions.h"
13 #include "chrome/browser/extensions/activity_log/api_name_constants.h"
14 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
15 #include "chrome/browser/extensions/extension_tab_util.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/web_contents.h"
20 #include "sql/statement.h"
10 21
11 namespace { 22 namespace {
12 23
13 std::string Serialize(const base::Value* value) { 24 std::string Serialize(const base::Value* value) {
14 std::string value_as_text; 25 std::string value_as_text;
15 if (!value) { 26 if (!value) {
16 value_as_text = "null"; 27 value_as_text = "null";
17 } else { 28 } else {
18 JSONStringValueSerializer serializer(&value_as_text); 29 JSONStringValueSerializer serializer(&value_as_text);
19 serializer.SerializeAndOmitBinaryValues(*value); 30 serializer.SerializeAndOmitBinaryValues(*value);
20 } 31 }
21 return value_as_text; 32 return value_as_text;
22 } 33 }
23 34
35 // Gets the URL for a given tab ID. Helper method for APIAction::LookupTabId.
36 std::string GetUrlForTabId(int tab_id, Profile* profile) {
37 content::WebContents* contents = NULL;
38 Browser* browser = NULL;
39 bool found = ExtensionTabUtil::GetTabById(tab_id,
40 profile,
41 true, // search incognito tabs too
42 &browser,
43 NULL,
44 &contents,
45 NULL);
46 if (found) {
47 // Check whether the profile the tab was found in is a normal or incognito
48 // profile.
49 if (!browser->profile()->IsOffTheRecord()) {
50 GURL url = contents->GetURL();
51 return std::string(url.spec());
52 } else {
53 return std::string(extensions::APIAction::kIncognitoUrl);
54 }
55 } else {
56 return std::string();
57 }
58 }
59
60 // Sets up the hashmap for mapping extension strings to "ints". The hashmap is
61 // only set up once because it's quite long; the value is then cached.
62 class APINameMap {
63 public:
64 APINameMap() {
65 SetupMap();
66 }
67
68 // activity_log_api_name_constants.h lists all known API calls as of 5/17.
69 // This code maps each of those API calls (and events) to short strings
70 // (integers converted to strings). They're all strings because (1) sqlite
71 // databases are all strings underneath anyway and (2) the Lookup function
72 // will simply return the original api_call string if we don't have it in our
73 // lookup table.
74 void SetupMap() {
75 for (size_t i = 0;
76 i < arraysize(activity_log_api_name_constants::kNames);
77 ++i) {
78 std::string name =
79 std::string(activity_log_api_name_constants::kNames[i]);
80 std::string num = base::IntToString(i);
81 names_to_nums_[name] = num;
82 nums_to_names_[num] = name;
83 }
84 }
85
86 static APINameMap* GetInstance() {
87 return Singleton<APINameMap>::get();
88 }
89
90 // This matches an api call to a number, if it's in the lookup table. If not,
91 // it returns the original api call.
92 const std::string& ApiToShortname(const std::string& api_call) {
93 std::map<std::string, std::string>::iterator it =
94 names_to_nums_.find(api_call);
95 if (it == names_to_nums_.end())
96 return api_call;
97 else
98 return it->second;
99 }
100
101 // This matches a number to an API call -- it's the opposite of
102 // ApiToShortname.
103 const std::string& ShortnameToApi(const std::string& shortname) {
104 std::map<std::string, std::string>::iterator it =
105 nums_to_names_.find(shortname);
106 if (it == nums_to_names_.end())
107 return shortname;
108 else
109 return it->second;
110 }
111
112 private:
113 std::map<std::string, std::string> names_to_nums_; // <name, number label>
114 std::map<std::string, std::string> nums_to_names_; // <number label, name>
115 };
116
24 } // namespace 117 } // namespace
25 118
26 namespace extensions { 119 namespace extensions {
27 120
121 using api::activity_log_private::BlockedChromeActivityDetail;
122 using api::activity_log_private::ChromeActivityDetail;
123 using api::activity_log_private::DomActivityDetail;
28 using api::activity_log_private::ExtensionActivity; 124 using api::activity_log_private::ExtensionActivity;
29 125
126 // We should log the arguments to these API calls, even if argument logging is
127 // disabled by default.
128 const char* APIAction::kAlwaysLog[] =
129 {"extension.connect", "extension.sendMessage",
130 "tabs.executeScript", "tabs.insertCSS" };
131 const int APIAction::kSizeAlwaysLog = arraysize(kAlwaysLog);
132
133 // A string used in place of the real URL when the URL is hidden because it is
134 // in an incognito window. Extension activity logs mentioning kIncognitoUrl
135 // let the user know that an extension is manipulating incognito tabs without
136 // recording specific data about the pages.
137 const char* APIAction::kIncognitoUrl = "http://incognito/";
138
139 // static
140 void APIAction::LookupTabId(const std::string& api_call,
141 base::ListValue* args,
142 Profile* profile) {
143 if (api_call == "tabs.get" || // api calls, ID as int
144 api_call == "tabs.connect" ||
145 api_call == "tabs.sendMessage" ||
146 api_call == "tabs.duplicate" ||
147 api_call == "tabs.update" ||
148 api_call == "tabs.reload" ||
149 api_call == "tabs.detectLanguage" ||
150 api_call == "tabs.executeScript" ||
151 api_call == "tabs.insertCSS" ||
152 api_call == "tabs.move" || // api calls, IDs in array
153 api_call == "tabs.remove" ||
154 api_call == "tabs.onUpdated" || // events, ID as int
155 api_call == "tabs.onMoved" ||
156 api_call == "tabs.onDetached" ||
157 api_call == "tabs.onAttached" ||
158 api_call == "tabs.onRemoved" ||
159 api_call == "tabs.onReplaced") {
160 int tab_id;
161 base::ListValue* id_list;
162 if (args->GetInteger(0, &tab_id)) {
163 std::string url = GetUrlForTabId(tab_id, profile);
164 if (url != std::string())
165 args->Set(0, new base::StringValue(url));
166 } else if ((api_call == "tabs.move" || api_call == "tabs.remove") &&
167 args->GetList(0, &id_list)) {
168 for (int i = 0; i < static_cast<int>(id_list->GetSize()); ++i) {
169 if (id_list->GetInteger(i, &tab_id)) {
170 std::string url = GetUrlForTabId(tab_id, profile);
171 if (url != std::string())
172 id_list->Set(i, new base::StringValue(url));
173 } else {
174 LOG(ERROR) << "The tab ID array is malformed at index " << i;
175 }
176 }
177 }
178 }
179 }
180
30 Action::Action(const std::string& extension_id, 181 Action::Action(const std::string& extension_id,
31 const base::Time& time, 182 const base::Time& time,
32 ExtensionActivity::ActivityType activity_type) 183 const ActionType action_type,
184 const std::string& api_name)
33 : extension_id_(extension_id), 185 : extension_id_(extension_id),
34 time_(time), 186 time_(time),
35 activity_type_(activity_type) {}
36
37 WatchdogAction::WatchdogAction(const std::string& extension_id,
38 const base::Time& time,
39 const ActionType action_type,
40 const std::string& api_name,
41 scoped_ptr<ListValue> args,
42 const GURL& page_url,
43 const GURL& arg_url,
44 scoped_ptr<DictionaryValue> other)
45 : Action(extension_id, time, ExtensionActivity::ACTIVITY_TYPE_CHROME),
46 action_type_(action_type), 187 action_type_(action_type),
47 api_name_(api_name), 188 api_name_(api_name) {}
48 args_(args.Pass()), 189
49 page_url_(page_url), 190 Action::~Action() {}
50 arg_url_(arg_url), 191
51 other_(other.Pass()) {} 192 void Action::set_args(scoped_ptr<ListValue> args) {
52 193 args_.reset(args.release());
53 WatchdogAction::~WatchdogAction() {} 194 }
54 195
55 bool WatchdogAction::Record(sql::Connection* db) { 196 ListValue* Action::mutable_args() {
56 // This methods isn't used and will go away entirely soon once database 197 if (!args_.get()) {
57 // writing moves to the policy objects. 198 args_.reset(new ListValue());
58 NOTREACHED(); 199 }
200 return args_.get();
201 }
202
203 void Action::set_page_url(const GURL& page_url) {
204 page_url_ = page_url;
205 }
206
207 void Action::set_arg_url(const GURL& arg_url) {
208 arg_url_ = arg_url;
209 }
210
211 void Action::set_other(scoped_ptr<DictionaryValue> other) {
212 other_.reset(other.release());
213 }
214
215 DictionaryValue* Action::mutable_other() {
216 if (!other_.get()) {
217 other_.reset(new DictionaryValue());
218 }
219 return other_.get();
220 }
221
222 bool Action::Record(sql::Connection* db) {
223 std::string sql_str =
224 "INSERT INTO " + std::string(FullStreamUIPolicy::kTableName) +
225 " (extension_id, time, action_type, api_name, args, "
226 "page_url, page_title, arg_url, other) VALUES (?,?,?,?,?,?,?,?,?)";
227 sql::Statement statement(db->GetCachedStatement(
228 sql::StatementID(SQL_FROM_HERE), sql_str.c_str()));
229 statement.BindString(0, extension_id());
230 statement.BindInt64(1, time().ToInternalValue());
231 statement.BindInt(2, static_cast<int>(action_type()));
232 statement.BindString(3, api_name());
233 if (args()) {
234 statement.BindString(4, Serialize(args()));
235 } else {
236 statement.BindNull(4);
237 }
238 if (other()) {
239 statement.BindString(8, Serialize(other()));
240 } else {
241 statement.BindNull(8);
242 }
243
244 url_canon::Replacements<char> url_sanitizer;
245 if (!CommandLine::ForCurrentProcess()->HasSwitch(
246 switches::kEnableExtensionActivityLogTesting)) {
247 url_sanitizer.ClearQuery();
248 url_sanitizer.ClearRef();
249 }
250 if (page_url().is_valid()) {
251 statement.BindString(5, page_url().ReplaceComponents(url_sanitizer).spec());
252 }
253 statement.BindString(6, page_title());
254 if (arg_url().is_valid()) {
255 statement.BindString(7, arg_url().ReplaceComponents(url_sanitizer).spec());
256 }
257
258 if (!statement.Run()) {
259 LOG(ERROR) << "Activity log database I/O failed: " << sql_str;
260 statement.Clear();
261 return false;
262 }
59 return true; 263 return true;
60 } 264 }
61 265
62 scoped_ptr<api::activity_log_private::ExtensionActivity> 266 scoped_ptr<ExtensionActivity> Action::ConvertToExtensionActivity() {
63 WatchdogAction::ConvertToExtensionActivity() { 267 scoped_ptr<ExtensionActivity> result(new ExtensionActivity);
64 scoped_ptr<api::activity_log_private::ExtensionActivity> result; 268
269 result->extension_id.reset(new std::string(extension_id()));
270 result->time.reset(new double(time().ToJsTime()));
271
272 switch (action_type()) {
273 case ACTION_API_CALL:
274 case ACTION_API_EVENT: {
275 ChromeActivityDetail* details = new ChromeActivityDetail;
276 if (action_type() == ACTION_API_CALL) {
277 details->api_activity_type =
278 ChromeActivityDetail::API_ACTIVITY_TYPE_CALL;
279 } else {
280 details->api_activity_type =
281 ChromeActivityDetail::API_ACTIVITY_TYPE_EVENT_CALLBACK;
282 }
283 details->api_call.reset(new std::string(api_name()));
284 details->args.reset(new std::string(Serialize(args())));
285 details->extra.reset(new std::string(Serialize(other())));
286
287 result->activity_type = ExtensionActivity::ACTIVITY_TYPE_CHROME;
288 result->chrome_activity_detail.reset(details);
289 break;
290 }
291
292 case ACTION_API_BLOCKED: {
293 BlockedChromeActivityDetail* details = new BlockedChromeActivityDetail;
294 details->api_call.reset(new std::string(api_name()));
295 details->args.reset(new std::string(Serialize(args())));
296 details->extra.reset(new std::string(Serialize(other())));
297 // TODO(mvrable): details->reason isn't filled in; fix this after
298 // converting logging to using the types from
299 // BlockedChromeActivityDetail::Reason.
300 details->reason = BlockedChromeActivityDetail::REASON_NONE;
301
302 result->activity_type = ExtensionActivity::ACTIVITY_TYPE_BLOCKED_CHROME;
303 result->blocked_chrome_activity_detail.reset(details);
304 break;
305 }
306
307 case ACTION_DOM_EVENT:
308 case ACTION_DOM_XHR:
309 case ACTION_DOM_ACCESS:
310 case ACTION_CONTENT_SCRIPT:
311 case ACTION_WEB_REQUEST: {
312 DomActivityDetail* details = new DomActivityDetail;
313
314 if (action_type() == ACTION_WEB_REQUEST) {
315 details->dom_activity_type =
316 DomActivityDetail::DOM_ACTIVITY_TYPE_WEBREQUEST;
317 } else if (action_type() == ACTION_CONTENT_SCRIPT) {
318 details->dom_activity_type =
319 DomActivityDetail::DOM_ACTIVITY_TYPE_INSERTED;
320 } else {
321 // TODO(mvrable): This ought to be filled in properly, but since the
322 // API will change soon don't worry about it now.
323 details->dom_activity_type =
324 DomActivityDetail::DOM_ACTIVITY_TYPE_NONE;
325 }
326 details->api_call.reset(new std::string(api_name()));
327 details->args.reset(new std::string(Serialize(args())));
328 details->extra.reset(new std::string(Serialize(other())));
329 details->url.reset(new std::string(page_url().spec()));
330 if (!page_title().empty())
331 details->url_title.reset(new std::string(page_title()));
332
333 result->activity_type = ExtensionActivity::ACTIVITY_TYPE_DOM;
334 result->dom_activity_detail.reset(details);
335 break;
336 }
337
338 default:
339 LOG(WARNING) << "Bad activity log entry read from database (type="
340 << action_type_ << ")!";
341 }
342
65 return result.Pass(); 343 return result.Pass();
66 } 344 }
67 345
68 std::string WatchdogAction::PrintForDebug() { 346 std::string Action::PrintForDebug() {
69 std::string result = "ID=" + extension_id() + " CATEGORY="; 347 std::string result = "ID=" + extension_id() + " CATEGORY=";
70 switch (action_type_) { 348 switch (action_type_) {
71 case ACTION_API_CALL: 349 case ACTION_API_CALL:
72 result += "api_call"; 350 result += "api_call";
73 break; 351 break;
74 case ACTION_API_EVENT: 352 case ACTION_API_EVENT:
75 result += "api_event_callback"; 353 result += "api_event_callback";
76 break; 354 break;
77 case ACTION_WEB_REQUEST: 355 case ACTION_WEB_REQUEST:
78 result += "webrequest"; 356 result += "webrequest";
(...skipping 17 matching lines...) Expand all
96 result += base::StringPrintf("type%d", static_cast<int>(action_type_)); 374 result += base::StringPrintf("type%d", static_cast<int>(action_type_));
97 } 375 }
98 376
99 result += " API=" + api_name_; 377 result += " API=" + api_name_;
100 if (args_.get()) { 378 if (args_.get()) {
101 result += " ARGS=" + Serialize(args_.get()); 379 result += " ARGS=" + Serialize(args_.get());
102 } 380 }
103 if (page_url_.is_valid()) { 381 if (page_url_.is_valid()) {
104 result += " PAGE_URL=" + page_url_.spec(); 382 result += " PAGE_URL=" + page_url_.spec();
105 } 383 }
384 if (!page_title_.empty()) {
385 StringValue title(page_title_);
386 result += " PAGE_TITLE=" + Serialize(&title);
387 }
106 if (arg_url_.is_valid()) { 388 if (arg_url_.is_valid()) {
107 result += " ARG_URL=" + arg_url_.spec(); 389 result += " ARG_URL=" + arg_url_.spec();
108 } 390 }
109 if (other_.get()) { 391 if (other_.get()) {
110 result += " OTHER=" + Serialize(other_.get()); 392 result += " OTHER=" + Serialize(other_.get());
111 } 393 }
112 394
113 return result; 395 return result;
114 } 396 }
115 397
116 } // namespace extensions 398 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/activity_log/activity_actions.h ('k') | chrome/browser/extensions/activity_log/activity_database.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698