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
EnsureCrosLibraryLoaded(AutomationProvider * provider,IPC::Message * reply_message)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
GetNetworkInfoDict(const chromeos::Network * network)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
GetProxySetting(const std::string & setting_name)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
UpdateStatusToString(chromeos::UpdateStatusOperation status)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
GetReleaseTrackCallback(void * user_data,const char * track)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
UpdateCheckCallback(void * user_data,chromeos::UpdateResult result,const char * error_msg)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
GetLoginInfo(DictionaryValue * args,IPC::Message * reply_message)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.
LoginAsGuest(DictionaryValue * args,IPC::Message * reply_message)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
Login(DictionaryValue * args,IPC::Message * reply_message)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
LockScreen(DictionaryValue * args,IPC::Message * reply_message)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
UnlockScreen(DictionaryValue * args,IPC::Message * reply_message)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.
SignoutInScreenLocker(DictionaryValue * args,IPC::Message * reply_message)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
GetBatteryInfo(DictionaryValue * args,IPC::Message * reply_message)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
GetNetworkInfo(DictionaryValue * args,IPC::Message * reply_message)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
NetworkScan(DictionaryValue * args,IPC::Message * reply_message)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
GetProxySettings(DictionaryValue * args,IPC::Message * reply_message)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
SetProxySettings(DictionaryValue * args,IPC::Message * reply_message)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
ConnectToWifiNetwork(DictionaryValue * args,IPC::Message * reply_message)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
ConnectToHiddenWifiNetwork(DictionaryValue * args,IPC::Message * reply_message)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
DisconnectFromWifiNetwork(DictionaryValue * args,IPC::Message * reply_message)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
GetUpdateInfo(DictionaryValue * args,IPC::Message * reply_message)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
UpdateCheck(DictionaryValue * args,IPC::Message * reply_message)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
SetReleaseTrack(DictionaryValue * args,IPC::Message * reply_message)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