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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/automation/testing_automation_provider.h" 6 7 #include "base/values.h" 8 #include "chrome/browser/automation/automation_provider_json.h" 9 #include "chrome/browser/automation/automation_provider_observers.h" 10 #include "chrome/browser/chromeos/cros/cros_library.h" 11 #include "chrome/browser/chromeos/cros/network_library.h" 12 #include "chrome/browser/chromeos/cros/power_library.h" 13 #include "chrome/browser/chromeos/cros/screen_lock_library.h" 14 #include "chrome/browser/chromeos/cros/update_library.h" 15 #include "chrome/browser/chromeos/login/existing_user_controller.h" 16 #include "chrome/browser/chromeos/login/screen_locker.h" 17 #include "chrome/browser/chromeos/proxy_cros_settings_provider.h" 18 19 using chromeos::CrosLibrary; 20 using chromeos::NetworkLibrary; 21 using chromeos::UserManager; 22 using chromeos::UpdateLibrary; 23 24 namespace { 25 26 bool EnsureCrosLibraryLoaded(AutomationProvider* provider, 27 IPC::Message* reply_message) { 28 if (!CrosLibrary::Get()->EnsureLoaded()) { 29 AutomationJSONReply(provider, reply_message).SendError( 30 "Could not load cros library."); 31 return false; 32 } 33 return true; 34 } 35 36 DictionaryValue* GetNetworkInfoDict(const chromeos::Network* network) { 37 DictionaryValue* item = new DictionaryValue; 38 item->SetString("name", network->name()); 39 item->SetString("device_path", network->device_path()); 40 item->SetString("ip_address", network->ip_address()); 41 item->SetString("status", network->GetStateString()); 42 return item; 43 } 44 45 Value* GetProxySetting(const std::string& setting_name) { 46 chromeos::ProxyCrosSettingsProvider settings_provider; 47 std::string setting_path = "cros.session.proxy."; 48 setting_path.append(setting_name); 49 50 if (setting_name == "ignorelist") { 51 Value* value; 52 if (settings_provider.Get(setting_path, &value)) 53 return value; 54 } else { 55 Value* setting; 56 if (settings_provider.Get(setting_path, &setting)) { 57 DictionaryValue* setting_dict = static_cast<DictionaryValue*>(setting); 58 Value* value; 59 bool found = setting_dict->Remove("value", &value); 60 delete setting; 61 if (found) 62 return value; 63 } 64 } 65 return NULL; 66 } 67 68 const char* UpdateStatusToString(chromeos::UpdateStatusOperation status) { 69 switch (status) { 70 case chromeos::UPDATE_STATUS_IDLE: 71 return "idle"; 72 case chromeos::UPDATE_STATUS_CHECKING_FOR_UPDATE: 73 return "checking for update"; 74 case chromeos::UPDATE_STATUS_UPDATE_AVAILABLE: 75 return "update available"; 76 case chromeos::UPDATE_STATUS_DOWNLOADING: 77 return "downloading"; 78 case chromeos::UPDATE_STATUS_VERIFYING: 79 return "verifying"; 80 case chromeos::UPDATE_STATUS_FINALIZING: 81 return "finalizing"; 82 case chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT: 83 return "updated need reboot"; 84 case chromeos::UPDATE_STATUS_REPORTING_ERROR_EVENT: 85 return "reporting error event"; 86 default: 87 return "unknown"; 88 } 89 } 90 91 void GetReleaseTrackCallback(void* user_data, const char* track) { 92 AutomationJSONReply* reply = static_cast<AutomationJSONReply*>(user_data); 93 94 if (track == NULL) { 95 reply->SendError("Unable to get release track."); 96 delete reply; 97 return; 98 } 99 100 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 101 return_value->SetString("release_track", track); 102 103 UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); 104 const UpdateLibrary::Status& status = update_library->status(); 105 chromeos::UpdateStatusOperation update_status = status.status; 106 return_value->SetString("status", UpdateStatusToString(update_status)); 107 if (update_status == chromeos::UPDATE_STATUS_DOWNLOADING) 108 return_value->SetDouble("download_progress", status.download_progress); 109 if (status.last_checked_time > 0) 110 return_value->SetInteger("last_checked_time", status.last_checked_time); 111 if (status.new_size > 0) 112 return_value->SetInteger("new_size", status.new_size); 113 114 reply->SendSuccess(return_value.get()); 115 delete reply; 116 } 117 118 void UpdateCheckCallback(void* user_data, chromeos::UpdateResult result, 119 const char* error_msg) { 120 AutomationJSONReply* reply = static_cast<AutomationJSONReply*>(user_data); 121 if (result == chromeos::UPDATE_RESULT_SUCCESS) 122 reply->SendSuccess(NULL); 123 else 124 reply->SendError(error_msg); 125 delete reply; 126 } 127 128 } // namespace 129 130 void TestingAutomationProvider::GetLoginInfo(DictionaryValue* args, 131 IPC::Message* reply_message) { 132 AutomationJSONReply reply(this, reply_message); 133 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 134 135 const UserManager* user_manager = UserManager::Get(); 136 if (!user_manager) 137 reply.SendError("No user manager!"); 138 const chromeos::ScreenLocker* screen_locker = 139 chromeos::ScreenLocker::default_screen_locker(); 140 141 return_value->SetBoolean("is_owner", user_manager->current_user_is_owner()); 142 return_value->SetBoolean("is_logged_in", user_manager->user_is_logged_in()); 143 return_value->SetBoolean("is_screen_locked", screen_locker); 144 if (user_manager->user_is_logged_in()) { 145 return_value->SetBoolean("is_guest", user_manager->IsLoggedInAsGuest()); 146 return_value->SetString("email", user_manager->logged_in_user().email()); 147 } 148 149 reply.SendSuccess(return_value.get()); 150 } 151 152 // Logging in as guest will cause session_manager to restart Chrome with new 153 // flags. If you used EnableChromeTesting, you will have to call it again. 154 void TestingAutomationProvider::LoginAsGuest(DictionaryValue* args, 155 IPC::Message* reply_message) { 156 chromeos::ExistingUserController* controller = 157 chromeos::ExistingUserController::current_controller(); 158 // Set up an observer (it will delete itself). 159 new LoginManagerObserver(this, reply_message); 160 controller->LoginAsGuest(); 161 } 162 163 void TestingAutomationProvider::Login(DictionaryValue* args, 164 IPC::Message* reply_message) { 165 std::string username, password; 166 if (!args->GetString("username", &username) || 167 !args->GetString("password", &password)) { 168 AutomationJSONReply(this, reply_message).SendError( 169 "Invalid or missing args."); 170 return; 171 } 172 173 chromeos::ExistingUserController* controller = 174 chromeos::ExistingUserController::current_controller(); 175 // Set up an observer (it will delete itself). 176 new LoginManagerObserver(this, reply_message); 177 controller->Login(username, password); 178 } 179 180 void TestingAutomationProvider::LockScreen(DictionaryValue* args, 181 IPC::Message* reply_message) { 182 if (!EnsureCrosLibraryLoaded(this, reply_message)) 183 return; 184 185 new ScreenLockUnlockObserver(this, reply_message, true); 186 CrosLibrary::Get()->GetScreenLockLibrary()-> 187 NotifyScreenLockRequested(); 188 } 189 190 void TestingAutomationProvider::UnlockScreen(DictionaryValue* args, 191 IPC::Message* reply_message) { 192 if (!EnsureCrosLibraryLoaded(this, reply_message)) 193 return; 194 195 new ScreenLockUnlockObserver(this, reply_message, false); 196 CrosLibrary::Get()->GetScreenLockLibrary()-> 197 NotifyScreenUnlockRequested(); 198 } 199 200 // Signing out could have undesirable side effects: session_manager is 201 // killed, so its children, including chrome and the window manager, will 202 // also be killed. Anything owned by chronos will probably be killed. 203 void TestingAutomationProvider::SignoutInScreenLocker( 204 DictionaryValue* args, IPC::Message* reply_message) { 205 AutomationJSONReply reply(this, reply_message); 206 chromeos::ScreenLocker* screen_locker = 207 chromeos::ScreenLocker::default_screen_locker(); 208 if (!screen_locker) { 209 reply.SendError( 210 "No default screen locker. Are you sure the screen is locked?"); 211 return; 212 } 213 214 // Send success before stopping session because if we're a child of 215 // session manager then we'll die when the session is stopped. 216 reply.SendSuccess(NULL); 217 screen_locker->Signout(); 218 } 219 220 void TestingAutomationProvider::GetBatteryInfo(DictionaryValue* args, 221 IPC::Message* reply_message) { 222 if (!EnsureCrosLibraryLoaded(this, reply_message)) 223 return; 224 225 chromeos::PowerLibrary* power_library = CrosLibrary::Get()->GetPowerLibrary(); 226 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 227 228 return_value->SetBoolean("battery_is_present", 229 power_library->battery_is_present()); 230 return_value->SetBoolean("line_power_on", power_library->line_power_on()); 231 if (power_library->battery_is_present()) { 232 return_value->SetBoolean("battery_fully_charged", 233 power_library->battery_fully_charged()); 234 return_value->SetDouble("battery_percentage", 235 power_library->battery_percentage()); 236 if (power_library->line_power_on()) { 237 int time = power_library->battery_time_to_full().InSeconds(); 238 if (time > 0 || power_library->battery_fully_charged()) 239 return_value->SetInteger("battery_time_to_full", time); 240 } else { 241 int time = power_library->battery_time_to_empty().InSeconds(); 242 if (time > 0) 243 return_value->SetInteger("battery_time_to_empty", time); 244 } 245 } 246 247 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); 248 } 249 250 void TestingAutomationProvider::GetNetworkInfo(DictionaryValue* args, 251 IPC::Message* reply_message) { 252 if (!EnsureCrosLibraryLoaded(this, reply_message)) 253 return; 254 255 NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); 256 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 257 258 // IP address. 259 return_value->SetString("ip_address", network_library->IPAddress()); 260 261 // Currently connected networks. 262 if (network_library->ethernet_network()) 263 return_value->SetString( 264 "connected_ethernet", 265 network_library->ethernet_network()->service_path()); 266 if (network_library->wifi_network()) 267 return_value->SetString("connected_wifi", 268 network_library->wifi_network()->service_path()); 269 if (network_library->cellular_network()) 270 return_value->SetString( 271 "connected_cellular", 272 network_library->cellular_network()->service_path()); 273 274 // Ethernet network. 275 bool ethernet_available = network_library->ethernet_available(); 276 bool ethernet_enabled = network_library->ethernet_enabled(); 277 if (ethernet_available && ethernet_enabled) { 278 const chromeos::EthernetNetwork* ethernet_network = 279 network_library->ethernet_network(); 280 if (ethernet_network) { 281 DictionaryValue* items = new DictionaryValue; 282 DictionaryValue* item = GetNetworkInfoDict(ethernet_network); 283 items->Set(ethernet_network->service_path(), item); 284 return_value->Set("ethernet_networks", items); 285 } 286 } 287 288 // Wi-fi networks. 289 bool wifi_available = network_library->wifi_available(); 290 bool wifi_enabled = network_library->wifi_enabled(); 291 if (wifi_available && wifi_enabled) { 292 const chromeos::WifiNetworkVector& wifi_networks = 293 network_library->wifi_networks(); 294 DictionaryValue* items = new DictionaryValue; 295 for (chromeos::WifiNetworkVector::const_iterator iter = 296 wifi_networks.begin(); iter != wifi_networks.end(); ++iter) { 297 const chromeos::WifiNetwork* wifi = *iter; 298 DictionaryValue* item = GetNetworkInfoDict(wifi); 299 item->SetInteger("strength", wifi->strength()); 300 item->SetBoolean("encrypted", wifi->encrypted()); 301 item->SetString("encryption", wifi->GetEncryptionString()); 302 items->Set(wifi->service_path(), item); 303 } 304 return_value->Set("wifi_networks", items); 305 } 306 307 // Cellular networks. 308 bool cellular_available = network_library->cellular_available(); 309 bool cellular_enabled = network_library->cellular_enabled(); 310 if (cellular_available && cellular_enabled) { 311 const chromeos::CellularNetworkVector& cellular_networks = 312 network_library->cellular_networks(); 313 DictionaryValue* items = new DictionaryValue; 314 for (size_t i = 0; i < cellular_networks.size(); ++i) { 315 DictionaryValue* item = GetNetworkInfoDict(cellular_networks[i]); 316 item->SetInteger("strength", cellular_networks[i]->strength()); 317 item->SetString("operator_name", cellular_networks[i]->operator_name()); 318 item->SetString("operator_code", cellular_networks[i]->operator_code()); 319 item->SetString("payment_url", cellular_networks[i]->payment_url()); 320 item->SetString("usage_url", cellular_networks[i]->usage_url()); 321 item->SetString("network_technology", 322 cellular_networks[i]->GetNetworkTechnologyString()); 323 item->SetString("connectivity_state", 324 cellular_networks[i]->GetConnectivityStateString()); 325 item->SetString("activation_state", 326 cellular_networks[i]->GetActivationStateString()); 327 item->SetString("roaming_state", 328 cellular_networks[i]->GetRoamingStateString()); 329 items->Set(cellular_networks[i]->service_path(), item); 330 } 331 return_value->Set("cellular_networks", items); 332 } 333 334 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); 335 } 336 337 void TestingAutomationProvider::NetworkScan(DictionaryValue* args, 338 IPC::Message* reply_message) { 339 if (!EnsureCrosLibraryLoaded(this, reply_message)) 340 return; 341 342 NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); 343 network_library->RequestNetworkScan(); 344 345 // Set up an observer (it will delete itself). 346 new NetworkScanObserver(this, reply_message); 347 } 348 349 void TestingAutomationProvider::GetProxySettings(DictionaryValue* args, 350 IPC::Message* reply_message) { 351 const char* settings[] = { "pacurl", "singlehttp", "singlehttpport", 352 "httpurl", "httpport", "httpsurl", "httpsport", 353 "type", "single", "ftpurl", "ftpport", 354 "socks", "socksport", "ignorelist" }; 355 356 scoped_ptr<DictionaryValue> return_value(new DictionaryValue); 357 chromeos::ProxyCrosSettingsProvider settings_provider; 358 359 for (size_t i = 0; i < arraysize(settings); ++i) { 360 Value* setting = GetProxySetting(settings[i]); 361 if (setting) 362 return_value->Set(settings[i], setting); 363 } 364 365 AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); 366 } 367 368 void TestingAutomationProvider::SetProxySettings(DictionaryValue* args, 369 IPC::Message* reply_message) { 370 AutomationJSONReply reply(this, reply_message); 371 std::string key; 372 Value* value; 373 if (!args->GetString("key", &key) || !args->Get("value", &value)) { 374 reply.SendError("Invalid or missing args."); 375 return; 376 } 377 378 std::string setting_path = "cros.session.proxy."; 379 setting_path.append(key); 380 381 // ProxyCrosSettingsProvider will own the Value* passed to Set(). 382 chromeos::ProxyCrosSettingsProvider().Set(setting_path, value->DeepCopy()); 383 reply.SendSuccess(NULL); 384 } 385 386 void TestingAutomationProvider::ConnectToWifiNetwork( 387 DictionaryValue* args, IPC::Message* reply_message) { 388 if (!EnsureCrosLibraryLoaded(this, reply_message)) 389 return; 390 391 AutomationJSONReply reply(this, reply_message); 392 std::string service_path, password, identity, certpath; 393 if (!args->GetString("service_path", &service_path) || 394 !args->GetString("password", &password) || 395 !args->GetString("identity", &identity) || 396 !args->GetString("certpath", &certpath)) { 397 reply.SendError("Invalid or missing args."); 398 return; 399 } 400 401 NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); 402 chromeos::WifiNetwork* wifi = 403 network_library->FindWifiNetworkByPath(service_path); 404 if (!wifi) { 405 reply.SendError("No network found with specified service path."); 406 return; 407 } 408 if (!password.empty()) 409 wifi->SetPassphrase(password); 410 if (!identity.empty()) 411 wifi->SetIdentity(identity); 412 if (!certpath.empty()) 413 wifi->SetCertPath(certpath); 414 415 // Set up an observer (it will delete itself). 416 new ServicePathConnectObserver(this, reply_message, service_path); 417 418 network_library->ConnectToWifiNetwork(wifi); 419 network_library->RequestNetworkScan(); 420 } 421 422 void TestingAutomationProvider::ConnectToHiddenWifiNetwork( 423 DictionaryValue* args, IPC::Message* reply_message) { 424 if (!CrosLibrary::Get()->EnsureLoaded()) { 425 AutomationJSONReply(this, reply_message) 426 .SendError("Could not load cros library."); 427 return; 428 } 429 430 std::string ssid, security, password, identity, certpath; 431 if (!args->GetString("ssid", &ssid) || 432 !args->GetString("security", &security) || 433 !args->GetString("password", &password) || 434 !args->GetString("identity", &identity) || 435 !args->GetString("certpath", &certpath)) { 436 AutomationJSONReply(this, reply_message) 437 .SendError("Invalid or missing args."); 438 return; 439 } 440 441 std::map<std::string, chromeos::ConnectionSecurity> connection_security_map; 442 connection_security_map["SECURITY_NONE"] = chromeos::SECURITY_NONE; 443 connection_security_map["SECURITY_WEP"] = chromeos::SECURITY_WEP; 444 connection_security_map["SECURITY_WPA"] = chromeos::SECURITY_WPA; 445 connection_security_map["SECURITY_RSN"] = chromeos::SECURITY_RSN; 446 connection_security_map["SECURITY_8021X"] = chromeos::SECURITY_8021X; 447 448 if (connection_security_map.find(security) == connection_security_map.end()) { 449 AutomationJSONReply(this, reply_message) 450 .SendError("Unknown security type."); 451 return; 452 } 453 chromeos::ConnectionSecurity connection_security = 454 connection_security_map[security]; 455 456 NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); 457 458 // Set up an observer (it will delete itself). 459 new SSIDConnectObserver(this, reply_message, ssid); 460 461 network_library->ConnectToWifiNetwork(connection_security, ssid, password, 462 identity, certpath); 463 } 464 465 void TestingAutomationProvider::DisconnectFromWifiNetwork( 466 DictionaryValue* args, IPC::Message* reply_message) { 467 if (!EnsureCrosLibraryLoaded(this, reply_message)) 468 return; 469 470 AutomationJSONReply reply(this, reply_message); 471 NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); 472 const chromeos::WifiNetwork* wifi = network_library->wifi_network(); 473 if (!wifi) { 474 reply.SendError("Not connected to any wifi network."); 475 return; 476 } 477 478 network_library->DisconnectFromNetwork(wifi); 479 reply.SendSuccess(NULL); 480 } 481 482 void TestingAutomationProvider::GetUpdateInfo(DictionaryValue* args, 483 IPC::Message* reply_message) { 484 if (!EnsureCrosLibraryLoaded(this, reply_message)) 485 return; 486 487 UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); 488 AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message); 489 update_library->GetReleaseTrack(GetReleaseTrackCallback, reply); 490 } 491 492 void TestingAutomationProvider::UpdateCheck( 493 DictionaryValue* args, 494 IPC::Message* reply_message) { 495 if (!EnsureCrosLibraryLoaded(this, reply_message)) 496 return; 497 498 UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); 499 AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message); 500 update_library->RequestUpdateCheck(UpdateCheckCallback, reply); 501 } 502 503 void TestingAutomationProvider::SetReleaseTrack(DictionaryValue* args, 504 IPC::Message* reply_message) { 505 if (!EnsureCrosLibraryLoaded(this, reply_message)) 506 return; 507 508 AutomationJSONReply reply(this, reply_message); 509 std::string track; 510 if (!args->GetString("track", &track)) { 511 reply.SendError("Invalid or missing args."); 512 return; 513 } 514 515 UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); 516 update_library->SetReleaseTrack(track); 517 reply.SendSuccess(NULL); 518 } 519