master_preferences.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/string_util.h" 14#include "chrome/installer/util/master_preferences_constants.h" 15#include "chrome/installer/util/util_constants.h" 16#include "googleurl/src/gurl.h" 17 18namespace { 19 20const char kFirstRunTabs[] = "first_run_tabs"; 21 22base::LazyInstance<installer::MasterPreferences> g_master_preferences = 23 LAZY_INSTANCE_INITIALIZER; 24 25bool GetGURLFromValue(const Value* in_value, GURL* out_value) { 26 if (!in_value || !out_value) 27 return false; 28 std::string url; 29 if (!in_value->GetAsString(&url)) 30 return false; 31 GURL gurl(url); 32 *out_value = gurl; 33 return true; 34} 35 36std::vector<GURL> GetNamedList(const char* name, 37 const DictionaryValue* prefs) { 38 std::vector<GURL> list; 39 if (!prefs) 40 return list; 41 const ListValue* value_list = NULL; 42 if (!prefs->GetList(name, &value_list)) 43 return list; 44 for (size_t i = 0; i < value_list->GetSize(); ++i) { 45 const Value* entry; 46 GURL gurl_entry; 47 if (!value_list->Get(i, &entry) || !GetGURLFromValue(entry, &gurl_entry)) { 48 NOTREACHED(); 49 break; 50 } 51 list.push_back(gurl_entry); 52 } 53 return list; 54} 55 56DictionaryValue* ParseDistributionPreferences(const std::string& json_data) { 57 JSONStringValueSerializer json(json_data); 58 std::string error; 59 scoped_ptr<Value> root(json.Deserialize(NULL, &error)); 60 if (!root.get()) { 61 LOG(WARNING) << "Failed to parse master prefs file: " << error; 62 return NULL; 63 } 64 if (!root->IsType(Value::TYPE_DICTIONARY)) { 65 LOG(WARNING) << "Failed to parse master prefs file: " 66 << "Root item must be a dictionary."; 67 return NULL; 68 } 69 return static_cast<DictionaryValue*>(root.release()); 70} 71 72} // namespace 73 74namespace installer { 75 76MasterPreferences::MasterPreferences() : distribution_(NULL), 77 preferences_read_from_file_(false), 78 chrome_(true), 79 chrome_app_host_(false), 80 chrome_frame_(false), 81 multi_install_(false) { 82 InitializeFromCommandLine(*CommandLine::ForCurrentProcess()); 83} 84 85MasterPreferences::MasterPreferences(const CommandLine& cmd_line) 86 : distribution_(NULL), 87 preferences_read_from_file_(false), 88 chrome_(true), 89 chrome_app_host_(false), 90 chrome_frame_(false), 91 multi_install_(false) { 92 InitializeFromCommandLine(cmd_line); 93} 94 95MasterPreferences::MasterPreferences(const FilePath& prefs_path) 96 : distribution_(NULL), 97 preferences_read_from_file_(false), 98 chrome_(true), 99 chrome_app_host_(false), 100 chrome_frame_(false), 101 multi_install_(false) { 102 std::string json_data; 103 // Failure to read the file is ignored as |json_data| will be the empty string 104 // and the remainder of this MasterPreferences objet should still be 105 // initialized as best as possible. 106 if (!file_util::ReadFileToString(prefs_path, &json_data)) { 107 LOG(ERROR) << "Failed to read master_preferences file at " 108 << prefs_path.value() 109 << ". Falling back to default preferences."; 110 } 111 if (InitializeFromString(json_data)) 112 preferences_read_from_file_ = true; 113} 114 115MasterPreferences::MasterPreferences(const std::string& prefs) 116 : distribution_(NULL), preferences_read_from_file_(false), 117 chrome_(true), chrome_app_host_(false), chrome_frame_(false), 118 multi_install_(false) { 119 InitializeFromString(prefs); 120} 121 122MasterPreferences::~MasterPreferences() { 123} 124 125void MasterPreferences::InitializeFromCommandLine(const CommandLine& cmd_line) { 126#if defined(OS_WIN) 127 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { 128 FilePath prefs_path(cmd_line.GetSwitchValuePath( 129 installer::switches::kInstallerData)); 130 this->MasterPreferences::MasterPreferences(prefs_path); 131 } else { 132 master_dictionary_.reset(new DictionaryValue()); 133 } 134 135 DCHECK(master_dictionary_.get()); 136 137 // A simple map from command line switches to equivalent switches in the 138 // distribution dictionary. Currently all switches added will be set to 139 // 'true'. 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::kChromeAppHost, 147 installer::master_preferences::kChromeAppHost }, 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 }, 172 }; 173 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); 180 } 181 } 182 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); 190 } 191 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()); 195 if (env != NULL) { 196 std::string is_machine_var; 197 env->GetVar(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); 203 } 204 } 205 206 // Cache a pointer to the distribution dictionary. Ignore errors if any. 207 master_dictionary_->GetDictionary(installer::master_preferences::kDistroDict, 208 &distribution_); 209 210 InitializeProductFlags(); 211#endif 212} 213 214bool MasterPreferences::InitializeFromString(const std::string& json_data) { 215 bool data_is_valid = true; 216 master_dictionary_.reset(ParseDistributionPreferences(json_data)); 217 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 bool pref_chrome_app_host = false; 234 bool pref_chrome_app_launcher = false; 235 // Make sure we start out with the correct defaults. 236 multi_install_ = false; 237 chrome_frame_ = false; 238 chrome_app_host_ = false; 239 chrome_ = true; 240 241 GetBool(installer::master_preferences::kMultiInstall, &multi_install_); 242 GetBool(installer::master_preferences::kChromeFrame, &chrome_frame_); 243 244 GetBool(installer::master_preferences::kChromeAppHost, &pref_chrome_app_host); 245 GetBool(installer::master_preferences::kChromeAppLauncher, 246 &pref_chrome_app_launcher); 247 chrome_app_host_ = pref_chrome_app_host || pref_chrome_app_launcher; 248 249 // When multi-install is specified, the checks are pretty simple (in theory): 250 // In order to be installed/uninstalled, each product must have its switch 251 // present on the command line. 252 // Before multi-install was introduced however, we only supported installing 253 // two products, Chrome and Chrome Frame. For the time being we need to 254 // continue to support this mode where multi-install is not set. 255 // So, when multi-install is not set, we continue to support mutually 256 // exclusive installation of Chrome and Chrome Frame. 257 if (multi_install_) { 258 if (!GetBool(installer::master_preferences::kChrome, &chrome_)) 259 chrome_ = false; 260 } else { 261 // If chrome-frame is on the command line however, we only install CF. 262 chrome_ = !chrome_frame_; 263 } 264} 265 266void MasterPreferences::EnforceLegacyPreferences() { 267 // If create_all_shortcuts was explicitly set to false, set 268 // do_not_create_(desktop|quick_launch)_shortcut to true. 269 bool create_all_shortcuts = true; 270 GetBool(installer::master_preferences::kCreateAllShortcuts, 271 &create_all_shortcuts); 272 if (!create_all_shortcuts) { 273 distribution_->SetBoolean( 274 installer::master_preferences::kDoNotCreateDesktopShortcut, true); 275 distribution_->SetBoolean( 276 installer::master_preferences::kDoNotCreateQuickLaunchShortcut, true); 277 } 278} 279 280bool MasterPreferences::GetBool(const std::string& name, bool* value) const { 281 bool ret = false; 282 if (distribution_) 283 ret = distribution_->GetBoolean(name, value); 284 return ret; 285} 286 287bool MasterPreferences::GetInt(const std::string& name, int* value) const { 288 bool ret = false; 289 if (distribution_) 290 ret = distribution_->GetInteger(name, value); 291 return ret; 292} 293 294bool MasterPreferences::GetString(const std::string& name, 295 std::string* value) const { 296 bool ret = false; 297 if (distribution_) 298 ret = (distribution_->GetString(name, value) && !value->empty()); 299 return ret; 300} 301 302std::vector<GURL> MasterPreferences::GetFirstRunTabs() const { 303 return GetNamedList(kFirstRunTabs, master_dictionary_.get()); 304} 305 306bool MasterPreferences::GetExtensionsBlock(DictionaryValue** extensions) const { 307 return master_dictionary_->GetDictionary( 308 master_preferences::kExtensionsBlock, extensions); 309} 310 311// static 312const MasterPreferences& MasterPreferences::ForCurrentProcess() { 313 return g_master_preferences.Get(); 314} 315} // installer_util 316