1 // Copyright 2018 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/ui/webui/settings/chromeos/crostini_handler.h"
6 
7 #include <string>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/callback_forward.h"
12 #include "base/callback_helpers.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chromeos/crostini/crostini_disk.h"
16 #include "chrome/browser/chromeos/crostini/crostini_features.h"
17 #include "chrome/browser/chromeos/crostini/crostini_installer.h"
18 #include "chrome/browser/chromeos/crostini/crostini_port_forwarder.h"
19 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
20 #include "chrome/browser/chromeos/crostini/crostini_types.mojom.h"
21 #include "chrome/browser/chromeos/crostini/crostini_util.h"
22 #include "chrome/browser/chromeos/file_manager/path_util.h"
23 #include "chrome/browser/chromeos/guest_os/guest_os_share_path.h"
24 #include "chrome/browser/chromeos/profiles/profile_helper.h"
25 #include "chrome/browser/lifetime/application_lifetime.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_dialog.h"
28 #include "chrome/common/pref_names.h"
29 #include "components/prefs/pref_service.h"
30 #include "components/user_manager/user_manager.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "ui/display/screen.h"
33 
34 namespace chromeos {
35 namespace settings {
36 
37 namespace {
38 
39 // These values are used for metrics and should not change.
40 enum class CrostiniSettingsEvent {
41   kEnableAdbSideloading = 0,
42   kDisableAdbSideloading = 1,
43   kMaxValue = kDisableAdbSideloading,
44 };
45 
LogEvent(CrostiniSettingsEvent action)46 void LogEvent(CrostiniSettingsEvent action) {
47   base::UmaHistogramEnumeration("Crostini.SettingsEvent", action);
48 }
49 
50 }  // namespace
51 
CrostiniHandler(Profile * profile)52 CrostiniHandler::CrostiniHandler(Profile* profile) : profile_(profile) {}
53 
~CrostiniHandler()54 CrostiniHandler::~CrostiniHandler() {
55   DisallowJavascript();
56 }
57 
RegisterMessages()58 void CrostiniHandler::RegisterMessages() {
59   web_ui()->RegisterMessageCallback(
60       "requestCrostiniInstallerView",
61       base::BindRepeating(&CrostiniHandler::HandleRequestCrostiniInstallerView,
62                           weak_ptr_factory_.GetWeakPtr()));
63   web_ui()->RegisterMessageCallback(
64       "requestRemoveCrostini",
65       base::BindRepeating(&CrostiniHandler::HandleRequestRemoveCrostini,
66                           weak_ptr_factory_.GetWeakPtr()));
67   web_ui()->RegisterMessageCallback(
68       "getCrostiniSharedPathsDisplayText",
69       base::BindRepeating(
70           &CrostiniHandler::HandleGetCrostiniSharedPathsDisplayText,
71           weak_ptr_factory_.GetWeakPtr()));
72   web_ui()->RegisterMessageCallback(
73       "removeCrostiniSharedPath",
74       base::BindRepeating(&CrostiniHandler::HandleRemoveCrostiniSharedPath,
75                           weak_ptr_factory_.GetWeakPtr()));
76   web_ui()->RegisterMessageCallback(
77       "notifyCrostiniSharedUsbDevicesPageReady",
78       base::BindRepeating(
79           &CrostiniHandler::HandleNotifyCrostiniSharedUsbDevicesPageReady,
80           weak_ptr_factory_.GetWeakPtr()));
81   web_ui()->RegisterMessageCallback(
82       "setCrostiniUsbDeviceShared",
83       base::BindRepeating(&CrostiniHandler::HandleSetCrostiniUsbDeviceShared,
84                           weak_ptr_factory_.GetWeakPtr()));
85   web_ui()->RegisterMessageCallback(
86       "exportCrostiniContainer",
87       base::BindRepeating(&CrostiniHandler::HandleExportCrostiniContainer,
88                           weak_ptr_factory_.GetWeakPtr()));
89   web_ui()->RegisterMessageCallback(
90       "importCrostiniContainer",
91       base::BindRepeating(&CrostiniHandler::HandleImportCrostiniContainer,
92                           weak_ptr_factory_.GetWeakPtr()));
93   web_ui()->RegisterMessageCallback(
94       "requestCrostiniInstallerStatus",
95       base::BindRepeating(
96           &CrostiniHandler::HandleCrostiniInstallerStatusRequest,
97           weak_ptr_factory_.GetWeakPtr()));
98   web_ui()->RegisterMessageCallback(
99       "requestCrostiniExportImportOperationStatus",
100       base::BindRepeating(
101           &CrostiniHandler::HandleCrostiniExportImportOperationStatusRequest,
102           weak_ptr_factory_.GetWeakPtr()));
103   web_ui()->RegisterMessageCallback(
104       "requestArcAdbSideloadStatus",
105       base::BindRepeating(&CrostiniHandler::HandleQueryArcAdbRequest,
106                           weak_ptr_factory_.GetWeakPtr()));
107   web_ui()->RegisterMessageCallback(
108       "getCanChangeArcAdbSideloading",
109       base::BindRepeating(
110           &CrostiniHandler::HandleCanChangeArcAdbSideloadingRequest,
111           weak_ptr_factory_.GetWeakPtr()));
112   web_ui()->RegisterMessageCallback(
113       "enableArcAdbSideload",
114       base::BindRepeating(&CrostiniHandler::HandleEnableArcAdbRequest,
115                           weak_ptr_factory_.GetWeakPtr()));
116   web_ui()->RegisterMessageCallback(
117       "disableArcAdbSideload",
118       base::BindRepeating(&CrostiniHandler::HandleDisableArcAdbRequest,
119                           weak_ptr_factory_.GetWeakPtr()));
120   web_ui()->RegisterMessageCallback(
121       "requestCrostiniContainerUpgradeView",
122       base::BindRepeating(&CrostiniHandler::HandleRequestContainerUpgradeView,
123                           weak_ptr_factory_.GetWeakPtr()));
124   web_ui()->RegisterMessageCallback(
125       "requestCrostiniUpgraderDialogStatus",
126       base::BindRepeating(
127           &CrostiniHandler::HandleCrostiniUpgraderDialogStatusRequest,
128           weak_ptr_factory_.GetWeakPtr()));
129   web_ui()->RegisterMessageCallback(
130       "requestCrostiniContainerUpgradeAvailable",
131       base::BindRepeating(
132           &CrostiniHandler::HandleCrostiniContainerUpgradeAvailableRequest,
133           weak_ptr_factory_.GetWeakPtr()));
134   web_ui()->RegisterMessageCallback(
135       "addCrostiniPortForward",
136       base::BindRepeating(&CrostiniHandler::HandleAddCrostiniPortForward,
137                           weak_ptr_factory_.GetWeakPtr()));
138   web_ui()->RegisterMessageCallback(
139       "getCrostiniDiskInfo",
140       base::BindRepeating(&CrostiniHandler::HandleGetCrostiniDiskInfo,
141                           weak_ptr_factory_.GetWeakPtr()));
142   web_ui()->RegisterMessageCallback(
143       "resizeCrostiniDisk",
144       base::BindRepeating(&CrostiniHandler::HandleResizeCrostiniDisk,
145                           weak_ptr_factory_.GetWeakPtr()));
146   web_ui()->RegisterMessageCallback(
147       "checkCrostiniMicSharingStatus",
148       base::BindRepeating(&CrostiniHandler::HandleCheckCrostiniMicSharingStatus,
149                           weak_ptr_factory_.GetWeakPtr()));
150   web_ui()->RegisterMessageCallback(
151       "removeCrostiniPortForward",
152       base::BindRepeating(&CrostiniHandler::HandleRemoveCrostiniPortForward,
153                           weak_ptr_factory_.GetWeakPtr()));
154   web_ui()->RegisterMessageCallback(
155       "removeAllCrostiniPortForwards",
156       base::BindRepeating(&CrostiniHandler::HandleRemoveAllCrostiniPortForwards,
157                           weak_ptr_factory_.GetWeakPtr()));
158   web_ui()->RegisterMessageCallback(
159       "activateCrostiniPortForward",
160       base::BindRepeating(&CrostiniHandler::HandleActivateCrostiniPortForward,
161                           weak_ptr_factory_.GetWeakPtr()));
162   web_ui()->RegisterMessageCallback(
163       "deactivateCrostiniPortForward",
164       base::BindRepeating(&CrostiniHandler::HandleDeactivateCrostiniPortForward,
165                           weak_ptr_factory_.GetWeakPtr()));
166   web_ui()->RegisterMessageCallback(
167       "getCrostiniActivePorts",
168       base::BindRepeating(&CrostiniHandler::HandleGetCrostiniActivePorts,
169                           weak_ptr_factory_.GetWeakPtr()));
170   web_ui()->RegisterMessageCallback(
171       "checkCrostiniIsRunning",
172       base::BindRepeating(&CrostiniHandler::HandleCheckCrostiniIsRunning,
173                           weak_ptr_factory_.GetWeakPtr()));
174   web_ui()->RegisterMessageCallback(
175       "shutdownCrostini",
176       base::BindRepeating(&CrostiniHandler::HandleShutdownCrostini,
177                           weak_ptr_factory_.GetWeakPtr()));
178   web_ui()->RegisterMessageCallback(
179       "setCrostiniMicSharingEnabled",
180       base::BindRepeating(&CrostiniHandler::HandleSetCrostiniMicSharingEnabled,
181                           weak_ptr_factory_.GetWeakPtr()));
182   web_ui()->RegisterMessageCallback(
183       "getCrostiniMicSharingEnabled",
184       base::BindRepeating(&CrostiniHandler::HandleGetCrostiniMicSharingEnabled,
185                           weak_ptr_factory_.GetWeakPtr()));
186 }
187 
OnJavascriptAllowed()188 void CrostiniHandler::OnJavascriptAllowed() {
189   auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_);
190   crostini_manager->AddCrostiniDialogStatusObserver(this);
191   crostini_manager->AddCrostiniContainerPropertiesObserver(this);
192   crostini_manager->AddContainerStartedObserver(this);
193   crostini_manager->AddContainerShutdownObserver(this);
194   crostini_manager->AddCrostiniMicSharingEnabledObserver(this);
195   if (chromeos::CrosUsbDetector::Get()) {
196     chromeos::CrosUsbDetector::Get()->AddUsbDeviceObserver(this);
197   }
198   crostini::CrostiniExportImport::GetForProfile(profile_)->AddObserver(this);
199   crostini::CrostiniPortForwarder::GetForProfile(profile_)->AddObserver(this);
200 
201   // Observe ADB sideloading device policy and react to its changes
202   adb_sideloading_device_policy_subscription_ =
203       chromeos::CrosSettings::Get()->AddSettingsObserver(
204           chromeos::kDeviceCrostiniArcAdbSideloadingAllowed,
205           base::BindRepeating(&CrostiniHandler::FetchCanChangeAdbSideloading,
206                               weak_ptr_factory_.GetWeakPtr()));
207 
208   // Observe ADB sideloading user policy and react to its changes
209   pref_change_registrar_.Init(profile_->GetPrefs());
210   pref_change_registrar_.Add(
211       crostini::prefs::kCrostiniArcAdbSideloadingUserPref,
212       base::BindRepeating(&CrostiniHandler::FetchCanChangeAdbSideloading,
213                           weak_ptr_factory_.GetWeakPtr()));
214 }
215 
OnJavascriptDisallowed()216 void CrostiniHandler::OnJavascriptDisallowed() {
217   auto* crostini_manager = crostini::CrostiniManager::GetForProfile(profile_);
218   crostini_manager->RemoveCrostiniDialogStatusObserver(this);
219   crostini_manager->RemoveCrostiniContainerPropertiesObserver(this);
220   crostini_manager->RemoveContainerStartedObserver(this);
221   crostini_manager->RemoveContainerShutdownObserver(this);
222   crostini_manager->RemoveCrostiniMicSharingEnabledObserver(this);
223   if (chromeos::CrosUsbDetector::Get()) {
224     chromeos::CrosUsbDetector::Get()->RemoveUsbDeviceObserver(this);
225   }
226   crostini::CrostiniExportImport::GetForProfile(profile_)->RemoveObserver(this);
227   crostini::CrostiniPortForwarder::GetForProfile(profile_)->RemoveObserver(
228       this);
229 
230   adb_sideloading_device_policy_subscription_.reset();
231   pref_change_registrar_.RemoveAll();
232 }
233 
HandleRequestCrostiniInstallerView(const base::ListValue * args)234 void CrostiniHandler::HandleRequestCrostiniInstallerView(
235     const base::ListValue* args) {
236   AllowJavascript();
237   crostini::CrostiniInstaller::GetForProfile(Profile::FromWebUI(web_ui()))
238       ->ShowDialog(crostini::CrostiniUISurface::kSettings);
239 }
240 
HandleRequestRemoveCrostini(const base::ListValue * args)241 void CrostiniHandler::HandleRequestRemoveCrostini(const base::ListValue* args) {
242   AllowJavascript();
243   ShowCrostiniUninstallerView(Profile::FromWebUI(web_ui()),
244                               crostini::CrostiniUISurface::kSettings);
245 }
246 
HandleGetCrostiniSharedPathsDisplayText(const base::ListValue * args)247 void CrostiniHandler::HandleGetCrostiniSharedPathsDisplayText(
248     const base::ListValue* args) {
249   AllowJavascript();
250   CHECK_EQ(2U, args->GetList().size());
251   std::string callback_id = args->GetList()[0].GetString();
252   base::Value::ConstListView paths = args->GetList()[1].GetList();
253 
254   base::ListValue texts;
255   for (size_t i = 0; i < paths.size(); ++i) {
256     texts.AppendString(file_manager::util::GetPathDisplayTextForSettings(
257         profile_, paths[i].GetString()));
258   }
259   ResolveJavascriptCallback(base::Value(callback_id), texts);
260 }
261 
HandleRemoveCrostiniSharedPath(const base::ListValue * args)262 void CrostiniHandler::HandleRemoveCrostiniSharedPath(
263     const base::ListValue* args) {
264   AllowJavascript();
265   CHECK_EQ(3U, args->GetList().size());
266   std::string callback_id = args->GetList()[0].GetString();
267   std::string vm_name = args->GetList()[1].GetString();
268   std::string path = args->GetList()[2].GetString();
269 
270   guest_os::GuestOsSharePath::GetForProfile(profile_)->UnsharePath(
271       vm_name, base::FilePath(path),
272       /*unpersist=*/true,
273       base::BindOnce(&CrostiniHandler::OnCrostiniSharedPathRemoved,
274                      weak_ptr_factory_.GetWeakPtr(), callback_id, path));
275 }
276 
OnCrostiniSharedPathRemoved(const std::string & callback_id,const std::string & path,bool result,const std::string & failure_reason)277 void CrostiniHandler::OnCrostiniSharedPathRemoved(
278     const std::string& callback_id,
279     const std::string& path,
280     bool result,
281     const std::string& failure_reason) {
282   if (!result) {
283     LOG(ERROR) << "Error unsharing " << path << ": " << failure_reason;
284   }
285   ResolveJavascriptCallback(base::Value(callback_id), base::Value(result));
286 }
287 
288 namespace {
UsbDevicesToListValue(const std::vector<CrosUsbDeviceInfo> shared_usbs)289 base::ListValue UsbDevicesToListValue(
290     const std::vector<CrosUsbDeviceInfo> shared_usbs) {
291   base::ListValue usb_devices_list;
292   for (auto& device : shared_usbs) {
293     base::Value device_info(base::Value::Type::DICTIONARY);
294     device_info.SetStringKey("guid", device.guid);
295     device_info.SetStringKey("label", device.label);
296     bool shared = device.shared_vm_name == crostini::kCrostiniDefaultVmName;
297     device_info.SetBoolKey("shared", shared);
298     device_info.SetBoolKey("shareWillReassign",
299                            device.shared_vm_name && !shared);
300     usb_devices_list.Append(std::move(device_info));
301   }
302   return usb_devices_list;
303 }
304 
CrostiniDiskInfoToValue(std::unique_ptr<crostini::CrostiniDiskInfo> disk_info)305 base::Value CrostiniDiskInfoToValue(
306     std::unique_ptr<crostini::CrostiniDiskInfo> disk_info) {
307   base::Value disk_value(base::Value::Type::DICTIONARY);
308   if (!disk_info) {
309     disk_value.SetBoolKey("succeeded", false);
310     return disk_value;
311   }
312   disk_value.SetBoolKey("succeeded", true);
313   disk_value.SetBoolKey("canResize", disk_info->can_resize);
314   disk_value.SetBoolKey("isUserChosenSize", disk_info->is_user_chosen_size);
315   disk_value.SetBoolKey("isLowSpaceAvailable",
316                         disk_info->is_low_space_available);
317   disk_value.SetIntKey("defaultIndex", disk_info->default_index);
318   base::Value ticks(base::Value::Type::LIST);
319   for (const auto& tick : disk_info->ticks) {
320     base::Value t(base::Value::Type::DICTIONARY);
321     t.SetDoubleKey("value", static_cast<double>(tick->value));
322     t.SetStringKey("ariaValue", tick->aria_value);
323     t.SetStringKey("label", tick->label);
324     ticks.Append(std::move(t));
325   }
326   disk_value.SetKey("ticks", std::move(ticks));
327   return disk_value;
328 }
329 }  // namespace
330 
HandleNotifyCrostiniSharedUsbDevicesPageReady(const base::ListValue * args)331 void CrostiniHandler::HandleNotifyCrostiniSharedUsbDevicesPageReady(
332     const base::ListValue* args) {
333   AllowJavascript();
334   OnUsbDevicesChanged();
335 }
336 
HandleSetCrostiniUsbDeviceShared(const base::ListValue * args)337 void CrostiniHandler::HandleSetCrostiniUsbDeviceShared(
338     const base::ListValue* args) {
339   CHECK_EQ(2U, args->GetList().size());
340   const auto& args_list = args->GetList();
341   std::string guid = args_list[0].GetString();
342   bool shared = args_list[1].GetBool();
343 
344   chromeos::CrosUsbDetector* detector = chromeos::CrosUsbDetector::Get();
345   if (!detector)
346     return;
347 
348   if (shared) {
349     detector->AttachUsbDeviceToVm(crostini::kCrostiniDefaultVmName, guid,
350                                   base::DoNothing());
351     return;
352   }
353   detector->DetachUsbDeviceFromVm(crostini::kCrostiniDefaultVmName, guid,
354                                   base::DoNothing());
355 }
356 
OnUsbDevicesChanged()357 void CrostiniHandler::OnUsbDevicesChanged() {
358   chromeos::CrosUsbDetector* detector = chromeos::CrosUsbDetector::Get();
359   DCHECK(detector);  // This callback is called by the detector.
360   FireWebUIListener(
361       "crostini-shared-usb-devices-changed",
362       UsbDevicesToListValue(detector->GetDevicesSharableWithCrostini()));
363 }
364 
HandleExportCrostiniContainer(const base::ListValue * args)365 void CrostiniHandler::HandleExportCrostiniContainer(
366     const base::ListValue* args) {
367   CHECK_EQ(0U, args->GetList().size());
368   crostini::CrostiniExportImport::GetForProfile(profile_)->ExportContainer(
369       web_ui()->GetWebContents());
370 }
371 
HandleImportCrostiniContainer(const base::ListValue * args)372 void CrostiniHandler::HandleImportCrostiniContainer(
373     const base::ListValue* args) {
374   CHECK_EQ(0U, args->GetList().size());
375   crostini::CrostiniExportImport::GetForProfile(profile_)->ImportContainer(
376       web_ui()->GetWebContents());
377 }
378 
HandleCrostiniInstallerStatusRequest(const base::ListValue * args)379 void CrostiniHandler::HandleCrostiniInstallerStatusRequest(
380     const base::ListValue* args) {
381   AllowJavascript();
382   CHECK_EQ(0U, args->GetList().size());
383   bool status = crostini::CrostiniManager::GetForProfile(profile_)
384                     ->GetCrostiniDialogStatus(crostini::DialogType::INSTALLER);
385   OnCrostiniDialogStatusChanged(crostini::DialogType::INSTALLER, status);
386 }
387 
HandleCrostiniExportImportOperationStatusRequest(const base::ListValue * args)388 void CrostiniHandler::HandleCrostiniExportImportOperationStatusRequest(
389     const base::ListValue* args) {
390   AllowJavascript();
391   CHECK_EQ(0U, args->GetList().size());
392   bool in_progress = crostini::CrostiniExportImport::GetForProfile(profile_)
393                          ->GetExportImportOperationStatus();
394   OnCrostiniExportImportOperationStatusChanged(in_progress);
395 }
396 
OnCrostiniDialogStatusChanged(crostini::DialogType dialog_type,bool status)397 void CrostiniHandler::OnCrostiniDialogStatusChanged(
398     crostini::DialogType dialog_type,
399     bool status) {
400   // It's technically possible for this to be called before Javascript is
401   // enabled, in which case we must not call FireWebUIListener
402   if (IsJavascriptAllowed()) {
403     // Other side listens with cr.addWebUIListener
404     switch (dialog_type) {
405       case crostini::DialogType::INSTALLER:
406         FireWebUIListener("crostini-installer-status-changed",
407                           base::Value(status));
408         break;
409       case crostini::DialogType::UPGRADER:
410         FireWebUIListener("crostini-upgrader-status-changed",
411                           base::Value(status));
412         break;
413       case crostini::DialogType::REMOVER:
414         FireWebUIListener("crostini-remover-status-changed",
415                           base::Value(status));
416         break;
417       default:
418         NOTREACHED();
419         break;
420     }
421   }
422 }
423 
OnContainerOsReleaseChanged(const crostini::ContainerId & container_id,bool can_upgrade)424 void CrostiniHandler::OnContainerOsReleaseChanged(
425     const crostini::ContainerId& container_id,
426     bool can_upgrade) {
427   if (crostini::CrostiniFeatures::Get()->IsContainerUpgradeUIAllowed(
428           profile_) &&
429       container_id == crostini::DefaultContainerId()) {
430     FireWebUIListener("crostini-container-upgrade-available-changed",
431                       base::Value(can_upgrade));
432   }
433 }
434 
OnQueryAdbSideload(SessionManagerClient::AdbSideloadResponseCode response_code,bool enabled)435 void CrostiniHandler::OnQueryAdbSideload(
436     SessionManagerClient::AdbSideloadResponseCode response_code,
437     bool enabled) {
438   if (response_code != SessionManagerClient::AdbSideloadResponseCode::SUCCESS) {
439     LOG(ERROR) << "Failed to query adb sideload status";
440     enabled = false;
441   }
442   bool need_powerwash =
443       response_code ==
444       SessionManagerClient::AdbSideloadResponseCode::NEED_POWERWASH;
445   // Other side listens with cr.addWebUIListener
446   FireWebUIListener("crostini-arc-adb-sideload-status-changed",
447                     base::Value(enabled), base::Value(need_powerwash));
448 }
449 
HandleEnableArcAdbRequest(const base::ListValue * args)450 void CrostiniHandler::HandleEnableArcAdbRequest(const base::ListValue* args) {
451   CHECK_EQ(0U, args->GetList().size());
452 
453   crostini::CrostiniFeatures::Get()->CanChangeAdbSideloading(
454       profile_, base::BindOnce(&CrostiniHandler::OnCanEnableArcAdbSideloading,
455                                weak_ptr_factory_.GetWeakPtr()));
456 }
457 
OnCanEnableArcAdbSideloading(bool can_change_adb_sideloading)458 void CrostiniHandler::OnCanEnableArcAdbSideloading(
459     bool can_change_adb_sideloading) {
460   if (!can_change_adb_sideloading)
461     return;
462 
463   LogEvent(CrostiniSettingsEvent::kEnableAdbSideloading);
464 
465   PrefService* prefs = g_browser_process->local_state();
466   prefs->SetBoolean(prefs::kEnableAdbSideloadingRequested, true);
467   prefs->CommitPendingWrite();
468 
469   chrome::AttemptRelaunch();
470 }
471 
HandleDisableArcAdbRequest(const base::ListValue * args)472 void CrostiniHandler::HandleDisableArcAdbRequest(const base::ListValue* args) {
473   CHECK_EQ(0U, args->GetList().size());
474 
475   crostini::CrostiniFeatures::Get()->CanChangeAdbSideloading(
476       profile_, base::BindOnce(&CrostiniHandler::OnCanDisableArcAdbSideloading,
477                                weak_ptr_factory_.GetWeakPtr()));
478 }
479 
OnCanDisableArcAdbSideloading(bool can_change_adb_sideloading)480 void CrostiniHandler::OnCanDisableArcAdbSideloading(
481     bool can_change_adb_sideloading) {
482   if (!can_change_adb_sideloading)
483     return;
484 
485   LogEvent(CrostiniSettingsEvent::kDisableAdbSideloading);
486 
487   PrefService* prefs = g_browser_process->local_state();
488   prefs->SetBoolean(prefs::kFactoryResetRequested, true);
489   prefs->CommitPendingWrite();
490 
491   chromeos::PowerManagerClient::Get()->RequestRestart(
492       power_manager::REQUEST_RESTART_FOR_USER, "disable adb sideloading");
493 }
494 
LaunchTerminal()495 void CrostiniHandler::LaunchTerminal() {
496   crostini::LaunchCrostiniApp(
497       profile_, crostini::kCrostiniTerminalSystemAppId,
498       display::Screen::GetScreen()->GetPrimaryDisplay().id());
499 }
500 
HandleRequestContainerUpgradeView(const base::ListValue * args)501 void CrostiniHandler::HandleRequestContainerUpgradeView(
502     const base::ListValue* args) {
503   CHECK_EQ(0U, args->GetList().size());
504   chromeos::CrostiniUpgraderDialog::Show(
505       profile_,
506       base::BindOnce(&CrostiniHandler::LaunchTerminal,
507                      weak_ptr_factory_.GetWeakPtr()),
508       // If the user cancels the upgrade, we won't need to restart Crostini and
509       // we don't want to run the launch closure which would launch Terminal.
510       /*only_run_launch_closure_on_restart=*/true);
511 }
512 
OnCrostiniExportImportOperationStatusChanged(bool in_progress)513 void CrostiniHandler::OnCrostiniExportImportOperationStatusChanged(
514     bool in_progress) {
515   // Other side listens with cr.addWebUIListener
516   FireWebUIListener("crostini-export-import-operation-status-changed",
517                     base::Value(in_progress));
518 }
519 
HandleQueryArcAdbRequest(const base::ListValue * args)520 void CrostiniHandler::HandleQueryArcAdbRequest(const base::ListValue* args) {
521   AllowJavascript();
522   CHECK_EQ(0U, args->GetList().size());
523 
524   chromeos::SessionManagerClient* client =
525       chromeos::SessionManagerClient::Get();
526   client->QueryAdbSideload(base::BindOnce(&CrostiniHandler::OnQueryAdbSideload,
527                                           weak_ptr_factory_.GetWeakPtr()));
528 }
529 
HandleCanChangeArcAdbSideloadingRequest(const base::ListValue * args)530 void CrostiniHandler::HandleCanChangeArcAdbSideloadingRequest(
531     const base::ListValue* args) {
532   AllowJavascript();
533   CHECK_EQ(0U, args->GetList().size());
534 
535   FetchCanChangeAdbSideloading();
536 }
537 
FetchCanChangeAdbSideloading()538 void CrostiniHandler::FetchCanChangeAdbSideloading() {
539   crostini::CrostiniFeatures::Get()->CanChangeAdbSideloading(
540       profile_, base::BindOnce(&CrostiniHandler::OnCanChangeArcAdbSideloading,
541                                weak_ptr_factory_.GetWeakPtr()));
542 }
543 
OnCanChangeArcAdbSideloading(bool can_change_arc_adb_sideloading)544 void CrostiniHandler::OnCanChangeArcAdbSideloading(
545     bool can_change_arc_adb_sideloading) {
546   FireWebUIListener("crostini-can-change-arc-adb-sideload-changed",
547                     base::Value(can_change_arc_adb_sideloading));
548 }
549 
HandleCrostiniUpgraderDialogStatusRequest(const base::ListValue * args)550 void CrostiniHandler::HandleCrostiniUpgraderDialogStatusRequest(
551     const base::ListValue* args) {
552   AllowJavascript();
553   CHECK_EQ(0U, args->GetList().size());
554   bool is_open = crostini::CrostiniManager::GetForProfile(profile_)
555                      ->GetCrostiniDialogStatus(crostini::DialogType::UPGRADER);
556   OnCrostiniDialogStatusChanged(crostini::DialogType::UPGRADER, is_open);
557 }
558 
HandleCrostiniContainerUpgradeAvailableRequest(const base::ListValue * args)559 void CrostiniHandler::HandleCrostiniContainerUpgradeAvailableRequest(
560     const base::ListValue* args) {
561   AllowJavascript();
562 
563   bool can_upgrade = crostini::ShouldAllowContainerUpgrade(profile_);
564   OnContainerOsReleaseChanged(crostini::DefaultContainerId(), can_upgrade);
565 }
566 
OnActivePortsChanged(const base::ListValue & activePorts)567 void CrostiniHandler::OnActivePortsChanged(const base::ListValue& activePorts) {
568   // Other side listens with cr.addWebUIListener
569   FireWebUIListener("crostini-port-forwarder-active-ports-changed",
570                     activePorts);
571 }
572 
HandleAddCrostiniPortForward(const base::ListValue * args)573 void CrostiniHandler::HandleAddCrostiniPortForward(
574     const base::ListValue* args) {
575   CHECK_EQ(6U, args->GetList().size());
576 
577   std::string callback_id = args->GetList()[0].GetString();
578   std::string vm_name = args->GetList()[1].GetString();
579   std::string container_name = args->GetList()[2].GetString();
580   int port_number = args->GetList()[3].GetInt();
581   int protocol_type = args->GetList()[4].GetInt();
582   std::string label = args->GetList()[5].GetString();
583 
584   if (!crostini::CrostiniFeatures::Get()->IsPortForwardingAllowed(profile_)) {
585     OnPortForwardComplete(callback_id, false);
586     return;
587   }
588 
589   crostini::CrostiniPortForwarder::GetForProfile(profile_)->AddPort(
590       crostini::ContainerId(std::move(vm_name), std::move(container_name)),
591       port_number,
592       static_cast<crostini::CrostiniPortForwarder::Protocol>(protocol_type),
593       std::move(label),
594       base::BindOnce(&CrostiniHandler::OnPortForwardComplete,
595                      weak_ptr_factory_.GetWeakPtr(), std::move(callback_id)));
596 }
597 
HandleRemoveCrostiniPortForward(const base::ListValue * args)598 void CrostiniHandler::HandleRemoveCrostiniPortForward(
599     const base::ListValue* args) {
600   CHECK_EQ(5U, args->GetSize());
601   std::string callback_id;
602   CHECK(args->GetString(0, &callback_id));
603   std::string vm_name;
604   CHECK(args->GetString(1, &vm_name));
605   std::string container_name;
606   CHECK(args->GetString(2, &container_name));
607   int port_number;
608   CHECK(args->GetInteger(3, &port_number));
609   int protocol_type;
610   CHECK(args->GetInteger(4, &protocol_type));
611 
612   if (!crostini::CrostiniFeatures::Get()->IsPortForwardingAllowed(profile_)) {
613     OnPortForwardComplete(callback_id, false);
614     return;
615   }
616 
617   crostini::CrostiniPortForwarder::GetForProfile(profile_)->RemovePort(
618       crostini::ContainerId(std::move(vm_name), std::move(container_name)),
619       port_number,
620       static_cast<crostini::CrostiniPortForwarder::Protocol>(protocol_type),
621       base::Bind(&CrostiniHandler::OnPortForwardComplete,
622                  weak_ptr_factory_.GetWeakPtr(), std::move(callback_id)));
623 }
624 
HandleRemoveAllCrostiniPortForwards(const base::ListValue * args)625 void CrostiniHandler::HandleRemoveAllCrostiniPortForwards(
626     const base::ListValue* args) {
627   CHECK_EQ(2U, args->GetSize());
628   const auto& args_list = args->GetList();
629   std::string vm_name = args_list[0].GetString();
630   std::string container_name = args_list[1].GetString();
631 
632   if (!crostini::CrostiniFeatures::Get()->IsPortForwardingAllowed(profile_)) {
633     return;
634   }
635 
636   crostini::CrostiniPortForwarder::GetForProfile(profile_)->RemoveAllPorts(
637       crostini::ContainerId(std::move(vm_name), std::move(container_name)));
638 }
639 
HandleActivateCrostiniPortForward(const base::ListValue * args)640 void CrostiniHandler::HandleActivateCrostiniPortForward(
641     const base::ListValue* args) {
642   CHECK_EQ(5U, args->GetSize());
643 
644   std::string callback_id;
645   CHECK(args->GetString(0, &callback_id));
646   std::string vm_name;
647   CHECK(args->GetString(1, &vm_name));
648   std::string container_name;
649   CHECK(args->GetString(2, &container_name));
650   int port_number;
651   CHECK(args->GetInteger(3, &port_number));
652   int protocol_type;
653   CHECK(args->GetInteger(4, &protocol_type));
654 
655   if (!crostini::CrostiniFeatures::Get()->IsPortForwardingAllowed(profile_)) {
656     OnPortForwardComplete(callback_id, false);
657     return;
658   }
659 
660   crostini::CrostiniPortForwarder::GetForProfile(profile_)->ActivatePort(
661       crostini::ContainerId(std::move(vm_name), std::move(container_name)),
662       port_number,
663       static_cast<crostini::CrostiniPortForwarder::Protocol>(protocol_type),
664       base::Bind(&CrostiniHandler::OnPortForwardComplete,
665                  weak_ptr_factory_.GetWeakPtr(), std::move(callback_id)));
666 }
667 
HandleDeactivateCrostiniPortForward(const base::ListValue * args)668 void CrostiniHandler::HandleDeactivateCrostiniPortForward(
669     const base::ListValue* args) {
670   CHECK_EQ(5U, args->GetSize());
671 
672   std::string callback_id;
673   CHECK(args->GetString(0, &callback_id));
674   std::string vm_name;
675   CHECK(args->GetString(1, &vm_name));
676   std::string container_name;
677   CHECK(args->GetString(2, &container_name));
678   int port_number;
679   CHECK(args->GetInteger(3, &port_number));
680   int protocol_type;
681   CHECK(args->GetInteger(4, &protocol_type));
682 
683   if (!crostini::CrostiniFeatures::Get()->IsPortForwardingAllowed(profile_)) {
684     OnPortForwardComplete(callback_id, false);
685     return;
686   }
687 
688   crostini::CrostiniPortForwarder::GetForProfile(profile_)->DeactivatePort(
689       crostini::ContainerId(std::move(vm_name), std::move(container_name)),
690       port_number,
691       static_cast<crostini::CrostiniPortForwarder::Protocol>(protocol_type),
692       base::Bind(&CrostiniHandler::OnPortForwardComplete,
693                  weak_ptr_factory_.GetWeakPtr(), std::move(callback_id)));
694 }
695 
OnPortForwardComplete(std::string callback_id,bool success)696 void CrostiniHandler::OnPortForwardComplete(std::string callback_id,
697                                             bool success) {
698   ResolveJavascriptCallback(base::Value(callback_id), base::Value(success));
699 }
700 
ResolveGetCrostiniDiskInfoCallback(const std::string & callback_id,std::unique_ptr<crostini::CrostiniDiskInfo> disk_info)701 void CrostiniHandler::ResolveGetCrostiniDiskInfoCallback(
702     const std::string& callback_id,
703     std::unique_ptr<crostini::CrostiniDiskInfo> disk_info) {
704   ResolveJavascriptCallback(base::Value(std::move(callback_id)),
705                             CrostiniDiskInfoToValue(std::move(disk_info)));
706 }
707 
HandleGetCrostiniDiskInfo(const base::ListValue * args)708 void CrostiniHandler::HandleGetCrostiniDiskInfo(const base::ListValue* args) {
709   AllowJavascript();
710   CHECK_EQ(3U, args->GetList().size());
711   std::string callback_id = args->GetList()[0].GetString();
712   std::string vm_name = args->GetList()[1].GetString();
713   bool full_info = args->GetList()[2].GetBool();
714   crostini::disk::GetDiskInfo(
715       base::BindOnce(&CrostiniHandler::ResolveGetCrostiniDiskInfoCallback,
716                      weak_ptr_factory_.GetWeakPtr(), std::move(callback_id)),
717       profile_, std::move(vm_name), full_info);
718 }
719 
HandleResizeCrostiniDisk(const base::ListValue * args)720 void CrostiniHandler::HandleResizeCrostiniDisk(const base::ListValue* args) {
721   CHECK_EQ(3U, args->GetList().size());
722   std::string callback_id = args->GetList()[0].GetString();
723   std::string vm_name = args->GetList()[1].GetString();
724   double bytes = args->GetList()[2].GetDouble();
725   crostini::disk::ResizeCrostiniDisk(
726       profile_, std::move(vm_name), bytes,
727       base::BindOnce(&CrostiniHandler::ResolveResizeCrostiniDiskCallback,
728                      weak_ptr_factory_.GetWeakPtr(), std::move(callback_id)));
729 }
730 
ResolveResizeCrostiniDiskCallback(const std::string & callback_id,bool succeeded)731 void CrostiniHandler::ResolveResizeCrostiniDiskCallback(
732     const std::string& callback_id,
733     bool succeeded) {
734   ResolveJavascriptCallback(base::Value(std::move(callback_id)),
735                             base::Value(succeeded));
736 }
737 
HandleCheckCrostiniMicSharingStatus(const base::ListValue * args)738 void CrostiniHandler::HandleCheckCrostiniMicSharingStatus(
739     const base::ListValue* args) {
740   CHECK_EQ(2U, args->GetList().size());
741   std::string callback_id = args->GetList()[0].GetString();
742   bool proposed_value = args->GetList()[1].GetBool();
743   bool requiresRestart =
744       crostini::IsCrostiniRunning(profile_) &&
745       crostini::CrostiniManager::GetForProfile(profile_)
746               ->crostini_mic_sharing_enabled() != proposed_value;
747 
748   ResolveJavascriptCallback(base::Value(std::move(callback_id)),
749                             base::Value(requiresRestart));
750 }
751 
HandleGetCrostiniActivePorts(const base::ListValue * args)752 void CrostiniHandler::HandleGetCrostiniActivePorts(
753     const base::ListValue* args) {
754   AllowJavascript();
755   CHECK_EQ(1U, args->GetList().size());
756 
757   std::string callback_id = args->GetList()[0].GetString();
758 
759   ResolveJavascriptCallback(
760       base::Value(callback_id),
761       crostini::CrostiniPortForwarder::GetForProfile(profile_)
762           ->GetActivePorts());
763 }
764 
HandleCheckCrostiniIsRunning(const base::ListValue * args)765 void CrostiniHandler::HandleCheckCrostiniIsRunning(
766     const base::ListValue* args) {
767   AllowJavascript();
768   CHECK_EQ(1U, args->GetList().size());
769 
770   std::string callback_id = args->GetList()[0].GetString();
771 
772   ResolveJavascriptCallback(base::Value(callback_id),
773                             base::Value(crostini::IsCrostiniRunning(profile_)));
774 }
775 
OnContainerStarted(const crostini::ContainerId & container_id)776 void CrostiniHandler::OnContainerStarted(
777     const crostini::ContainerId& container_id) {
778   FireWebUIListener("crostini-status-changed", base::Value(true));
779 }
780 
OnContainerShutdown(const crostini::ContainerId & container_id)781 void CrostiniHandler::OnContainerShutdown(
782     const crostini::ContainerId& container_id) {
783   FireWebUIListener("crostini-status-changed", base::Value(false));
784 }
785 
HandleShutdownCrostini(const base::ListValue * args)786 void CrostiniHandler::HandleShutdownCrostini(const base::ListValue* args) {
787   CHECK_EQ(0U, args->GetList().size());
788 
789   const std::string vm_name = "termina";
790 
791   crostini::CrostiniManager::GetForProfile(profile_)->StopVm(
792       std::move(vm_name), std::move(base::DoNothing()));
793 }
794 
OnCrostiniMicSharingEnabledChanged(bool enabled)795 void CrostiniHandler::OnCrostiniMicSharingEnabledChanged(bool enabled) {
796   FireWebUIListener("crostini-mic-sharing-enabled-changed",
797                     base::Value(enabled));
798 }
799 
HandleSetCrostiniMicSharingEnabled(const base::ListValue * args)800 void CrostiniHandler::HandleSetCrostiniMicSharingEnabled(
801     const base::ListValue* args) {
802   CHECK_EQ(1U, args->GetList().size());
803   bool enabled = args->GetList()[0].GetBool();
804 
805   crostini::CrostiniManager::GetForProfile(profile_)
806       ->SetCrostiniMicSharingEnabled(enabled);
807 }
808 
HandleGetCrostiniMicSharingEnabled(const base::ListValue * args)809 void CrostiniHandler::HandleGetCrostiniMicSharingEnabled(
810     const base::ListValue* args) {
811   CHECK_EQ(1U, args->GetList().size());
812 
813   std::string callback_id = args->GetList()[0].GetString();
814 
815   ResolveJavascriptCallback(
816       base::Value(callback_id),
817       base::Value(crostini::CrostiniManager::GetForProfile(profile_)
818                       ->crostini_mic_sharing_enabled()));
819 }
820 
821 }  // namespace settings
822 }  // namespace chromeos
823