1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/rlz/rlz_extension_api.h" 6 7 #include "base/bind.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/threading/sequenced_worker_pool.h" 10 #include "base/threading/thread_restrictions.h" 11 #include "base/values.h" 12 #include "chrome/browser/browser_process.h" 13 #include "chrome/common/extensions/extension.h" 14 #include "rlz/lib/lib_values.h" 15 #include "rlz/lib/rlz_lib.h" 16 17 namespace { 18 19 bool GetProductFromName(const std::string& product_name, 20 rlz_lib::Product* product) { 21 bool success = true; 22 switch (product_name[0]) { 23 case 'B': 24 *product = rlz_lib::FF_TOOLBAR; 25 break; 26 case 'C': 27 *product = rlz_lib::CHROME; 28 break; 29 case 'D': 30 *product = rlz_lib::DESKTOP; 31 break; 32 case 'K': 33 *product = rlz_lib::QSB_WIN; 34 break; 35 case 'N': 36 *product = rlz_lib::PINYIN_IME; 37 break; 38 case 'P': 39 *product = rlz_lib::TOOLBAR_NOTIFIER; 40 break; 41 case 'T': 42 *product = rlz_lib::IE_TOOLBAR; 43 break; 44 case 'U': 45 *product = rlz_lib::PACK; 46 break; 47 case 'W': 48 *product = rlz_lib::WEBAPPS; 49 break; 50 default: 51 success = false; 52 break; 53 } 54 55 return success; 56 } 57 58 bool GetEventFromName(const std::string& event_name, 59 rlz_lib::Event* event_id) { 60 *event_id = rlz_lib::INVALID_EVENT; 61 62 if (event_name == "install") { 63 *event_id = rlz_lib::INSTALL; 64 } else if (event_name == "set-to-google") { 65 *event_id = rlz_lib::SET_TO_GOOGLE; 66 } else if (event_name == "first-search") { 67 *event_id = rlz_lib::FIRST_SEARCH; 68 } else if (event_name == "activate") { 69 *event_id = rlz_lib::ACTIVATE; 70 } 71 72 return *event_id != rlz_lib::INVALID_EVENT; 73 } 74 75 } // namespace 76 77 bool RlzRecordProductEventFunction::RunImpl() { 78 // This can be slow if registry access goes to disk. Should preferably 79 // perform registry operations on the File thread. 80 // http://code.google.com/p/chromium/issues/detail?id=62098 81 base::ThreadRestrictions::ScopedAllowIO allow_io; 82 83 std::string product_name; 84 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &product_name)); 85 rlz_lib::Product product; 86 EXTENSION_FUNCTION_VALIDATE(GetProductFromName(product_name, &product)); 87 88 std::string ap_name; 89 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &ap_name)); 90 rlz_lib::AccessPoint access_point; 91 EXTENSION_FUNCTION_VALIDATE(rlz_lib::GetAccessPointFromName(ap_name.c_str(), 92 &access_point)); 93 94 std::string event_name; 95 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &event_name)); 96 rlz_lib::Event event_id; 97 EXTENSION_FUNCTION_VALIDATE(GetEventFromName(event_name, &event_id)); 98 99 return rlz_lib::RecordProductEvent(product, access_point, event_id); 100 } 101 102 bool RlzGetAccessPointRlzFunction::RunImpl() { 103 // This can be slow if registry access goes to disk. Should preferably 104 // perform registry operations on the File thread. 105 // http://code.google.com/p/chromium/issues/detail?id=62098 106 base::ThreadRestrictions::ScopedAllowIO allow_io; 107 108 std::string ap_name; 109 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &ap_name)); 110 rlz_lib::AccessPoint access_point; 111 EXTENSION_FUNCTION_VALIDATE(rlz_lib::GetAccessPointFromName(ap_name.c_str(), 112 &access_point)); 113 114 char rlz[rlz_lib::kMaxRlzLength + 1]; 115 rlz_lib::GetAccessPointRlz(access_point, rlz, rlz_lib::kMaxRlzLength); 116 SetResult(Value::CreateStringValue(rlz)); 117 return true; 118 } 119 120 RlzSendFinancialPingFunction::RlzSendFinancialPingFunction() 121 : product_(rlz_lib::CHROME), 122 exclude_machine_id_(true) { 123 } 124 125 RlzSendFinancialPingFunction::~RlzSendFinancialPingFunction() { 126 } 127 128 bool RlzSendFinancialPingFunction::RunImpl() { 129 std::string product_name; 130 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &product_name)); 131 EXTENSION_FUNCTION_VALIDATE(GetProductFromName(product_name, &product_)); 132 133 ListValue* access_points_list; 134 EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &access_points_list)); 135 if (access_points_list->GetSize() < 1) { 136 EXTENSION_FUNCTION_ERROR("Access point array should not be empty."); 137 } 138 139 // Allocate an access point array to pass to ClearProductState(). The array 140 // must be terminated with the value rlz_lib::NO_ACCESS_POINT, hence + 1 141 // when allocating the array. 142 access_points_.reset( 143 new rlz_lib::AccessPoint[access_points_list->GetSize() + 1]); 144 145 size_t i; 146 for (i = 0; i < access_points_list->GetSize(); ++i) { 147 std::string ap_name; 148 EXTENSION_FUNCTION_VALIDATE(access_points_list->GetString(i, &ap_name)); 149 EXTENSION_FUNCTION_VALIDATE(rlz_lib::GetAccessPointFromName( 150 ap_name.c_str(), &access_points_[i])); 151 } 152 access_points_[i] = rlz_lib::NO_ACCESS_POINT; 153 154 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &signature_)); 155 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &brand_)); 156 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &id_)); 157 EXTENSION_FUNCTION_VALIDATE(args_->GetString(5, &lang_)); 158 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(6, &exclude_machine_id_)); 159 160 // |system_request_context| needs to run on the UI thread. 161 rlz_lib::SetURLRequestContext(g_browser_process->system_request_context()); 162 163 content::BrowserThread::GetBlockingPool()->PostTask( 164 FROM_HERE, 165 base::Bind(&RlzSendFinancialPingFunction::WorkOnWorkerThread, this)); 166 167 return true; 168 } 169 170 void RlzSendFinancialPingFunction::WorkOnWorkerThread() { 171 // rlz_lib::SendFinancialPing() will not send a ping more often than once in 172 // any 24-hour period. Calling it more often has no effect. If a ping is 173 // not sent false is returned, but this is not an error, so we should not 174 // use the return value of rlz_lib::SendFinancialPing() as the return value 175 // of this function. Callers interested in the return value can register 176 // an optional callback function. 177 bool sent = rlz_lib::SendFinancialPing(product_, access_points_.get(), 178 signature_.c_str(), brand_.c_str(), 179 id_.c_str(), lang_.c_str(), 180 exclude_machine_id_); 181 182 SetResult(Value::CreateBooleanValue(sent)); 183 184 bool post_task_result = content::BrowserThread::PostTask( 185 content::BrowserThread::UI, FROM_HERE, 186 base::Bind(&RlzSendFinancialPingFunction::RespondOnUIThread, this)); 187 DCHECK(post_task_result); 188 } 189 190 void RlzSendFinancialPingFunction::RespondOnUIThread() { 191 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 192 SendResponse(true); 193 } 194 195 bool RlzClearProductStateFunction::RunImpl() { 196 // This can be slow if registry access goes to disk. Should preferably 197 // perform registry operations on the File thread. 198 // http://code.google.com/p/chromium/issues/detail?id=62098 199 base::ThreadRestrictions::ScopedAllowIO allow_io; 200 201 std::string product_name; 202 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &product_name)); 203 rlz_lib::Product product; 204 EXTENSION_FUNCTION_VALIDATE(GetProductFromName(product_name, &product)); 205 206 ListValue* access_points_list; 207 EXTENSION_FUNCTION_VALIDATE(args_->GetList(1, &access_points_list)); 208 if (access_points_list->GetSize() < 1) { 209 EXTENSION_FUNCTION_ERROR("Access point array should not be empty."); 210 } 211 212 // Allocate an access point array to pass to ClearProductState(). The array 213 // must be termindated with the value rlz_lib::NO_ACCESS_POINT, hence + 1 214 // when allocating the array. 215 scoped_ptr<rlz_lib::AccessPoint[]> access_points( 216 new rlz_lib::AccessPoint[access_points_list->GetSize() + 1]); 217 218 size_t i; 219 for (i = 0; i < access_points_list->GetSize(); ++i) { 220 std::string ap_name; 221 EXTENSION_FUNCTION_VALIDATE(access_points_list->GetString(i, &ap_name)); 222 EXTENSION_FUNCTION_VALIDATE(rlz_lib::GetAccessPointFromName( 223 ap_name.c_str(), &access_points[i])); 224 } 225 access_points[i] = rlz_lib::NO_ACCESS_POINT; 226 227 rlz_lib::ClearProductState(product, access_points.get()); 228 return true; 229 } 230