1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
|
// 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/settings/about_flags.h"
#include <string_view>
#include "base/check.h"
#include "base/command_line.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/values.h"
#include "chrome/browser/about_flags.h"
#include "chrome/browser/ash/login/session/user_session_manager.h"
#include "chrome/browser/site_isolation/about_flags.h"
#include "chrome/common/pref_names.h"
#include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "components/account_id/account_id.h"
#include "components/ownership/owner_settings_service.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"
#include "components/webui/flags/flags_storage.h"
#include "components/webui/flags/flags_ui_pref_names.h"
#include "third_party/cros_system_api/switches/chrome_switches.h"
namespace ash {
namespace about_flags {
namespace {
std::set<std::string> ParseFlagsFromCommandLine(
base::CommandLine* command_line) {
std::set<std::string> flags;
std::string encoded =
command_line->GetSwitchValueNative(chromeos::switches::kFeatureFlags);
if (encoded.empty()) {
return flags;
}
auto flags_list = base::JSONReader::Read(encoded);
if (!flags_list) {
LOG(WARNING) << "Failed to parse feature flags configuration";
return flags;
}
for (const auto& flag : flags_list.value().GetList()) {
if (!flag.is_string()) {
LOG(WARNING) << "Invalid entry in encoded feature flags";
continue;
}
flags.insert(flag.GetString());
}
return flags;
}
std::map<std::string, std::string> ParseOriginListFlagsFromCommmandLine(
base::CommandLine* command_line) {
std::map<std::string, std::string> origin_list_flags;
std::string encoded = command_line->GetSwitchValueNative(
chromeos::switches::kFeatureFlagsOriginList);
if (encoded.empty()) {
return origin_list_flags;
}
auto origin_list_flags_dict = base::JSONReader::Read(encoded);
if (!origin_list_flags_dict) {
LOG(WARNING) << "Failed to parse origin list configuration";
return origin_list_flags;
}
for (const auto entry : origin_list_flags_dict->GetDict()) {
if (!entry.second.is_string()) {
LOG(WARNING) << "Invalid entry in encoded origin list flags";
continue;
}
origin_list_flags[entry.first] = entry.second.GetString();
}
return origin_list_flags;
}
} // namespace
OwnerFlagsStorage::OwnerFlagsStorage(
PrefService* prefs,
ownership::OwnerSettingsService* owner_settings_service)
: flags_ui::PrefServiceFlagsStorage(prefs),
owner_settings_service_(owner_settings_service) {}
OwnerFlagsStorage::~OwnerFlagsStorage() = default;
bool OwnerFlagsStorage::SetFlags(const std::set<std::string>& flags) {
// Write the flags configuration to profile preferences, which are used to
// determine flags to apply when launching a user session.
PrefServiceFlagsStorage::SetFlags(flags);
// Also write the flags to device settings so they get applied to the Chrome
// OS login screen. The device setting is read by session_manager and passed
// to Chrome via a command line flag on startup.
base::Value::List feature_flags_list;
for (const auto& flag : flags) {
feature_flags_list.Append(flag);
}
owner_settings_service_->Set(kFeatureFlags,
base::Value(std::move(feature_flags_list)));
return true;
}
ReadOnlyFlagsStorage::ReadOnlyFlagsStorage(
const std::set<std::string>& flags,
const std::map<std::string, std::string>& origin_list_flags)
: flags_(flags), origin_list_flags_(origin_list_flags) {}
ReadOnlyFlagsStorage::ReadOnlyFlagsStorage(base::CommandLine* command_line)
: flags_(ParseFlagsFromCommandLine(command_line)),
origin_list_flags_(ParseOriginListFlagsFromCommmandLine(command_line)) {}
ReadOnlyFlagsStorage::~ReadOnlyFlagsStorage() = default;
std::set<std::string> ReadOnlyFlagsStorage::GetFlags() const {
return flags_;
}
bool ReadOnlyFlagsStorage::SetFlags(const std::set<std::string>& flags) {
return false;
}
void ReadOnlyFlagsStorage::CommitPendingWrites() {}
std::string ReadOnlyFlagsStorage::GetOriginListFlag(
const std::string& internal_entry_name) const {
const auto& entry = origin_list_flags_.find(internal_entry_name);
return entry != origin_list_flags_.end() ? entry->second : std::string();
}
void ReadOnlyFlagsStorage::SetOriginListFlag(
const std::string& internal_entry_name,
const std::string& origin_list_value) {}
std::string ReadOnlyFlagsStorage::GetStringFlag(
const std::string& internal_entry_name) const {
return GetOriginListFlag(internal_entry_name);
}
void ReadOnlyFlagsStorage::SetStringFlag(const std::string& internal_entry_name,
const std::string& string_value) {}
FeatureFlagsUpdate::FeatureFlagsUpdate(
const ::flags_ui::FlagsStorage& flags_storage,
PrefService* profile_prefs) {
flags_ = flags_storage.GetFlags();
ApplyUserPolicyToFlags(profile_prefs, &flags_);
for (const auto& flag : flags_) {
const auto origin_list_flag = flags_storage.GetOriginListFlag(flag);
if (!origin_list_flag.empty()) {
origin_list_flags_[flag] = origin_list_flag;
}
}
}
FeatureFlagsUpdate::~FeatureFlagsUpdate() = default;
bool FeatureFlagsUpdate::DiffersFromCommandLine(
base::CommandLine* cmdline,
std::set<std::string>* flags_difference) {
flags_difference->clear();
const auto cmdline_flags = ParseFlagsFromCommandLine(cmdline);
std::set_symmetric_difference(
flags_.begin(), flags_.end(), cmdline_flags.begin(), cmdline_flags.end(),
std::inserter(*flags_difference, flags_difference->begin()));
auto lookup = [](const std::map<std::string, std::string>& origin_list_flags,
const std::string& key) {
const auto entry = origin_list_flags.find(key);
return entry == origin_list_flags.end() ? std::nullopt
: std::make_optional(entry->second);
};
const auto cmdline_origin_list_flags =
ParseOriginListFlagsFromCommmandLine(cmdline);
for (const auto& flag : flags_) {
if (lookup(origin_list_flags_, flag) !=
lookup(cmdline_origin_list_flags, flag)) {
flags_difference->insert(flag);
}
}
return !flags_difference->empty();
}
void FeatureFlagsUpdate::UpdateSessionManager() {
// TODO(crbug.com/832857): Introduce a CHECK to ensure primary user.
// Early out so that switches for secondary users are not applied to the whole
// session. This could be removed when things like flags UI of secondary users
// are fixed properly and TODO above to add CHECK() is done.
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
const user_manager::User* primary_user = user_manager->GetPrimaryUser();
if (!primary_user || primary_user != user_manager->GetActiveUser())
return;
auto account_id = cryptohome::CreateAccountIdentifierFromAccountId(
primary_user->GetAccountId());
SessionManagerClient::Get()->SetFeatureFlagsForUser(
account_id, {flags_.begin(), flags_.end()}, origin_list_flags_);
}
// static
void FeatureFlagsUpdate::ApplyUserPolicyToFlags(PrefService* user_profile_prefs,
std::set<std::string>* flags) {
// Get target value for --site-per-process for the user session according to
// policy. If it is supposed to be enabled, make sure it can not be disabled
// using flags-induced command-line switches.
const PrefService::Preference* site_per_process_pref =
user_profile_prefs->FindPreference(::prefs::kSitePerProcess);
if (site_per_process_pref->IsManaged() &&
site_per_process_pref->GetValue()->GetBool()) {
flags->erase(::about_flags::SiteIsolationTrialOptOutChoiceEnabled());
}
}
} // namespace about_flags
} // namespace ash
|