master_preferences.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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. 4 5#include "chrome/installer/util/master_preferences.h" 6 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" 18 19namespace { 20 21const char kFirstRunTabs[] = "first_run_tabs"; 22 23base::LazyInstance<installer::MasterPreferences> g_master_preferences = 24 LAZY_INSTANCE_INITIALIZER; 25 26bool GetURLFromValue(const Value* in_value, std::string* out_value) { 27 return in_value && out_value && in_value->GetAsString(out_value); 28} 29 30std::vector<std::string> GetNamedList(const char* name, 31 const DictionaryValue* prefs) { 32 std::vector<std::string> list; 33 if (!prefs) 34 return list; 35 36 const ListValue* value_list = NULL; 37 if (!prefs->GetList(name, &value_list)) 38 return list; 39 40 list.reserve(value_list->GetSize()); 41 for (size_t i = 0; i < value_list->GetSize(); ++i) { 42 const Value* entry; 43 std::string url_entry; 44 if (!value_list->Get(i, &entry) || !GetURLFromValue(entry, &url_entry)) { 45 NOTREACHED(); 46 break; 47 } 48 list.push_back(url_entry); 49 } 50 return list; 51} 52 53DictionaryValue* ParseDistributionPreferences(const std::string& json_data) { 54 JSONStringValueSerializer json(json_data); 55 std::string error; 56 scoped_ptr<Value> root(json.Deserialize(NULL, &error)); 57 if (!root.get()) { 58 LOG(WARNING) << "Failed to parse master prefs file: " << error; 59 return NULL; 60 } 61 if (!root->IsType(Value::TYPE_DICTIONARY)) { 62 LOG(WARNING) << "Failed to parse master prefs file: " 63 << "Root item must be a dictionary."; 64 return NULL; 65 } 66 return static_cast<DictionaryValue*>(root.release()); 67} 68 69} // namespace 70 71namespace installer { 72 73MasterPreferences::MasterPreferences() : distribution_(NULL), 74 preferences_read_from_file_(false), 75 chrome_(true), 76 chrome_app_launcher_(false), 77 chrome_frame_(false), 78 multi_install_(false) { 79 InitializeFromCommandLine(*CommandLine::ForCurrentProcess()); 80} 81 82MasterPreferences::MasterPreferences(const CommandLine& cmd_line) 83 : distribution_(NULL), 84 preferences_read_from_file_(false), 85 chrome_(true), 86 chrome_app_launcher_(false), 87 chrome_frame_(false), 88 multi_install_(false) { 89 InitializeFromCommandLine(cmd_line); 90} 91 92MasterPreferences::MasterPreferences(const base::FilePath& prefs_path) 93 : distribution_(NULL), 94 preferences_read_from_file_(false), 95 chrome_(true), 96 chrome_app_launcher_(false), 97 chrome_frame_(false), 98 multi_install_(false) { 99 std::string json_data; 100 // Failure to read the file is ignored as |json_data| will be the empty string 101 // and the remainder of this MasterPreferences object should still be 102 // initialized as best as possible. 103 if (file_util::PathExists(prefs_path) && 104 !file_util::ReadFileToString(prefs_path, &json_data)) { 105 LOG(ERROR) << "Failed to read preferences from " << prefs_path.value(); 106 } 107 if (InitializeFromString(json_data)) 108 preferences_read_from_file_ = true; 109} 110 111MasterPreferences::MasterPreferences(const std::string& prefs) 112 : distribution_(NULL), 113 preferences_read_from_file_(false), 114 chrome_(true), 115 chrome_app_launcher_(false), 116 chrome_frame_(false), 117 multi_install_(false) { 118 InitializeFromString(prefs); 119} 120 121MasterPreferences::~MasterPreferences() { 122} 123 124void MasterPreferences::InitializeFromCommandLine(const CommandLine& cmd_line) { 125#if defined(OS_WIN) 126 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { 127 base::FilePath prefs_path(cmd_line.GetSwitchValuePath( 128 installer::switches::kInstallerData)); 129 this->MasterPreferences::MasterPreferences(prefs_path); 130 } else { 131 master_dictionary_.reset(new DictionaryValue()); 132 } 133 134 DCHECK(master_dictionary_.get()); 135 136 // A simple map from command line switches to equivalent switches in the 137 // distribution dictionary. Currently all switches added will be set to 138 // 'true'. 139 static const struct CmdLineSwitchToDistributionSwitch { 140 const char* cmd_line_switch; 141 const char* distribution_switch; 142 } translate_switches[] = { 143 { installer::switches::kAutoLaunchChrome, 144 installer::master_preferences::kAutoLaunchChrome }, 145 { installer::switches::kChromeAppHostDeprecated, 146 installer::master_preferences::kChromeAppHostDeprecated }, 147 { installer::switches::kChromeAppLauncher, 148 installer::master_preferences::kChromeAppLauncher }, 149 { installer::switches::kChrome, 150 installer::master_preferences::kChrome }, 151 { installer::switches::kChromeFrame, 152 installer::master_preferences::kChromeFrame }, 153 { installer::switches::kChromeFrameReadyMode, 154 installer::master_preferences::kChromeFrameReadyMode }, 155 { installer::switches::kDisableLogging, 156 installer::master_preferences::kDisableLogging }, 157 { installer::switches::kMsi, 158 installer::master_preferences::kMsi }, 159 { installer::switches::kMultiInstall, 160 installer::master_preferences::kMultiInstall }, 161 { installer::switches::kDoNotRegisterForUpdateLaunch, 162 installer::master_preferences::kDoNotRegisterForUpdateLaunch }, 163 { installer::switches::kDoNotLaunchChrome, 164 installer::master_preferences::kDoNotLaunchChrome }, 165 { installer::switches::kMakeChromeDefault, 166 installer::master_preferences::kMakeChromeDefault }, 167 { installer::switches::kSystemLevel, 168 installer::master_preferences::kSystemLevel }, 169 { installer::switches::kVerboseLogging, 170 installer::master_preferences::kVerboseLogging }, 171 }; 172 173 std::string name(installer::master_preferences::kDistroDict); 174 for (int i = 0; i < arraysize(translate_switches); ++i) { 175 if (cmd_line.HasSwitch(translate_switches[i].cmd_line_switch)) { 176 name.assign(installer::master_preferences::kDistroDict); 177 name.append(".").append(translate_switches[i].distribution_switch); 178 master_dictionary_->SetBoolean(name, true); 179 } 180 } 181 182 // See if the log file path was specified on the command line. 183 std::wstring str_value(cmd_line.GetSwitchValueNative( 184 installer::switches::kLogFile)); 185 if (!str_value.empty()) { 186 name.assign(installer::master_preferences::kDistroDict); 187 name.append(".").append(installer::master_preferences::kLogFile); 188 master_dictionary_->SetString(name, str_value); 189 } 190 191 // Handle the special case of --system-level being implied by the presence of 192 // the kGoogleUpdateIsMachineEnvVar environment variable. 193 scoped_ptr<base::Environment> env(base::Environment::Create()); 194 if (env != NULL) { 195 std::string is_machine_var; 196 env->GetVar(env_vars::kGoogleUpdateIsMachineEnvVar, &is_machine_var); 197 if (!is_machine_var.empty() && is_machine_var[0] == '1') { 198 VLOG(1) << "Taking system-level from environment."; 199 name.assign(installer::master_preferences::kDistroDict); 200 name.append(".").append(installer::master_preferences::kSystemLevel); 201 master_dictionary_->SetBoolean(name, true); 202 } 203 } 204 205 // Cache a pointer to the distribution dictionary. Ignore errors if any. 206 master_dictionary_->GetDictionary(installer::master_preferences::kDistroDict, 207 &distribution_); 208 209 InitializeProductFlags(); 210#endif 211} 212 213bool MasterPreferences::InitializeFromString(const std::string& json_data) { 214 if (!json_data.empty()) 215 master_dictionary_.reset(ParseDistributionPreferences(json_data)); 216 217 bool data_is_valid = true; 218 if (!master_dictionary_.get()) { 219 master_dictionary_.reset(new DictionaryValue()); 220 data_is_valid = false; 221 } else { 222 // Cache a pointer to the distribution dictionary. 223 master_dictionary_->GetDictionary( 224 installer::master_preferences::kDistroDict, &distribution_); 225 } 226 227 InitializeProductFlags(); 228 EnforceLegacyPreferences(); 229 return data_is_valid; 230} 231 232void MasterPreferences::InitializeProductFlags() { 233 // Make sure we start out with the correct defaults. 234 multi_install_ = false; 235 chrome_frame_ = false; 236 chrome_app_launcher_ = false; 237 chrome_ = true; 238 239 GetBool(installer::master_preferences::kMultiInstall, &multi_install_); 240 GetBool(installer::master_preferences::kChromeFrame, &chrome_frame_); 241 242 GetBool(installer::master_preferences::kChromeAppLauncher, 243 &chrome_app_launcher_); 244 245 // The deprecated switch --app-host behaves like --app-launcher. 246 bool chrome_app_host = false; 247 GetBool(installer::master_preferences::kChromeAppHostDeprecated, 248 &chrome_app_host); 249 chrome_app_launcher_ = chrome_app_launcher_ || chrome_app_host; 250 251 // When multi-install is specified, the checks are pretty simple (in theory): 252 // In order to be installed/uninstalled, each product must have its switch 253 // present on the command line. 254 // Before multi-install was introduced however, we only supported installing 255 // two products, Chrome and Chrome Frame. For the time being we need to 256 // continue to support this mode where multi-install is not set. 257 // So, when multi-install is not set, we continue to support mutually 258 // exclusive installation of Chrome and Chrome Frame. 259 if (multi_install_) { 260 if (!GetBool(installer::master_preferences::kChrome, &chrome_)) 261 chrome_ = false; 262 } else { 263 // If chrome-frame is on the command line however, we only install CF. 264 chrome_ = !chrome_frame_; 265 } 266} 267 268void MasterPreferences::EnforceLegacyPreferences() { 269 // If create_all_shortcuts was explicitly set to false, set 270 // do_not_create_(desktop|quick_launch)_shortcut to true. 271 bool create_all_shortcuts = true; 272 GetBool(installer::master_preferences::kCreateAllShortcuts, 273 &create_all_shortcuts); 274 if (!create_all_shortcuts) { 275 distribution_->SetBoolean( 276 installer::master_preferences::kDoNotCreateDesktopShortcut, true); 277 distribution_->SetBoolean( 278 installer::master_preferences::kDoNotCreateQuickLaunchShortcut, true); 279 } 280} 281 282bool MasterPreferences::GetBool(const std::string& name, bool* value) const { 283 bool ret = false; 284 if (distribution_) 285 ret = distribution_->GetBoolean(name, value); 286 return ret; 287} 288 289bool MasterPreferences::GetInt(const std::string& name, int* value) const { 290 bool ret = false; 291 if (distribution_) 292 ret = distribution_->GetInteger(name, value); 293 return ret; 294} 295 296bool MasterPreferences::GetString(const std::string& name, 297 std::string* value) const { 298 bool ret = false; 299 if (distribution_) 300 ret = (distribution_->GetString(name, value) && !value->empty()); 301 return ret; 302} 303 304std::vector<std::string> MasterPreferences::GetFirstRunTabs() const { 305 return GetNamedList(kFirstRunTabs, master_dictionary_.get()); 306} 307 308bool MasterPreferences::GetExtensionsBlock(DictionaryValue** extensions) const { 309 return master_dictionary_->GetDictionary( 310 master_preferences::kExtensionsBlock, extensions); 311} 312 313std::string MasterPreferences::GetVariationsSeed() const { 314 std::string variations_seed; 315 master_dictionary_->GetString(prefs::kVariationsSeed, &variations_seed); 316 return variations_seed; 317} 318 319// static 320const MasterPreferences& MasterPreferences::ForCurrentProcess() { 321 return g_master_preferences.Get(); 322} 323 324} // namespace installer 325