blob: 7415c12e582872161f7514841e5a166a0d6401c4 [file] [log] [blame]
// Copyright 2018 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/system/user_removal_manager.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner.h"
#include "base/time/time.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/persistent_pref_store.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
namespace ash {
namespace user_removal_manager {
namespace {
// The time that InitiateUserRemoval waits on the passed callback to do a log
// out, otherwise it does the log out itself.
constexpr base::TimeDelta kFailsafeTimerTimeout = base::Seconds(60);
// Override for the LogOut function inside of tests.
base::OnceClosure& GetLogOutOverrideCallbackForTest() {
static base::NoDestructor<base::OnceClosure> callback;
return *callback;
}
} // namespace
bool RemoveUsersIfNeeded(PrefService* local_state) {
const PrefService::Preference* pref =
local_state->FindPreference(prefs::kRemoveUsersRemoteCommand);
if (pref->IsDefaultValue()) {
// Nothing to be done.
return false;
}
if (!pref->GetValue()->GetBool()) {
LOG(ERROR) << "RemoveUsers started and did not finish. Chrome crashed?";
// Return to avoid crash loop.
return false;
}
local_state->SetBoolean(prefs::kRemoveUsersRemoteCommand, false);
local_state->CommitPendingWrite();
// TODO(https://crbug.com/1344832): Emit start metric here.
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
// Make a copy of the list since we'll be removing users (and the list would
// change underneath us if we used a reference).
const user_manager::UserList user_list = user_manager->GetPersistedUsers();
for (user_manager::User* user : user_list) {
user_manager->RemoveUser(
user->GetAccountId(),
user_manager::UserRemovalReason::REMOTE_ADMIN_INITIATED);
}
// Revert to default value after removal is done.
local_state->ClearPref(prefs::kRemoveUsersRemoteCommand);
// TODO(https://crbug.com/1344832): Emit finish metric here.
return true;
}
void LogOut() {
auto& log_out_override_callback = GetLogOutOverrideCallbackForTest();
if (log_out_override_callback) {
std::move(log_out_override_callback).Run();
return;
}
chrome::AttemptUserExit();
}
void OverrideLogOutForTesting(base::OnceClosure callback) {
auto& log_out_override_callback = GetLogOutOverrideCallbackForTest();
log_out_override_callback = std::move(callback);
}
void InitiateUserRemoval(PrefService* local_state,
base::OnceClosure on_pref_persisted_callback) {
local_state->SetBoolean(prefs::kRemoveUsersRemoteCommand, true);
local_state->CommitPendingWrite(base::BindOnce(
[](base::OnceClosure on_pref_persisted_callback) {
// Start the failsafe timer.
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, base::BindOnce(&LogOut), kFailsafeTimerTimeout);
if (on_pref_persisted_callback)
std::move(on_pref_persisted_callback).Run();
},
std::move(on_pref_persisted_callback)));
}
} // namespace user_removal_manager
} // namespace ash