blob: 821ea0a8c02d04e368bc263bb0f2972b12eaf54d [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/app_mode/app_launch_utils.h"
#include "ash/constants/ash_switches.h"
#include "base/check_deref.h"
#include "base/command_line.h"
#include "base/notreached.h"
#include "chrome/browser/ash/app_mode/crash_recovery_launcher.h"
#include "chrome/browser/ash/app_mode/kiosk_app_launch_error.h"
#include "chrome/browser/ash/app_mode/kiosk_app_types.h"
#include "chrome/browser/ash/app_mode/kiosk_chrome_app_manager.h"
#include "chrome/browser/ash/app_mode/kiosk_controller.h"
#include "chrome/browser/ash/app_mode/web_app/web_kiosk_app_manager.h"
#include "chrome/browser/ash/login/startup_utils.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"
namespace ash {
namespace {
// The list of prefs that are reset on the start of each kiosk session.
const char* const kPrefsToReset[] = {"settings.accessibility", // ChromeVox
"settings.a11y", "ash.docked_magnifier",
"settings.tts"};
const char* const kOneTimeAutoLaunchWebKioskAccountId =
"one_time_auto_launch.web_app_account_id";
const char* const kOneTimeAutoLaunchChromeAppAccountId =
"one_time_auto_launch.chrome_app_account_id";
const char* const kOneTimeAutoLaunchChromeAppId =
"one_time_auto_launch.chrome_app_id";
// This vector is used in tests when they want to replace `kPrefsToReset` with
// their own list.
std::vector<std::string>* test_prefs_to_reset = nullptr;
AccountId ToAccountId(const std::string* account_id_string) {
AccountId account_id;
CHECK(AccountId::Deserialize(CHECK_DEREF(account_id_string), &account_id));
return account_id;
}
} // namespace
void LaunchAppOrDie(Profile* profile, const KioskAppId& kiosk_app_id) {
auto* launcher =
new CrashRecoveryLauncher(CHECK_DEREF(profile), kiosk_app_id);
launcher->Start(base::BindOnce(
[](CrashRecoveryLauncher* launcher, const KioskAppId& kiosk_app_id,
Profile* profile, bool success,
const std::optional<std::string>& app_name) {
delete launcher;
if (success) {
CreateKioskSystemSession(kiosk_app_id, profile, app_name);
} else {
chrome::AttemptUserExit();
}
},
launcher, kiosk_app_id, profile));
}
void ResetEphemeralKioskPreferences(PrefService* prefs) {
CHECK(prefs);
CHECK(user_manager::UserManager::IsInitialized() &&
user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp());
for (size_t pref_id = 0;
pref_id < (test_prefs_to_reset ? test_prefs_to_reset->size()
: std::size(kPrefsToReset));
pref_id++) {
const std::string branch_path = test_prefs_to_reset
? (*test_prefs_to_reset)[pref_id]
: kPrefsToReset[pref_id];
prefs->ClearPrefsWithPrefixSilently(branch_path);
}
}
void SetEphemeralKioskPreferencesListForTesting(
std::vector<std::string>* prefs) {
test_prefs_to_reset = prefs;
}
bool ShouldAutoLaunchKioskApp(const base::CommandLine& command_line,
const PrefService& local_state) {
// We shouldn't auto launch kiosk app if a designated command line switch was
// used.
//
// For example, in Tast tests command line switch is used to prevent kiosk
// autolaunch configured by policy from a previous test. This way ChromeOS
// will stay on the login screen and Tast can perform policies cleanup.
if (command_line.HasSwitch(switches::kPreventKioskAutolaunchForTesting)) {
return false;
}
// We shouldn't auto launch kiosk app if powerwash screen should be shown.
if (local_state.GetBoolean(prefs::kFactoryResetRequested)) {
return false;
}
return command_line.HasSwitch(switches::kLoginManager) &&
KioskController::Get().GetAutoLaunchApp().has_value() &&
KioskAppLaunchError::Get() == KioskAppLaunchError::Error::kNone &&
// IsOobeCompleted() is needed to prevent kiosk session start in case
// of enterprise rollback, when keeping the enrollment, policy, not
// clearing TPM, but wiping stateful partition.
StartupUtils::IsOobeCompleted();
}
void CreateKioskSystemSession(const KioskAppId& kiosk_app_id,
Profile* profile,
const std::optional<std::string>& app_name) {
switch (kiosk_app_id.type) {
case KioskAppType::kWebApp:
WebKioskAppManager::Get()->InitKioskSystemSession(profile, kiosk_app_id,
app_name);
return;
case KioskAppType::kChromeApp:
KioskChromeAppManager::Get()->InitKioskSystemSession(profile,
kiosk_app_id);
return;
case KioskAppType::kArcApp:
// Do not create a `KioskBrowserSession` for ARC kiosk
return;
}
}
bool ShouldOneTimeAutoLaunchKioskApp(const base::CommandLine& command_line,
const PrefService& local_state) {
return command_line.HasSwitch(switches::kLoginManager) &&
GetOneTimeAutoLaunchKioskAppId(local_state).has_value();
}
std::optional<KioskAppId> GetOneTimeAutoLaunchKioskAppId(
const PrefService& local_state) {
const base::Value::Dict& dict =
local_state.GetDict(KioskChromeAppManager::kKioskDictionaryName);
if (dict.contains(kOneTimeAutoLaunchWebKioskAccountId)) {
return KioskAppId::ForWebApp(
ToAccountId(dict.FindString(kOneTimeAutoLaunchWebKioskAccountId)));
} else if (dict.contains(kOneTimeAutoLaunchChromeAppAccountId)) {
return KioskAppId::ForChromeApp(
CHECK_DEREF(dict.FindString(kOneTimeAutoLaunchChromeAppId)),
ToAccountId(dict.FindString(kOneTimeAutoLaunchChromeAppAccountId)));
}
return std::nullopt;
}
void ClearOneTimeAutoLaunchKioskAppId(PrefService& local_state) {
ScopedDictPrefUpdate dict_update(&local_state,
KioskChromeAppManager::kKioskDictionaryName);
dict_update->Remove(kOneTimeAutoLaunchWebKioskAccountId);
dict_update->Remove(kOneTimeAutoLaunchChromeAppAccountId);
dict_update->Remove(kOneTimeAutoLaunchChromeAppId);
local_state.CommitPendingWrite();
}
KioskAppId ExtractOneTimeAutoLaunchKioskAppId(PrefService& local_state) {
auto result = GetOneTimeAutoLaunchKioskAppId(local_state);
ClearOneTimeAutoLaunchKioskAppId(local_state);
return result.value();
}
void SetOneTimeAutoLaunchKioskAppId(PrefService& local_state,
const KioskAppId& kiosk_app_id) {
ScopedDictPrefUpdate dict_update(&local_state,
KioskChromeAppManager::kKioskDictionaryName);
switch (kiosk_app_id.type) {
case KioskAppType::kArcApp:
NOTREACHED();
return;
case KioskAppType::kChromeApp:
dict_update->Set(kOneTimeAutoLaunchChromeAppAccountId,
kiosk_app_id.account_id.Serialize());
dict_update->Set(kOneTimeAutoLaunchChromeAppId,
kiosk_app_id.app_id.value());
local_state.CommitPendingWrite();
return;
case KioskAppType::kWebApp:
dict_update->Set(kOneTimeAutoLaunchWebKioskAccountId,
kiosk_app_id.account_id.Serialize());
local_state.CommitPendingWrite();
return;
}
NOTREACHED_NORETURN();
}
} // namespace ash