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/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/path_service.h"
13 #include "base/strings/string_util.h"
14 #include "chrome/common/env_vars.h"
15 #include "chrome/common/pref_names.h"
16 #include "chrome/installer/util/master_preferences_constants.h"
17 #include "chrome/installer/util/util_constants.h"
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
;
36 const base::ListValue
* value_list
= NULL
;
37 if (!prefs
->GetList(name
, &value_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
)) {
48 list
.push_back(url_entry
);
53 base::DictionaryValue
* ParseDistributionPreferences(
54 const std::string
& json_data
) {
55 JSONStringValueSerializer
json(json_data
);
57 scoped_ptr
<base::Value
> root(json
.Deserialize(NULL
, &error
));
59 LOG(WARNING
) << "Failed to parse master prefs file: " << error
;
62 if (!root
->IsType(base::Value::TYPE_DICTIONARY
)) {
63 LOG(WARNING
) << "Failed to parse master prefs file: "
64 << "Root item must be a dictionary.";
67 return static_cast<base::DictionaryValue
*>(root
.release());
74 MasterPreferences::MasterPreferences() : distribution_(NULL
),
75 preferences_read_from_file_(false),
77 chrome_app_launcher_(false),
79 multi_install_(false) {
80 InitializeFromCommandLine(*CommandLine::ForCurrentProcess());
83 MasterPreferences::MasterPreferences(const CommandLine
& cmd_line
)
84 : distribution_(NULL
),
85 preferences_read_from_file_(false),
87 chrome_app_launcher_(false),
89 multi_install_(false) {
90 InitializeFromCommandLine(cmd_line
);
93 MasterPreferences::MasterPreferences(const base::FilePath
& prefs_path
)
94 : distribution_(NULL
),
95 preferences_read_from_file_(false),
97 chrome_app_launcher_(false),
99 multi_install_(false) {
100 std::string json_data
;
101 // Failure to read the file is ignored as |json_data| will be the empty string
102 // and the remainder of this MasterPreferences object should still be
103 // initialized as best as possible.
104 if (base::PathExists(prefs_path
) &&
105 !file_util::ReadFileToString(prefs_path
, &json_data
)) {
106 LOG(ERROR
) << "Failed to read preferences from " << prefs_path
.value();
108 if (InitializeFromString(json_data
))
109 preferences_read_from_file_
= true;
112 MasterPreferences::MasterPreferences(const std::string
& prefs
)
113 : distribution_(NULL
),
114 preferences_read_from_file_(false),
116 chrome_app_launcher_(false),
117 chrome_frame_(false),
118 multi_install_(false) {
119 InitializeFromString(prefs
);
122 MasterPreferences::~MasterPreferences() {
125 void MasterPreferences::InitializeFromCommandLine(const CommandLine
& cmd_line
) {
127 if (cmd_line
.HasSwitch(installer::switches::kInstallerData
)) {
128 base::FilePath
prefs_path(cmd_line
.GetSwitchValuePath(
129 installer::switches::kInstallerData
));
130 this->MasterPreferences::MasterPreferences(prefs_path
);
132 master_dictionary_
.reset(new base::DictionaryValue());
135 DCHECK(master_dictionary_
.get());
137 // A simple map from command line switches to equivalent switches in the
138 // distribution dictionary. Currently all switches added will be set to
140 static const struct CmdLineSwitchToDistributionSwitch
{
141 const char* cmd_line_switch
;
142 const char* distribution_switch
;
143 } translate_switches
[] = {
144 { installer::switches::kAutoLaunchChrome
,
145 installer::master_preferences::kAutoLaunchChrome
},
146 { installer::switches::kChromeAppHostDeprecated
,
147 installer::master_preferences::kChromeAppHostDeprecated
},
148 { installer::switches::kChromeAppLauncher
,
149 installer::master_preferences::kChromeAppLauncher
},
150 { installer::switches::kChrome
,
151 installer::master_preferences::kChrome
},
152 { installer::switches::kChromeFrame
,
153 installer::master_preferences::kChromeFrame
},
154 { installer::switches::kChromeFrameReadyMode
,
155 installer::master_preferences::kChromeFrameReadyMode
},
156 { installer::switches::kDisableLogging
,
157 installer::master_preferences::kDisableLogging
},
158 { installer::switches::kMsi
,
159 installer::master_preferences::kMsi
},
160 { installer::switches::kMultiInstall
,
161 installer::master_preferences::kMultiInstall
},
162 { installer::switches::kDoNotRegisterForUpdateLaunch
,
163 installer::master_preferences::kDoNotRegisterForUpdateLaunch
},
164 { installer::switches::kDoNotLaunchChrome
,
165 installer::master_preferences::kDoNotLaunchChrome
},
166 { installer::switches::kMakeChromeDefault
,
167 installer::master_preferences::kMakeChromeDefault
},
168 { installer::switches::kSystemLevel
,
169 installer::master_preferences::kSystemLevel
},
170 { installer::switches::kVerboseLogging
,
171 installer::master_preferences::kVerboseLogging
},
174 std::string
name(installer::master_preferences::kDistroDict
);
175 for (int i
= 0; i
< arraysize(translate_switches
); ++i
) {
176 if (cmd_line
.HasSwitch(translate_switches
[i
].cmd_line_switch
)) {
177 name
.assign(installer::master_preferences::kDistroDict
);
178 name
.append(".").append(translate_switches
[i
].distribution_switch
);
179 master_dictionary_
->SetBoolean(name
, true);
183 // See if the log file path was specified on the command line.
184 std::wstring
str_value(cmd_line
.GetSwitchValueNative(
185 installer::switches::kLogFile
));
186 if (!str_value
.empty()) {
187 name
.assign(installer::master_preferences::kDistroDict
);
188 name
.append(".").append(installer::master_preferences::kLogFile
);
189 master_dictionary_
->SetString(name
, str_value
);
192 // Handle the special case of --system-level being implied by the presence of
193 // the kGoogleUpdateIsMachineEnvVar environment variable.
194 scoped_ptr
<base::Environment
> env(base::Environment::Create());
196 std::string is_machine_var
;
197 env
->GetVar(env_vars::kGoogleUpdateIsMachineEnvVar
, &is_machine_var
);
198 if (!is_machine_var
.empty() && is_machine_var
[0] == '1') {
199 VLOG(1) << "Taking system-level from environment.";
200 name
.assign(installer::master_preferences::kDistroDict
);
201 name
.append(".").append(installer::master_preferences::kSystemLevel
);
202 master_dictionary_
->SetBoolean(name
, true);
206 // Cache a pointer to the distribution dictionary. Ignore errors if any.
207 master_dictionary_
->GetDictionary(installer::master_preferences::kDistroDict
,
210 InitializeProductFlags();
214 bool MasterPreferences::InitializeFromString(const std::string
& json_data
) {
215 if (!json_data
.empty())
216 master_dictionary_
.reset(ParseDistributionPreferences(json_data
));
218 bool data_is_valid
= true;
219 if (!master_dictionary_
.get()) {
220 master_dictionary_
.reset(new base::DictionaryValue());
221 data_is_valid
= false;
223 // Cache a pointer to the distribution dictionary.
224 master_dictionary_
->GetDictionary(
225 installer::master_preferences::kDistroDict
, &distribution_
);
228 InitializeProductFlags();
229 EnforceLegacyPreferences();
230 return data_is_valid
;
233 void MasterPreferences::InitializeProductFlags() {
234 // Make sure we start out with the correct defaults.
235 multi_install_
= false;
236 chrome_frame_
= false;
237 chrome_app_launcher_
= false;
240 GetBool(installer::master_preferences::kMultiInstall
, &multi_install_
);
241 GetBool(installer::master_preferences::kChromeFrame
, &chrome_frame_
);
243 GetBool(installer::master_preferences::kChromeAppLauncher
,
244 &chrome_app_launcher_
);
246 // The deprecated switch --app-host behaves like --app-launcher.
247 bool chrome_app_host
= false;
248 GetBool(installer::master_preferences::kChromeAppHostDeprecated
,
250 chrome_app_launcher_
= chrome_app_launcher_
|| chrome_app_host
;
252 // When multi-install is specified, the checks are pretty simple (in theory):
253 // In order to be installed/uninstalled, each product must have its switch
254 // present on the command line.
255 // Before multi-install was introduced however, we only supported installing
256 // two products, Chrome and Chrome Frame. For the time being we need to
257 // continue to support this mode where multi-install is not set.
258 // So, when multi-install is not set, we continue to support mutually
259 // exclusive installation of Chrome and Chrome Frame.
260 if (multi_install_
) {
261 if (!GetBool(installer::master_preferences::kChrome
, &chrome_
))
264 // If chrome-frame is on the command line however, we only install CF.
265 chrome_
= !chrome_frame_
;
269 void MasterPreferences::EnforceLegacyPreferences() {
270 // If create_all_shortcuts was explicitly set to false, set
271 // do_not_create_(desktop|quick_launch)_shortcut to true.
272 bool create_all_shortcuts
= true;
273 GetBool(installer::master_preferences::kCreateAllShortcuts
,
274 &create_all_shortcuts
);
275 if (!create_all_shortcuts
) {
276 distribution_
->SetBoolean(
277 installer::master_preferences::kDoNotCreateDesktopShortcut
, true);
278 distribution_
->SetBoolean(
279 installer::master_preferences::kDoNotCreateQuickLaunchShortcut
, true);
283 bool MasterPreferences::GetBool(const std::string
& name
, bool* value
) const {
286 ret
= distribution_
->GetBoolean(name
, value
);
290 bool MasterPreferences::GetInt(const std::string
& name
, int* value
) const {
293 ret
= distribution_
->GetInteger(name
, value
);
297 bool MasterPreferences::GetString(const std::string
& name
,
298 std::string
* value
) const {
301 ret
= (distribution_
->GetString(name
, value
) && !value
->empty());
305 std::vector
<std::string
> MasterPreferences::GetFirstRunTabs() const {
306 return GetNamedList(kFirstRunTabs
, master_dictionary_
.get());
309 bool MasterPreferences::GetExtensionsBlock(
310 base::DictionaryValue
** extensions
) const {
311 return master_dictionary_
->GetDictionary(
312 master_preferences::kExtensionsBlock
, extensions
);
315 std::string
MasterPreferences::GetVariationsSeed() const {
316 std::string variations_seed
;
317 master_dictionary_
->GetString(prefs::kVariationsSeed
, &variations_seed
);
318 return variations_seed
;
322 const MasterPreferences
& MasterPreferences::ForCurrentProcess() {
323 return g_master_preferences
.Get();
326 } // namespace installer