| OLD | NEW |
| 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 "base/logging.h" | 5 #include "base/logging.h" |
| 6 #include "base/memory/singleton.h" |
| 7 #include "base/string_number_conversions.h" |
| 6 #include "base/stringprintf.h" | 8 #include "base/stringprintf.h" |
| 7 #include "chrome/browser/extensions/activity_log/api_actions.h" | 9 #include "chrome/browser/extensions/activity_log/api_actions.h" |
| 10 #include "chrome/browser/extensions/activity_log/api_name_constants.h" |
| 8 #include "chrome/browser/extensions/extension_tab_util.h" | 11 #include "chrome/browser/extensions/extension_tab_util.h" |
| 9 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
| 10 #include "content/public/browser/web_contents.h" | 13 #include "content/public/browser/web_contents.h" |
| 11 #include "googleurl/src/gurl.h" | 14 #include "googleurl/src/gurl.h" |
| 12 | 15 |
| 13 using content::BrowserThread; | 16 using content::BrowserThread; |
| 14 | 17 |
| 15 namespace { | 18 namespace { |
| 16 | 19 |
| 17 // Gets the URL for a given tab ID. Helper method for APIAction::LookupTabId. | 20 // Gets the URL for a given tab ID. Helper method for APIAction::LookupTabId. |
| 18 std::string GetURLForTabId(const int tab_id, Profile* profile) { | 21 std::string GetURLForTabId(const int tab_id, Profile* profile) { |
| 19 content::WebContents* contents = NULL; | 22 content::WebContents* contents = NULL; |
| 20 bool found = ExtensionTabUtil::GetTabById(tab_id, | 23 bool found = ExtensionTabUtil::GetTabById(tab_id, |
| 21 profile, | 24 profile, |
| 22 false, // no incognito URLs | 25 false, // no incognito URLs |
| 23 NULL, | 26 NULL, |
| 24 NULL, | 27 NULL, |
| 25 &contents, | 28 &contents, |
| 26 NULL); | 29 NULL); |
| 27 if (found) { | 30 if (found) { |
| 28 GURL url = contents->GetURL(); | 31 GURL url = contents->GetURL(); |
| 29 return std::string(url.spec()); | 32 return std::string(url.spec()); |
| 30 } else { | 33 } else { |
| 31 return std::string(); | 34 return std::string(); |
| 32 } | 35 } |
| 33 } | 36 } |
| 34 | 37 |
| 38 // Sets up the hashmap for mapping extension strings to "ints". The hashmap is |
| 39 // only set up once because it's quite long; the value is then cached. |
| 40 class APINameMap { |
| 41 public: |
| 42 APINameMap() { |
| 43 SetupMap(); |
| 44 } |
| 45 |
| 46 // activity_log_api_name_constants.h lists all known API calls as of 5/17. |
| 47 // This code maps each of those API calls (and events) to short strings |
| 48 // (integers converted to strings). They're all strings because (1) sqlite |
| 49 // databases are all strings underneath anyway and (2) the Lookup function |
| 50 // will simply return the original api_call string if we don't have it in our |
| 51 // lookup table. |
| 52 void SetupMap() { |
| 53 for (size_t i = 0; |
| 54 i < arraysize(activity_log_api_name_constants::kNames); |
| 55 ++i) { |
| 56 std::string name = |
| 57 std::string(activity_log_api_name_constants::kNames[i]); |
| 58 std::string num = base::IntToString(i); |
| 59 names_to_nums_[name] = num; |
| 60 nums_to_names_[num] = name; |
| 61 } |
| 62 } |
| 63 |
| 64 static APINameMap* GetInstance() { |
| 65 return Singleton<APINameMap>::get(); |
| 66 } |
| 67 |
| 68 // This matches an api call to a number, if it's in the lookup table. If not, |
| 69 // it returns the original api call. |
| 70 const std::string& ApiToShortname(const std::string& api_call) { |
| 71 std::map<std::string, std::string>::iterator it = |
| 72 names_to_nums_.find(api_call); |
| 73 if (it == names_to_nums_.end()) |
| 74 return api_call; |
| 75 else |
| 76 return it->second; |
| 77 } |
| 78 |
| 79 // This matches a number to an API call -- it's the opposite of |
| 80 // ApiToShortname. |
| 81 const std::string& ShortnameToApi(const std::string& shortname) { |
| 82 std::map<std::string, std::string>::iterator it = |
| 83 nums_to_names_.find(shortname); |
| 84 if (it == nums_to_names_.end()) |
| 85 return shortname; |
| 86 else |
| 87 return it->second; |
| 88 } |
| 89 |
| 90 private: |
| 91 std::map<std::string, std::string> names_to_nums_; // <name, number label> |
| 92 std::map<std::string, std::string> nums_to_names_; // <number label, name> |
| 93 }; |
| 94 |
| 35 } // namespace | 95 } // namespace |
| 36 | 96 |
| 37 namespace extensions { | 97 namespace extensions { |
| 38 | 98 |
| 39 const char* APIAction::kTableName = "activitylog_apis"; | 99 const char* APIAction::kTableName = "activitylog_apis"; |
| 40 const char* APIAction::kTableContentFields[] = | 100 const char* APIAction::kTableContentFields[] = |
| 41 {"api_type", "api_call", "args", "extra"}; | 101 {"api_type", "api_call", "args", "extra"}; |
| 102 const char* APIAction::kTableFieldTypes[] = |
| 103 {"INTEGER", "LONGVARCHAR", "LONGVARCHAR", "LONGVARCHAR"}; |
| 42 | 104 |
| 43 // We should log the arguments to these API calls, even if argument logging is | 105 // We should log the arguments to these API calls, even if argument logging is |
| 44 // disabled by default. | 106 // disabled by default. |
| 45 const char* APIAction::kAlwaysLog[] = | 107 const char* APIAction::kAlwaysLog[] = |
| 46 {"extension.connect", "extension.sendMessage", | 108 {"extension.connect", "extension.sendMessage", |
| 47 "tabs.executeScript", "tabs.insertCSS" }; | 109 "tabs.executeScript", "tabs.insertCSS" }; |
| 48 const int APIAction::kSizeAlwaysLog = arraysize(kAlwaysLog); | 110 const int APIAction::kSizeAlwaysLog = arraysize(kAlwaysLog); |
| 49 | 111 |
| 50 APIAction::APIAction(const std::string& extension_id, | 112 APIAction::APIAction(const std::string& extension_id, |
| 51 const base::Time& time, | 113 const base::Time& time, |
| 52 const Type type, | 114 const Type type, |
| 53 const std::string& api_call, | 115 const std::string& api_call, |
| 54 const std::string& args, | 116 const std::string& args, |
| 55 const std::string& extra) | 117 const std::string& extra) |
| 56 : Action(extension_id, time), | 118 : Action(extension_id, time), |
| 57 type_(type), | 119 type_(type), |
| 58 api_call_(api_call), | 120 api_call_(api_call), |
| 59 args_(args), | 121 args_(args), |
| 60 extra_(extra) { } | 122 extra_(extra) { } |
| 61 | 123 |
| 62 APIAction::APIAction(const sql::Statement& s) | 124 APIAction::APIAction(const sql::Statement& s) |
| 63 : Action(s.ColumnString(0), | 125 : Action(s.ColumnString(0), |
| 64 base::Time::FromInternalValue(s.ColumnInt64(1))), | 126 base::Time::FromInternalValue(s.ColumnInt64(1))), |
| 65 type_(StringAsType(s.ColumnString(2))), | 127 type_(static_cast<Type>(s.ColumnInt(2))), |
| 66 api_call_(s.ColumnString(3)), | 128 api_call_(APINameMap::GetInstance()->ShortnameToApi(s.ColumnString(3))), |
| 67 args_(s.ColumnString(4)), | 129 args_(s.ColumnString(4)), |
| 68 extra_(s.ColumnString(5)) { } | 130 extra_(s.ColumnString(5)) { } |
| 69 | 131 |
| 70 APIAction::~APIAction() { | 132 APIAction::~APIAction() { |
| 71 } | 133 } |
| 72 | 134 |
| 73 // static | 135 // static |
| 74 bool APIAction::InitializeTable(sql::Connection* db) { | 136 bool APIAction::InitializeTable(sql::Connection* db) { |
| 75 // The original table schema was different than the existing one. | 137 // The original table schema was different than the existing one. |
| 76 // We no longer want the api_action_type or target_type columns. | 138 // We no longer want the api_action_type or target_type columns. |
| 77 // Sqlite doesn't let you delete or modify existing columns, so we drop it. | 139 // Sqlite doesn't let you delete or modify existing columns, so we drop it. |
| 78 // Any data loss incurred here doesn't matter since these fields existed | 140 // Any data loss incurred here doesn't matter since these fields existed |
| 79 // before we started using the AL for anything. | 141 // before we started using the AL for anything. |
| 80 if (db->DoesColumnExist(kTableName, "api_action_type")) { | 142 if (db->DoesColumnExist(kTableName, "api_action_type")) { |
| 81 std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName); | 143 std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName); |
| 82 if (!db->Execute(drop_table.c_str())) | 144 if (!db->Execute(drop_table.c_str())) |
| 83 return false; | 145 return false; |
| 84 } | 146 } |
| 147 // We also now use INTEGER instead of VARCHAR for api_type. |
| 148 if (db->DoesColumnExist(kTableName, "api_type")) { |
| 149 std::string select = base::StringPrintf( |
| 150 "SELECT api_type FROM %s ORDER BY rowid LIMIT 1", kTableName); |
| 151 sql::Statement statement(db->GetUniqueStatement(select.c_str())); |
| 152 if (statement.DeclaredColumnType(0) != sql::COLUMN_TYPE_INTEGER) { |
| 153 std::string drop_table = base::StringPrintf("DROP TABLE %s", kTableName); |
| 154 if (!db->Execute(drop_table.c_str())) |
| 155 return false; |
| 156 } |
| 157 } |
| 85 // Now initialize the table. | 158 // Now initialize the table. |
| 86 return InitializeTableInternal(db, | 159 return InitializeTableInternal(db, |
| 87 kTableName, | 160 kTableName, |
| 88 kTableContentFields, | 161 kTableContentFields, |
| 162 kTableFieldTypes, |
| 89 arraysize(kTableContentFields)); | 163 arraysize(kTableContentFields)); |
| 90 } | 164 } |
| 91 | 165 |
| 92 void APIAction::Record(sql::Connection* db) { | 166 void APIAction::Record(sql::Connection* db) { |
| 93 std::string sql_str = "INSERT INTO " + std::string(kTableName) | 167 std::string sql_str = "INSERT INTO " + std::string(kTableName) |
| 94 + " (extension_id, time, api_type, api_call, args, extra) VALUES" | 168 + " (extension_id, time, api_type, api_call, args, extra) VALUES" |
| 95 " (?,?,?,?,?,?)"; | 169 " (?,?,?,?,?,?)"; |
| 96 sql::Statement statement(db->GetCachedStatement( | 170 sql::Statement statement(db->GetCachedStatement( |
| 97 sql::StatementID(SQL_FROM_HERE), sql_str.c_str())); | 171 sql::StatementID(SQL_FROM_HERE), sql_str.c_str())); |
| 98 statement.BindString(0, extension_id()); | 172 statement.BindString(0, extension_id()); |
| 99 statement.BindInt64(1, time().ToInternalValue()); | 173 statement.BindInt64(1, time().ToInternalValue()); |
| 100 statement.BindString(2, TypeAsString()); | 174 statement.BindInt(2, static_cast<int>(type_)); |
| 101 statement.BindString(3, api_call_); | 175 statement.BindString(3, APINameMap::GetInstance()->ApiToShortname(api_call_)); |
| 102 statement.BindString(4, args_); | 176 statement.BindString(4, args_); |
| 103 statement.BindString(5, extra_); | 177 statement.BindString(5, extra_); |
| 104 if (!statement.Run()) | 178 if (!statement.Run()) |
| 105 LOG(ERROR) << "Activity log database I/O failed: " << sql_str; | 179 LOG(ERROR) << "Activity log database I/O failed: " << sql_str; |
| 106 } | 180 } |
| 107 | 181 |
| 108 // static | 182 // static |
| 109 void APIAction::LookupTabId(const std::string& api_call, | 183 void APIAction::LookupTabId(const std::string& api_call, |
| 110 ListValue* args, | 184 ListValue* args, |
| 111 Profile* profile) { | 185 Profile* profile) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 switch (type_) { | 230 switch (type_) { |
| 157 case CALL: | 231 case CALL: |
| 158 return "CALL"; | 232 return "CALL"; |
| 159 case EVENT_CALLBACK: | 233 case EVENT_CALLBACK: |
| 160 return "EVENT_CALLBACK"; | 234 return "EVENT_CALLBACK"; |
| 161 default: | 235 default: |
| 162 return "UNKNOWN_TYPE"; | 236 return "UNKNOWN_TYPE"; |
| 163 } | 237 } |
| 164 } | 238 } |
| 165 | 239 |
| 166 APIAction::Type APIAction::StringAsType( | |
| 167 const std::string& str) { | |
| 168 if (str == "CALL") { | |
| 169 return CALL; | |
| 170 } else if (str == "EVENT_CALLBACK") { | |
| 171 return EVENT_CALLBACK; | |
| 172 } else { | |
| 173 return UNKNOWN_TYPE; | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 } // namespace extensions | 240 } // namespace extensions |
| 178 | 241 |
| OLD | NEW |