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"
20 const char kFirstRunTabs
[] = "first_run_tabs";
22 base::LazyInstance
<installer::MasterPreferences
> g_master_preferences
=
23 LAZY_INSTANCE_INITIALIZER
;
25 bool GetURLFromValue(const base::Value
* in_value
, std::string
* out_value
) {
26 return in_value
&& out_value
&& in_value
->GetAsString(out_value
);
29 std::vector
<std::string
> GetNamedList(const char* name
,
30 const base::DictionaryValue
* prefs
) {
31 std::vector
<std::string
> list
;
35 const base::ListValue
* value_list
= NULL
;
36 if (!prefs
->GetList(name
, &value_list
))
39 list
.reserve(value_list
->GetSize());
40 for (size_t i
= 0; i
< value_list
->GetSize(); ++i
) {
41 const base::Value
* entry
;
42 std::string url_entry
;
43 if (!value_list
->Get(i
, &entry
) || !GetURLFromValue(entry
, &url_entry
)) {
47 list
.push_back(url_entry
);
52 base::DictionaryValue
* ParseDistributionPreferences(
53 const std::string
& json_data
) {
54 JSONStringValueSerializer
json(json_data
);
56 scoped_ptr
<base::Value
> root(json
.Deserialize(NULL
, &error
));
58 LOG(WARNING
) << "Failed to parse master prefs file: " << error
;
61 if (!root
->IsType(base::Value::TYPE_DICTIONARY
)) {
62 LOG(WARNING
) << "Failed to parse master prefs file: "
63 << "Root item must be a dictionary.";
66 return static_cast<base::DictionaryValue
*>(root
.release());
73 MasterPreferences::MasterPreferences() : distribution_(NULL
),
74 preferences_read_from_file_(false),
76 chrome_app_launcher_(false),
77 multi_install_(false) {
78 InitializeFromCommandLine(*CommandLine::ForCurrentProcess());
81 MasterPreferences::MasterPreferences(const CommandLine
& cmd_line
)
82 : distribution_(NULL
),
83 preferences_read_from_file_(false),
85 chrome_app_launcher_(false),
86 multi_install_(false) {
87 InitializeFromCommandLine(cmd_line
);
90 MasterPreferences::MasterPreferences(const base::FilePath
& prefs_path
)
91 : distribution_(NULL
),
92 preferences_read_from_file_(false),
94 chrome_app_launcher_(false),
95 multi_install_(false) {
96 std::string json_data
;
97 // Failure to read the file is ignored as |json_data| will be the empty string
98 // and the remainder of this MasterPreferences object should still be
99 // initialized as best as possible.
100 if (base::PathExists(prefs_path
) &&
101 !base::ReadFileToString(prefs_path
, &json_data
)) {
102 LOG(ERROR
) << "Failed to read preferences from " << prefs_path
.value();
104 if (InitializeFromString(json_data
))
105 preferences_read_from_file_
= true;
108 MasterPreferences::MasterPreferences(const std::string
& prefs
)
109 : distribution_(NULL
),
110 preferences_read_from_file_(false),
112 chrome_app_launcher_(false),
113 multi_install_(false) {
114 InitializeFromString(prefs
);
117 MasterPreferences::~MasterPreferences() {
120 void MasterPreferences::InitializeFromCommandLine(const CommandLine
& cmd_line
) {
122 if (cmd_line
.HasSwitch(installer::switches::kInstallerData
)) {
123 base::FilePath
prefs_path(cmd_line
.GetSwitchValuePath(
124 installer::switches::kInstallerData
));
125 this->MasterPreferences::MasterPreferences(prefs_path
);
127 master_dictionary_
.reset(new base::DictionaryValue());
130 DCHECK(master_dictionary_
.get());
132 // A simple map from command line switches to equivalent switches in the
133 // distribution dictionary. Currently all switches added will be set to
135 static const struct CmdLineSwitchToDistributionSwitch
{
136 const char* cmd_line_switch
;
137 const char* distribution_switch
;
138 } translate_switches
[] = {
139 { installer::switches::kAutoLaunchChrome
,
140 installer::master_preferences::kAutoLaunchChrome
},
141 { installer::switches::kChromeAppHostDeprecated
,
142 installer::master_preferences::kChromeAppHostDeprecated
},
143 { installer::switches::kChromeAppLauncher
,
144 installer::master_preferences::kChromeAppLauncher
},
145 { installer::switches::kChrome
,
146 installer::master_preferences::kChrome
},
147 { installer::switches::kDisableLogging
,
148 installer::master_preferences::kDisableLogging
},
149 { installer::switches::kMsi
,
150 installer::master_preferences::kMsi
},
151 { installer::switches::kMultiInstall
,
152 installer::master_preferences::kMultiInstall
},
153 { installer::switches::kDoNotRegisterForUpdateLaunch
,
154 installer::master_preferences::kDoNotRegisterForUpdateLaunch
},
155 { installer::switches::kDoNotLaunchChrome
,
156 installer::master_preferences::kDoNotLaunchChrome
},
157 { installer::switches::kMakeChromeDefault
,
158 installer::master_preferences::kMakeChromeDefault
},
159 { installer::switches::kSystemLevel
,
160 installer::master_preferences::kSystemLevel
},
161 { installer::switches::kVerboseLogging
,
162 installer::master_preferences::kVerboseLogging
},
165 std::string
name(installer::master_preferences::kDistroDict
);
166 for (int i
= 0; i
< arraysize(translate_switches
); ++i
) {
167 if (cmd_line
.HasSwitch(translate_switches
[i
].cmd_line_switch
)) {
168 name
.assign(installer::master_preferences::kDistroDict
);
169 name
.append(".").append(translate_switches
[i
].distribution_switch
);
170 master_dictionary_
->SetBoolean(name
, true);
174 // See if the log file path was specified on the command line.
175 std::wstring
str_value(cmd_line
.GetSwitchValueNative(
176 installer::switches::kLogFile
));
177 if (!str_value
.empty()) {
178 name
.assign(installer::master_preferences::kDistroDict
);
179 name
.append(".").append(installer::master_preferences::kLogFile
);
180 master_dictionary_
->SetString(name
, str_value
);
183 // Handle the special case of --system-level being implied by the presence of
184 // the kGoogleUpdateIsMachineEnvVar environment variable.
185 scoped_ptr
<base::Environment
> env(base::Environment::Create());
187 std::string is_machine_var
;
188 env
->GetVar(env_vars::kGoogleUpdateIsMachineEnvVar
, &is_machine_var
);
189 if (!is_machine_var
.empty() && is_machine_var
[0] == '1') {
190 VLOG(1) << "Taking system-level from environment.";
191 name
.assign(installer::master_preferences::kDistroDict
);
192 name
.append(".").append(installer::master_preferences::kSystemLevel
);
193 master_dictionary_
->SetBoolean(name
, true);
197 // Cache a pointer to the distribution dictionary. Ignore errors if any.
198 master_dictionary_
->GetDictionary(installer::master_preferences::kDistroDict
,
201 InitializeProductFlags();
205 bool MasterPreferences::InitializeFromString(const std::string
& json_data
) {
206 if (!json_data
.empty())
207 master_dictionary_
.reset(ParseDistributionPreferences(json_data
));
209 bool data_is_valid
= true;
210 if (!master_dictionary_
.get()) {
211 master_dictionary_
.reset(new base::DictionaryValue());
212 data_is_valid
= false;
214 // Cache a pointer to the distribution dictionary.
215 master_dictionary_
->GetDictionary(
216 installer::master_preferences::kDistroDict
, &distribution_
);
219 InitializeProductFlags();
220 EnforceLegacyPreferences();
221 return data_is_valid
;
224 void MasterPreferences::InitializeProductFlags() {
225 // Make sure we start out with the correct defaults.
226 multi_install_
= false;
227 chrome_app_launcher_
= false;
230 GetBool(installer::master_preferences::kMultiInstall
, &multi_install_
);
232 GetBool(installer::master_preferences::kChromeAppLauncher
,
233 &chrome_app_launcher_
);
235 // The deprecated switch --app-host behaves like --app-launcher.
236 bool chrome_app_host
= false;
237 GetBool(installer::master_preferences::kChromeAppHostDeprecated
,
239 chrome_app_launcher_
= chrome_app_launcher_
|| chrome_app_host
;
241 // When multi-install is specified, the checks are pretty simple (in theory):
242 // In order to be installed/uninstalled, each product must have its switch
243 // present on the command line.
244 // When multi-install is not set, operate on Chrome.
245 if (multi_install_
) {
246 if (!GetBool(installer::master_preferences::kChrome
, &chrome_
))
253 void MasterPreferences::EnforceLegacyPreferences() {
254 // If create_all_shortcuts was explicitly set to false, set
255 // do_not_create_(desktop|quick_launch)_shortcut to true.
256 bool create_all_shortcuts
= true;
257 GetBool(installer::master_preferences::kCreateAllShortcuts
,
258 &create_all_shortcuts
);
259 if (!create_all_shortcuts
) {
260 distribution_
->SetBoolean(
261 installer::master_preferences::kDoNotCreateDesktopShortcut
, true);
262 distribution_
->SetBoolean(
263 installer::master_preferences::kDoNotCreateQuickLaunchShortcut
, true);
266 // If there is no entry for kURLsToRestoreOnStartup and there is one for
267 // kURLsToRestoreOnStartupOld, copy the old to the new.
268 const base::ListValue
* startup_urls_list
= NULL
;
269 if (master_dictionary_
&&
270 !master_dictionary_
->GetList(prefs::kURLsToRestoreOnStartup
, NULL
) &&
271 master_dictionary_
->GetList(prefs::kURLsToRestoreOnStartupOld
,
272 &startup_urls_list
) &&
274 base::ListValue
* new_startup_urls_list
= startup_urls_list
->DeepCopy();
275 master_dictionary_
->Set(prefs::kURLsToRestoreOnStartup
,
276 new_startup_urls_list
);
280 bool MasterPreferences::GetBool(const std::string
& name
, bool* value
) const {
283 ret
= distribution_
->GetBoolean(name
, value
);
287 bool MasterPreferences::GetInt(const std::string
& name
, int* value
) const {
290 ret
= distribution_
->GetInteger(name
, value
);
294 bool MasterPreferences::GetString(const std::string
& name
,
295 std::string
* value
) const {
298 ret
= (distribution_
->GetString(name
, value
) && !value
->empty());
302 std::vector
<std::string
> MasterPreferences::GetFirstRunTabs() const {
303 return GetNamedList(kFirstRunTabs
, master_dictionary_
.get());
306 bool MasterPreferences::GetExtensionsBlock(
307 base::DictionaryValue
** extensions
) const {
308 return master_dictionary_
->GetDictionary(
309 master_preferences::kExtensionsBlock
, extensions
);
312 std::string
MasterPreferences::GetVariationsSeed() const {
313 return ExtractPrefString(prefs::kVariationsSeed
);
316 std::string
MasterPreferences::GetVariationsSeedSignature() const {
317 return ExtractPrefString(prefs::kVariationsSeedSignature
);
320 std::string
MasterPreferences::ExtractPrefString(
321 const std::string
& name
) const {
323 scoped_ptr
<base::Value
> pref_value
;
324 if (master_dictionary_
->Remove(name
, &pref_value
)) {
325 if (!pref_value
->GetAsString(&result
))
332 const MasterPreferences
& MasterPreferences::ForCurrentProcess() {
333 return g_master_preferences
.Get();
336 } // namespace installer