// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/automation/testing_automation_provider.h" #include "base/values.h" #include "chrome/browser/automation/automation_provider_json.h" #include "chrome/browser/automation/automation_provider_observers.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "chrome/browser/chromeos/cros/network_library.h" #include "chrome/browser/chromeos/cros/power_library.h" #include "chrome/browser/chromeos/cros/screen_lock_library.h" #include "chrome/browser/chromeos/cros/update_library.h" #include "chrome/browser/chromeos/login/existing_user_controller.h" #include "chrome/browser/chromeos/login/screen_locker.h" #include "chrome/browser/chromeos/proxy_cros_settings_provider.h" using chromeos::CrosLibrary; using chromeos::NetworkLibrary; using chromeos::UserManager; using chromeos::UpdateLibrary; namespace { bool EnsureCrosLibraryLoaded(AutomationProvider* provider, IPC::Message* reply_message) { if (!CrosLibrary::Get()->EnsureLoaded()) { AutomationJSONReply(provider, reply_message).SendError( "Could not load cros library."); return false; } return true; } DictionaryValue* GetNetworkInfoDict(const chromeos::Network* network) { DictionaryValue* item = new DictionaryValue; item->SetString("name", network->name()); item->SetString("device_path", network->device_path()); item->SetString("ip_address", network->ip_address()); item->SetString("status", network->GetStateString()); return item; } Value* GetProxySetting(const std::string& setting_name) { chromeos::ProxyCrosSettingsProvider settings_provider; std::string setting_path = "cros.session.proxy."; setting_path.append(setting_name); if (setting_name == "ignorelist") { Value* value; if (settings_provider.Get(setting_path, &value)) return value; } else { Value* setting; if (settings_provider.Get(setting_path, &setting)) { DictionaryValue* setting_dict = static_cast<DictionaryValue*>(setting); Value* value; bool found = setting_dict->Remove("value", &value); delete setting; if (found) return value; } } return NULL; } const char* UpdateStatusToString(chromeos::UpdateStatusOperation status) { switch (status) { case chromeos::UPDATE_STATUS_IDLE: return "idle"; case chromeos::UPDATE_STATUS_CHECKING_FOR_UPDATE: return "checking for update"; case chromeos::UPDATE_STATUS_UPDATE_AVAILABLE: return "update available"; case chromeos::UPDATE_STATUS_DOWNLOADING: return "downloading"; case chromeos::UPDATE_STATUS_VERIFYING: return "verifying"; case chromeos::UPDATE_STATUS_FINALIZING: return "finalizing"; case chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT: return "updated need reboot"; case chromeos::UPDATE_STATUS_REPORTING_ERROR_EVENT: return "reporting error event"; default: return "unknown"; } } void GetReleaseTrackCallback(void* user_data, const char* track) { AutomationJSONReply* reply = static_cast<AutomationJSONReply*>(user_data); if (track == NULL) { reply->SendError("Unable to get release track."); delete reply; return; } scoped_ptr<DictionaryValue> return_value(new DictionaryValue); return_value->SetString("release_track", track); UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); const UpdateLibrary::Status& status = update_library->status(); chromeos::UpdateStatusOperation update_status = status.status; return_value->SetString("status", UpdateStatusToString(update_status)); if (update_status == chromeos::UPDATE_STATUS_DOWNLOADING) return_value->SetDouble("download_progress", status.download_progress); if (status.last_checked_time > 0) return_value->SetInteger("last_checked_time", status.last_checked_time); if (status.new_size > 0) return_value->SetInteger("new_size", status.new_size); reply->SendSuccess(return_value.get()); delete reply; } void UpdateCheckCallback(void* user_data, chromeos::UpdateResult result, const char* error_msg) { AutomationJSONReply* reply = static_cast<AutomationJSONReply*>(user_data); if (result == chromeos::UPDATE_RESULT_SUCCESS) reply->SendSuccess(NULL); else reply->SendError(error_msg); delete reply; } } // namespace void TestingAutomationProvider::GetLoginInfo(DictionaryValue* args, IPC::Message* reply_message) { AutomationJSONReply reply(this, reply_message); scoped_ptr<DictionaryValue> return_value(new DictionaryValue); const UserManager* user_manager = UserManager::Get(); if (!user_manager) reply.SendError("No user manager!"); const chromeos::ScreenLocker* screen_locker = chromeos::ScreenLocker::default_screen_locker(); return_value->SetBoolean("is_owner", user_manager->current_user_is_owner()); return_value->SetBoolean("is_logged_in", user_manager->user_is_logged_in()); return_value->SetBoolean("is_screen_locked", screen_locker); if (user_manager->user_is_logged_in()) { return_value->SetBoolean("is_guest", user_manager->IsLoggedInAsGuest()); return_value->SetString("email", user_manager->logged_in_user().email()); } reply.SendSuccess(return_value.get()); } // Logging in as guest will cause session_manager to restart Chrome with new // flags. If you used EnableChromeTesting, you will have to call it again. void TestingAutomationProvider::LoginAsGuest(DictionaryValue* args, IPC::Message* reply_message) { chromeos::ExistingUserController* controller = chromeos::ExistingUserController::current_controller(); // Set up an observer (it will delete itself). new LoginManagerObserver(this, reply_message); controller->LoginAsGuest(); } void TestingAutomationProvider::Login(DictionaryValue* args, IPC::Message* reply_message) { std::string username, password; if (!args->GetString("username", &username) || !args->GetString("password", &password)) { AutomationJSONReply(this, reply_message).SendError( "Invalid or missing args."); return; } chromeos::ExistingUserController* controller = chromeos::ExistingUserController::current_controller(); // Set up an observer (it will delete itself). new LoginManagerObserver(this, reply_message); controller->Login(username, password); } void TestingAutomationProvider::LockScreen(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; new ScreenLockUnlockObserver(this, reply_message, true); CrosLibrary::Get()->GetScreenLockLibrary()-> NotifyScreenLockRequested(); } void TestingAutomationProvider::UnlockScreen(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; new ScreenLockUnlockObserver(this, reply_message, false); CrosLibrary::Get()->GetScreenLockLibrary()-> NotifyScreenUnlockRequested(); } // Signing out could have undesirable side effects: session_manager is // killed, so its children, including chrome and the window manager, will // also be killed. Anything owned by chronos will probably be killed. void TestingAutomationProvider::SignoutInScreenLocker( DictionaryValue* args, IPC::Message* reply_message) { AutomationJSONReply reply(this, reply_message); chromeos::ScreenLocker* screen_locker = chromeos::ScreenLocker::default_screen_locker(); if (!screen_locker) { reply.SendError( "No default screen locker. Are you sure the screen is locked?"); return; } // Send success before stopping session because if we're a child of // session manager then we'll die when the session is stopped. reply.SendSuccess(NULL); screen_locker->Signout(); } void TestingAutomationProvider::GetBatteryInfo(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; chromeos::PowerLibrary* power_library = CrosLibrary::Get()->GetPowerLibrary(); scoped_ptr<DictionaryValue> return_value(new DictionaryValue); return_value->SetBoolean("battery_is_present", power_library->battery_is_present()); return_value->SetBoolean("line_power_on", power_library->line_power_on()); if (power_library->battery_is_present()) { return_value->SetBoolean("battery_fully_charged", power_library->battery_fully_charged()); return_value->SetDouble("battery_percentage", power_library->battery_percentage()); if (power_library->line_power_on()) { int time = power_library->battery_time_to_full().InSeconds(); if (time > 0 || power_library->battery_fully_charged()) return_value->SetInteger("battery_time_to_full", time); } else { int time = power_library->battery_time_to_empty().InSeconds(); if (time > 0) return_value->SetInteger("battery_time_to_empty", time); } } AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); } void TestingAutomationProvider::GetNetworkInfo(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); scoped_ptr<DictionaryValue> return_value(new DictionaryValue); // IP address. return_value->SetString("ip_address", network_library->IPAddress()); // Currently connected networks. if (network_library->ethernet_network()) return_value->SetString( "connected_ethernet", network_library->ethernet_network()->service_path()); if (network_library->wifi_network()) return_value->SetString("connected_wifi", network_library->wifi_network()->service_path()); if (network_library->cellular_network()) return_value->SetString( "connected_cellular", network_library->cellular_network()->service_path()); // Ethernet network. bool ethernet_available = network_library->ethernet_available(); bool ethernet_enabled = network_library->ethernet_enabled(); if (ethernet_available && ethernet_enabled) { const chromeos::EthernetNetwork* ethernet_network = network_library->ethernet_network(); if (ethernet_network) { DictionaryValue* items = new DictionaryValue; DictionaryValue* item = GetNetworkInfoDict(ethernet_network); items->Set(ethernet_network->service_path(), item); return_value->Set("ethernet_networks", items); } } // Wi-fi networks. bool wifi_available = network_library->wifi_available(); bool wifi_enabled = network_library->wifi_enabled(); if (wifi_available && wifi_enabled) { const chromeos::WifiNetworkVector& wifi_networks = network_library->wifi_networks(); DictionaryValue* items = new DictionaryValue; for (chromeos::WifiNetworkVector::const_iterator iter = wifi_networks.begin(); iter != wifi_networks.end(); ++iter) { const chromeos::WifiNetwork* wifi = *iter; DictionaryValue* item = GetNetworkInfoDict(wifi); item->SetInteger("strength", wifi->strength()); item->SetBoolean("encrypted", wifi->encrypted()); item->SetString("encryption", wifi->GetEncryptionString()); items->Set(wifi->service_path(), item); } return_value->Set("wifi_networks", items); } // Cellular networks. bool cellular_available = network_library->cellular_available(); bool cellular_enabled = network_library->cellular_enabled(); if (cellular_available && cellular_enabled) { const chromeos::CellularNetworkVector& cellular_networks = network_library->cellular_networks(); DictionaryValue* items = new DictionaryValue; for (size_t i = 0; i < cellular_networks.size(); ++i) { DictionaryValue* item = GetNetworkInfoDict(cellular_networks[i]); item->SetInteger("strength", cellular_networks[i]->strength()); item->SetString("operator_name", cellular_networks[i]->operator_name()); item->SetString("operator_code", cellular_networks[i]->operator_code()); item->SetString("payment_url", cellular_networks[i]->payment_url()); item->SetString("usage_url", cellular_networks[i]->usage_url()); item->SetString("network_technology", cellular_networks[i]->GetNetworkTechnologyString()); item->SetString("connectivity_state", cellular_networks[i]->GetConnectivityStateString()); item->SetString("activation_state", cellular_networks[i]->GetActivationStateString()); item->SetString("roaming_state", cellular_networks[i]->GetRoamingStateString()); items->Set(cellular_networks[i]->service_path(), item); } return_value->Set("cellular_networks", items); } AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); } void TestingAutomationProvider::NetworkScan(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); network_library->RequestNetworkScan(); // Set up an observer (it will delete itself). new NetworkScanObserver(this, reply_message); } void TestingAutomationProvider::GetProxySettings(DictionaryValue* args, IPC::Message* reply_message) { const char* settings[] = { "pacurl", "singlehttp", "singlehttpport", "httpurl", "httpport", "httpsurl", "httpsport", "type", "single", "ftpurl", "ftpport", "socks", "socksport", "ignorelist" }; scoped_ptr<DictionaryValue> return_value(new DictionaryValue); chromeos::ProxyCrosSettingsProvider settings_provider; for (size_t i = 0; i < arraysize(settings); ++i) { Value* setting = GetProxySetting(settings[i]); if (setting) return_value->Set(settings[i], setting); } AutomationJSONReply(this, reply_message).SendSuccess(return_value.get()); } void TestingAutomationProvider::SetProxySettings(DictionaryValue* args, IPC::Message* reply_message) { AutomationJSONReply reply(this, reply_message); std::string key; Value* value; if (!args->GetString("key", &key) || !args->Get("value", &value)) { reply.SendError("Invalid or missing args."); return; } std::string setting_path = "cros.session.proxy."; setting_path.append(key); // ProxyCrosSettingsProvider will own the Value* passed to Set(). chromeos::ProxyCrosSettingsProvider().Set(setting_path, value->DeepCopy()); reply.SendSuccess(NULL); } void TestingAutomationProvider::ConnectToWifiNetwork( DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; AutomationJSONReply reply(this, reply_message); std::string service_path, password, identity, certpath; if (!args->GetString("service_path", &service_path) || !args->GetString("password", &password) || !args->GetString("identity", &identity) || !args->GetString("certpath", &certpath)) { reply.SendError("Invalid or missing args."); return; } NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); chromeos::WifiNetwork* wifi = network_library->FindWifiNetworkByPath(service_path); if (!wifi) { reply.SendError("No network found with specified service path."); return; } if (!password.empty()) wifi->SetPassphrase(password); if (!identity.empty()) wifi->SetIdentity(identity); if (!certpath.empty()) wifi->SetCertPath(certpath); // Set up an observer (it will delete itself). new ServicePathConnectObserver(this, reply_message, service_path); network_library->ConnectToWifiNetwork(wifi); network_library->RequestNetworkScan(); } void TestingAutomationProvider::ConnectToHiddenWifiNetwork( DictionaryValue* args, IPC::Message* reply_message) { if (!CrosLibrary::Get()->EnsureLoaded()) { AutomationJSONReply(this, reply_message) .SendError("Could not load cros library."); return; } std::string ssid, security, password, identity, certpath; if (!args->GetString("ssid", &ssid) || !args->GetString("security", &security) || !args->GetString("password", &password) || !args->GetString("identity", &identity) || !args->GetString("certpath", &certpath)) { AutomationJSONReply(this, reply_message) .SendError("Invalid or missing args."); return; } std::map<std::string, chromeos::ConnectionSecurity> connection_security_map; connection_security_map["SECURITY_NONE"] = chromeos::SECURITY_NONE; connection_security_map["SECURITY_WEP"] = chromeos::SECURITY_WEP; connection_security_map["SECURITY_WPA"] = chromeos::SECURITY_WPA; connection_security_map["SECURITY_RSN"] = chromeos::SECURITY_RSN; connection_security_map["SECURITY_8021X"] = chromeos::SECURITY_8021X; if (connection_security_map.find(security) == connection_security_map.end()) { AutomationJSONReply(this, reply_message) .SendError("Unknown security type."); return; } chromeos::ConnectionSecurity connection_security = connection_security_map[security]; NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); // Set up an observer (it will delete itself). new SSIDConnectObserver(this, reply_message, ssid); network_library->ConnectToWifiNetwork(connection_security, ssid, password, identity, certpath); } void TestingAutomationProvider::DisconnectFromWifiNetwork( DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; AutomationJSONReply reply(this, reply_message); NetworkLibrary* network_library = CrosLibrary::Get()->GetNetworkLibrary(); const chromeos::WifiNetwork* wifi = network_library->wifi_network(); if (!wifi) { reply.SendError("Not connected to any wifi network."); return; } network_library->DisconnectFromNetwork(wifi); reply.SendSuccess(NULL); } void TestingAutomationProvider::GetUpdateInfo(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message); update_library->GetReleaseTrack(GetReleaseTrackCallback, reply); } void TestingAutomationProvider::UpdateCheck( DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message); update_library->RequestUpdateCheck(UpdateCheckCallback, reply); } void TestingAutomationProvider::SetReleaseTrack(DictionaryValue* args, IPC::Message* reply_message) { if (!EnsureCrosLibraryLoaded(this, reply_message)) return; AutomationJSONReply reply(this, reply_message); std::string track; if (!args->GetString("track", &track)) { reply.SendError("Invalid or missing args."); return; } UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary(); update_library->SetReleaseTrack(track); reply.SendSuccess(NULL); }