blob: a340b551445cf93a907bf4208662c24fa5e24948 [file] [log] [blame]
// Copyright (c) 2019 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/ui/webui/flags_ui_handler.h"
#include "base/bind.h"
#include "chrome/browser/about_flags.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/common/channel_info.h"
#include "components/flags_ui/flags_storage.h"
#include "components/flags_ui/flags_ui_constants.h"
#include "components/version_info/channel.h"
#if defined(OS_CHROMEOS)
#include "base/system/sys_info.h"
#include "chrome/browser/chromeos/login/session/user_session_manager.h"
#include "components/account_id/account_id.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/user_manager/user_manager.h"
#endif
FlagsUIHandler::FlagsUIHandler()
: access_(flags_ui::kGeneralAccessFlagsOnly),
experimental_features_requested_(false),
deprecated_features_only_(false) {}
FlagsUIHandler::~FlagsUIHandler() {}
void FlagsUIHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
flags_ui::kRequestExperimentalFeatures,
base::BindRepeating(&FlagsUIHandler::HandleRequestExperimentalFeatures,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
flags_ui::kEnableExperimentalFeature,
base::BindRepeating(
&FlagsUIHandler::HandleEnableExperimentalFeatureMessage,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
flags_ui::kSetOriginListFlag,
base::BindRepeating(&FlagsUIHandler::HandleSetOriginListFlagMessage,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
flags_ui::kRestartBrowser,
base::BindRepeating(&FlagsUIHandler::HandleRestartBrowser,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
flags_ui::kResetAllFlags,
base::BindRepeating(&FlagsUIHandler::HandleResetAllFlags,
base::Unretained(this)));
}
void FlagsUIHandler::Init(flags_ui::FlagsStorage* flags_storage,
flags_ui::FlagAccess access) {
flags_storage_.reset(flags_storage);
access_ = access;
if (experimental_features_requested_)
HandleRequestExperimentalFeatures(nullptr);
}
void FlagsUIHandler::HandleRequestExperimentalFeatures(
const base::ListValue* args) {
experimental_features_requested_ = true;
// Bail out if the handler hasn't been initialized yet. The request will be
// handled after the initialization.
if (!flags_storage_)
return;
base::DictionaryValue results;
std::unique_ptr<base::ListValue> supported_features(new base::ListValue);
std::unique_ptr<base::ListValue> unsupported_features(new base::ListValue);
if (deprecated_features_only_) {
about_flags::GetFlagFeatureEntriesForDeprecatedPage(
flags_storage_.get(), access_, supported_features.get(),
unsupported_features.get());
} else {
about_flags::GetFlagFeatureEntries(flags_storage_.get(), access_,
supported_features.get(),
unsupported_features.get());
}
results.Set(flags_ui::kSupportedFeatures, std::move(supported_features));
results.Set(flags_ui::kUnsupportedFeatures, std::move(unsupported_features));
results.SetBoolean(flags_ui::kNeedsRestart,
about_flags::IsRestartNeededToCommitChanges());
results.SetBoolean(flags_ui::kShowOwnerWarning,
access_ == flags_ui::kGeneralAccessFlagsOnly);
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
version_info::Channel channel = chrome::GetChannel();
results.SetBoolean(
flags_ui::kShowBetaChannelPromotion,
channel == version_info::Channel::STABLE && !deprecated_features_only_);
results.SetBoolean(
flags_ui::kShowDevChannelPromotion,
channel == version_info::Channel::BETA && !deprecated_features_only_);
#else
results.SetBoolean(flags_ui::kShowBetaChannelPromotion, false);
results.SetBoolean(flags_ui::kShowDevChannelPromotion, false);
#endif
web_ui()->CallJavascriptFunctionUnsafe(flags_ui::kReturnExperimentalFeatures,
results);
}
void FlagsUIHandler::HandleEnableExperimentalFeatureMessage(
const base::ListValue* args) {
DCHECK(flags_storage_);
DCHECK_EQ(2u, args->GetSize());
if (args->GetSize() != 2)
return;
std::string entry_internal_name;
std::string enable_str;
if (!args->GetString(0, &entry_internal_name) ||
!args->GetString(1, &enable_str) || entry_internal_name.empty()) {
NOTREACHED();
return;
}
about_flags::SetFeatureEntryEnabled(flags_storage_.get(), entry_internal_name,
enable_str == "true");
}
void FlagsUIHandler::HandleSetOriginListFlagMessage(
const base::ListValue* args) {
DCHECK(flags_storage_);
if (args->GetSize() != 2) {
NOTREACHED();
return;
}
std::string entry_internal_name;
std::string value_str;
if (!args->GetString(0, &entry_internal_name) ||
!args->GetString(1, &value_str) || entry_internal_name.empty()) {
NOTREACHED();
return;
}
about_flags::SetOriginListFlag(entry_internal_name, value_str,
flags_storage_.get());
}
void FlagsUIHandler::HandleRestartBrowser(const base::ListValue* args) {
DCHECK(flags_storage_);
#if defined(OS_CHROMEOS)
// On ChromeOS be less intrusive and restart inside the user session after
// we apply the newly selected flags.
base::CommandLine user_flags(base::CommandLine::NO_PROGRAM);
about_flags::ConvertFlagsToSwitches(flags_storage_.get(), &user_flags,
flags_ui::kAddSentinels);
// Adhere to policy-enforced command-line switch handling when
// applying modified flags..
chromeos::UserSessionManager::ApplyUserPolicyToSwitches(
Profile::FromWebUI(web_ui())->GetPrefs(), &user_flags);
base::CommandLine::StringVector flags;
// argv[0] is the program name |base::CommandLine::NO_PROGRAM|.
flags.assign(user_flags.argv().begin() + 1, user_flags.argv().end());
VLOG(1) << "Restarting to apply per-session flags...";
AccountId account_id =
user_manager::UserManager::Get()->GetActiveUser()->GetAccountId();
chromeos::UserSessionManager::GetInstance()->SetSwitchesForUser(
account_id,
chromeos::UserSessionManager::CommandLineSwitchesType::
kPolicyAndFlagsAndKioskControl,
flags);
#endif
chrome::AttemptRestart();
}
void FlagsUIHandler::HandleResetAllFlags(const base::ListValue* args) {
DCHECK(flags_storage_);
about_flags::ResetAllFlags(flags_storage_.get());
}