Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / installer / util / master_preferences.cc
blob8754b7013a4e8f7baa56cd9b2398bafdfea51058
1 // Copyright (c) 2012 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.
5 #include "chrome/installer/util/master_preferences.h"
7 #include "base/environment.h"
8 #include "base/files/file_util.h"
9 #include "base/json/json_string_value_serializer.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "chrome/common/env_vars.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/installer/util/master_preferences_constants.h"
16 #include "chrome/installer/util/util_constants.h"
17 #include "components/variations/pref_names.h"
19 namespace {
21 const char kFirstRunTabs[] = "first_run_tabs";
23 base::LazyInstance<installer::MasterPreferences> g_master_preferences =
24 LAZY_INSTANCE_INITIALIZER;
26 bool GetURLFromValue(const base::Value* in_value, std::string* out_value) {
27 return in_value && out_value && in_value->GetAsString(out_value);
30 std::vector<std::string> GetNamedList(const char* name,
31 const base::DictionaryValue* prefs) {
32 std::vector<std::string> list;
33 if (!prefs)
34 return list;
36 const base::ListValue* value_list = NULL;
37 if (!prefs->GetList(name, &value_list))
38 return list;
40 list.reserve(value_list->GetSize());
41 for (size_t i = 0; i < value_list->GetSize(); ++i) {
42 const base::Value* entry;
43 std::string url_entry;
44 if (!value_list->Get(i, &entry) || !GetURLFromValue(entry, &url_entry)) {
45 NOTREACHED();
46 break;
48 list.push_back(url_entry);
50 return list;
53 base::DictionaryValue* ParseDistributionPreferences(
54 const std::string& json_data) {
55 JSONStringValueDeserializer json(json_data);
56 std::string error;
57 scoped_ptr<base::Value> root(json.Deserialize(NULL, &error));
58 if (!root.get()) {
59 LOG(WARNING) << "Failed to parse master prefs file: " << error;
60 return NULL;
62 if (!root->IsType(base::Value::TYPE_DICTIONARY)) {
63 LOG(WARNING) << "Failed to parse master prefs file: "
64 << "Root item must be a dictionary.";
65 return NULL;
67 return static_cast<base::DictionaryValue*>(root.release());
70 } // namespace
72 namespace installer {
74 MasterPreferences::MasterPreferences() : distribution_(NULL),
75 preferences_read_from_file_(false),
76 chrome_(true),
77 multi_install_(false) {
78 InitializeFromCommandLine(*base::CommandLine::ForCurrentProcess());
81 MasterPreferences::MasterPreferences(const base::CommandLine& cmd_line)
82 : distribution_(NULL),
83 preferences_read_from_file_(false),
84 chrome_(true),
85 multi_install_(false) {
86 InitializeFromCommandLine(cmd_line);
89 MasterPreferences::MasterPreferences(const base::FilePath& prefs_path)
90 : distribution_(NULL),
91 preferences_read_from_file_(false),
92 chrome_(true),
93 multi_install_(false) {
94 InitializeFromFilePath(prefs_path);
97 MasterPreferences::MasterPreferences(const std::string& prefs)
98 : distribution_(NULL),
99 preferences_read_from_file_(false),
100 chrome_(true),
101 multi_install_(false) {
102 InitializeFromString(prefs);
105 MasterPreferences::~MasterPreferences() {
108 void MasterPreferences::InitializeFromCommandLine(
109 const base::CommandLine& cmd_line) {
110 #if defined(OS_WIN)
111 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) {
112 base::FilePath prefs_path(cmd_line.GetSwitchValuePath(
113 installer::switches::kInstallerData));
114 InitializeFromFilePath(prefs_path);
115 } else {
116 master_dictionary_.reset(new base::DictionaryValue());
119 DCHECK(master_dictionary_.get());
121 // A simple map from command line switches to equivalent switches in the
122 // distribution dictionary. Currently all switches added will be set to
123 // 'true'.
124 static const struct CmdLineSwitchToDistributionSwitch {
125 const char* cmd_line_switch;
126 const char* distribution_switch;
127 } translate_switches[] = {
128 { installer::switches::kAutoLaunchChrome,
129 installer::master_preferences::kAutoLaunchChrome },
130 { installer::switches::kChrome,
131 installer::master_preferences::kChrome },
132 { installer::switches::kDisableLogging,
133 installer::master_preferences::kDisableLogging },
134 { installer::switches::kMsi,
135 installer::master_preferences::kMsi },
136 { installer::switches::kMultiInstall,
137 installer::master_preferences::kMultiInstall },
138 { installer::switches::kDoNotRegisterForUpdateLaunch,
139 installer::master_preferences::kDoNotRegisterForUpdateLaunch },
140 { installer::switches::kDoNotLaunchChrome,
141 installer::master_preferences::kDoNotLaunchChrome },
142 { installer::switches::kMakeChromeDefault,
143 installer::master_preferences::kMakeChromeDefault },
144 { installer::switches::kSystemLevel,
145 installer::master_preferences::kSystemLevel },
146 { installer::switches::kVerboseLogging,
147 installer::master_preferences::kVerboseLogging },
150 std::string name(installer::master_preferences::kDistroDict);
151 for (int i = 0; i < arraysize(translate_switches); ++i) {
152 if (cmd_line.HasSwitch(translate_switches[i].cmd_line_switch)) {
153 name.assign(installer::master_preferences::kDistroDict);
154 name.append(".").append(translate_switches[i].distribution_switch);
155 master_dictionary_->SetBoolean(name, true);
159 // See if the log file path was specified on the command line.
160 std::wstring str_value(cmd_line.GetSwitchValueNative(
161 installer::switches::kLogFile));
162 if (!str_value.empty()) {
163 name.assign(installer::master_preferences::kDistroDict);
164 name.append(".").append(installer::master_preferences::kLogFile);
165 master_dictionary_->SetString(name, str_value);
168 // Handle the special case of --system-level being implied by the presence of
169 // the kGoogleUpdateIsMachineEnvVar environment variable.
170 scoped_ptr<base::Environment> env(base::Environment::Create());
171 if (env != NULL) {
172 std::string is_machine_var;
173 env->GetVar(env_vars::kGoogleUpdateIsMachineEnvVar, &is_machine_var);
174 if (!is_machine_var.empty() && is_machine_var[0] == '1') {
175 VLOG(1) << "Taking system-level from environment.";
176 name.assign(installer::master_preferences::kDistroDict);
177 name.append(".").append(installer::master_preferences::kSystemLevel);
178 master_dictionary_->SetBoolean(name, true);
182 // Cache a pointer to the distribution dictionary. Ignore errors if any.
183 master_dictionary_->GetDictionary(installer::master_preferences::kDistroDict,
184 &distribution_);
186 InitializeProductFlags();
187 #endif
190 void MasterPreferences::InitializeFromFilePath(
191 const base::FilePath& prefs_path) {
192 std::string json_data;
193 // Failure to read the file is ignored as |json_data| will be the empty string
194 // and the remainder of this MasterPreferences object should still be
195 // initialized as best as possible.
196 if (base::PathExists(prefs_path) &&
197 !base::ReadFileToString(prefs_path, &json_data)) {
198 LOG(ERROR) << "Failed to read preferences from " << prefs_path.value();
200 if (InitializeFromString(json_data))
201 preferences_read_from_file_ = true;
204 bool MasterPreferences::InitializeFromString(const std::string& json_data) {
205 if (!json_data.empty())
206 master_dictionary_.reset(ParseDistributionPreferences(json_data));
208 bool data_is_valid = true;
209 if (!master_dictionary_.get()) {
210 master_dictionary_.reset(new base::DictionaryValue());
211 data_is_valid = false;
212 } else {
213 // Cache a pointer to the distribution dictionary.
214 master_dictionary_->GetDictionary(
215 installer::master_preferences::kDistroDict, &distribution_);
218 InitializeProductFlags();
219 EnforceLegacyPreferences();
220 return data_is_valid;
223 void MasterPreferences::InitializeProductFlags() {
224 // Make sure we start out with the correct defaults.
225 multi_install_ = false;
226 chrome_ = true;
228 GetBool(installer::master_preferences::kMultiInstall, &multi_install_);
230 // When multi-install is specified, the checks are pretty simple (in theory):
231 // In order to be installed/uninstalled, each product must have its switch
232 // present on the command line.
233 // When multi-install is not set, operate on Chrome.
234 if (multi_install_) {
235 if (!GetBool(installer::master_preferences::kChrome, &chrome_))
236 chrome_ = false;
237 } else {
238 chrome_ = true;
242 void MasterPreferences::EnforceLegacyPreferences() {
243 // If create_all_shortcuts was explicitly set to false, set
244 // do_not_create_(desktop|quick_launch)_shortcut to true.
245 bool create_all_shortcuts = true;
246 GetBool(installer::master_preferences::kCreateAllShortcuts,
247 &create_all_shortcuts);
248 if (!create_all_shortcuts) {
249 distribution_->SetBoolean(
250 installer::master_preferences::kDoNotCreateDesktopShortcut, true);
251 distribution_->SetBoolean(
252 installer::master_preferences::kDoNotCreateQuickLaunchShortcut, true);
255 // If there is no entry for kURLsToRestoreOnStartup and there is one for
256 // kURLsToRestoreOnStartupOld, copy the old to the new.
257 const base::ListValue* startup_urls_list = NULL;
258 if (master_dictionary_ &&
259 !master_dictionary_->GetList(prefs::kURLsToRestoreOnStartup, NULL) &&
260 master_dictionary_->GetList(prefs::kURLsToRestoreOnStartupOld,
261 &startup_urls_list) &&
262 startup_urls_list) {
263 base::ListValue* new_startup_urls_list = startup_urls_list->DeepCopy();
264 master_dictionary_->Set(prefs::kURLsToRestoreOnStartup,
265 new_startup_urls_list);
269 bool MasterPreferences::GetBool(const std::string& name, bool* value) const {
270 bool ret = false;
271 if (distribution_)
272 ret = distribution_->GetBoolean(name, value);
273 return ret;
276 bool MasterPreferences::GetInt(const std::string& name, int* value) const {
277 bool ret = false;
278 if (distribution_)
279 ret = distribution_->GetInteger(name, value);
280 return ret;
283 bool MasterPreferences::GetString(const std::string& name,
284 std::string* value) const {
285 bool ret = false;
286 if (distribution_)
287 ret = (distribution_->GetString(name, value) && !value->empty());
288 return ret;
291 std::vector<std::string> MasterPreferences::GetFirstRunTabs() const {
292 return GetNamedList(kFirstRunTabs, master_dictionary_.get());
295 bool MasterPreferences::GetExtensionsBlock(
296 base::DictionaryValue** extensions) const {
297 return master_dictionary_->GetDictionary(
298 master_preferences::kExtensionsBlock, extensions);
301 std::string MasterPreferences::GetCompressedVariationsSeed() const {
302 return ExtractPrefString(variations::prefs::kVariationsCompressedSeed);
305 std::string MasterPreferences::GetVariationsSeed() const {
306 return ExtractPrefString(variations::prefs::kVariationsSeed);
309 std::string MasterPreferences::GetVariationsSeedSignature() const {
310 return ExtractPrefString(variations::prefs::kVariationsSeedSignature);
313 std::string MasterPreferences::ExtractPrefString(
314 const std::string& name) const {
315 std::string result;
316 scoped_ptr<base::Value> pref_value;
317 if (master_dictionary_->Remove(name, &pref_value)) {
318 if (!pref_value->GetAsString(&result))
319 NOTREACHED();
321 return result;
324 // static
325 const MasterPreferences& MasterPreferences::ForCurrentProcess() {
326 return g_master_preferences.Get();
329 } // namespace installer