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/installation_state.h"
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/version.h"
11 #include "base/win/registry.h"
12 #include "chrome/installer/util/google_update_constants.h"
13 #include "chrome/installer/util/install_util.h"
17 ProductState::ProductState()
18 : uninstall_command_(base::CommandLine::NO_PROGRAM
),
22 multi_install_(false),
23 has_eula_accepted_(false),
24 has_oem_install_(false),
25 has_usagestats_(false) {
28 ProductState::~ProductState() {
31 bool ProductState::Initialize(bool system_install
,
32 BrowserDistribution::Type type
) {
33 return Initialize(system_install
,
34 BrowserDistribution::GetSpecificDistribution(type
));
37 // Initializes |commands| from the "Commands" subkey of |version_key|.
38 // Returns false if there is no "Commands" subkey or on error.
40 bool ProductState::InitializeCommands(const base::win::RegKey
& version_key
,
41 AppCommands
* commands
) {
42 static const DWORD kAccess
=
43 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
| KEY_WOW64_32KEY
;
44 base::win::RegKey commands_key
;
46 if (commands_key
.Open(version_key
.Handle(), google_update::kRegCommandsKey
,
47 kAccess
) == ERROR_SUCCESS
)
48 return commands
->Initialize(commands_key
, KEY_WOW64_32KEY
);
52 bool ProductState::Initialize(bool system_install
,
53 BrowserDistribution
* distribution
) {
54 static const DWORD kAccess
= KEY_QUERY_VALUE
| KEY_WOW64_32KEY
;
55 const std::wstring
version_key(distribution
->GetVersionKey());
56 const std::wstring
state_key(distribution
->GetStateKey());
57 const HKEY root_key
= system_install
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
58 base::win::RegKey key
;
63 // Read from the Clients key.
64 if (key
.Open(root_key
, version_key
.c_str(), kAccess
) == ERROR_SUCCESS
) {
65 base::string16 version_str
;
66 if (key
.ReadValue(google_update::kRegVersionField
,
67 &version_str
) == ERROR_SUCCESS
) {
68 version_
.reset(new Version(base::UTF16ToASCII(version_str
)));
69 if (!version_
->IsValid())
73 // Attempt to read the other values even if the "pv" version value was
74 // absent. Note that ProductState instances containing these values will
75 // only be accessible via InstallationState::GetNonVersionedProductState.
76 if (key
.ReadValue(google_update::kRegOldVersionField
,
77 &version_str
) == ERROR_SUCCESS
) {
78 old_version_
.reset(new Version(base::UTF16ToASCII(version_str
)));
79 if (!old_version_
->IsValid())
83 key
.ReadValue(google_update::kRegRenameCmdField
, &rename_cmd_
);
84 if (!InitializeCommands(key
, &commands_
))
88 // Read from the ClientState key.
89 if (key
.Open(root_key
, state_key
.c_str(), kAccess
) == ERROR_SUCCESS
) {
90 std::wstring setup_path
;
91 std::wstring uninstall_arguments
;
92 // "ap" will be absent if not managed by Google Update.
93 channel_
.Initialize(key
);
95 // Read in the brand code, it may be absent
96 key
.ReadValue(google_update::kRegBrandField
, &brand_
);
98 // "UninstallString" will be absent for the multi-installer package.
99 key
.ReadValue(kUninstallStringField
, &setup_path
);
100 // "UninstallArguments" will be absent for the multi-installer package.
101 key
.ReadValue(kUninstallArgumentsField
, &uninstall_arguments
);
102 InstallUtil::ComposeCommandLine(setup_path
, uninstall_arguments
,
103 &uninstall_command_
);
105 // "usagestats" may be absent, 0 (false), or 1 (true). On the chance that
106 // different values are permitted in the future, we'll simply hold whatever
108 has_usagestats_
= (key
.ReadValueDW(google_update::kRegUsageStatsField
,
109 &usagestats_
) == ERROR_SUCCESS
);
110 // "oeminstall" may be present with any value or absent.
111 has_oem_install_
= (key
.ReadValue(google_update::kRegOemInstallField
,
112 &oem_install_
) == ERROR_SUCCESS
);
113 // "eulaaccepted" may be absent, 0 or 1.
114 has_eula_accepted_
= (key
.ReadValueDW(google_update::kRegEULAAceptedField
,
115 &eula_accepted_
) == ERROR_SUCCESS
);
116 // "msi" may be absent, 0 or 1
118 msi_
= (key
.ReadValueDW(google_update::kRegMSIField
,
119 &dw_value
) == ERROR_SUCCESS
) && (dw_value
!= 0);
120 // Multi-install is implied or is derived from the command-line.
121 if (distribution
->GetType() == BrowserDistribution::CHROME_BINARIES
)
122 multi_install_
= true;
124 multi_install_
= uninstall_command_
.HasSwitch(switches::kMultiInstall
);
127 // Read from the ClientStateMedium key. Values here override those in
129 if (system_install
&&
130 key
.Open(root_key
, distribution
->GetStateMediumKey().c_str(), kAccess
) ==
132 DWORD dword_value
= 0;
134 if (key
.ReadValueDW(google_update::kRegUsageStatsField
,
135 &dword_value
) == ERROR_SUCCESS
) {
136 has_usagestats_
= true;
137 usagestats_
= dword_value
;
140 if (key
.ReadValueDW(google_update::kRegEULAAceptedField
,
141 &dword_value
) == ERROR_SUCCESS
) {
142 has_eula_accepted_
= true;
143 eula_accepted_
= dword_value
;
147 return version_
.get() != NULL
;
150 base::FilePath
ProductState::GetSetupPath() const {
151 return uninstall_command_
.GetProgram();
154 const Version
& ProductState::version() const {
155 DCHECK(version_
.get() != NULL
);
159 ProductState
& ProductState::CopyFrom(const ProductState
& other
) {
160 channel_
.set_value(other
.channel_
.value());
161 version_
.reset(other
.version_
.get() ? new Version(*other
.version_
) : NULL
);
163 other
.old_version_
.get() ? new Version(*other
.old_version_
) : NULL
);
164 brand_
= other
.brand_
;
165 rename_cmd_
= other
.rename_cmd_
;
166 uninstall_command_
= other
.uninstall_command_
;
167 oem_install_
= other
.oem_install_
;
168 commands_
.CopyFrom(other
.commands_
);
169 eula_accepted_
= other
.eula_accepted_
;
170 usagestats_
= other
.usagestats_
;
172 multi_install_
= other
.multi_install_
;
173 has_eula_accepted_
= other
.has_eula_accepted_
;
174 has_oem_install_
= other
.has_oem_install_
;
175 has_usagestats_
= other
.has_usagestats_
;
180 void ProductState::Clear() {
181 channel_
.set_value(std::wstring());
183 old_version_
.reset();
186 oem_install_
.clear();
187 uninstall_command_
= base::CommandLine(base::CommandLine::NO_PROGRAM
);
192 multi_install_
= false;
193 has_eula_accepted_
= false;
194 has_oem_install_
= false;
195 has_usagestats_
= false;
198 bool ProductState::GetEulaAccepted(DWORD
* eula_accepted
) const {
199 DCHECK(eula_accepted
);
200 if (!has_eula_accepted_
)
202 *eula_accepted
= eula_accepted_
;
206 bool ProductState::GetOemInstall(std::wstring
* oem_install
) const {
208 if (!has_oem_install_
)
210 *oem_install
= oem_install_
;
214 bool ProductState::GetUsageStats(DWORD
* usagestats
) const {
216 if (!has_usagestats_
)
218 *usagestats
= usagestats_
;
222 InstallationState::InstallationState() {
226 int InstallationState::IndexFromDistType(BrowserDistribution::Type type
) {
227 COMPILE_ASSERT(BrowserDistribution::CHROME_BROWSER
== CHROME_BROWSER_INDEX
,
228 unexpected_chrome_browser_distribution_value_
);
229 COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME
== CHROME_FRAME_INDEX
,
230 unexpected_chrome_frame_distribution_value_
);
231 COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES
== CHROME_BINARIES_INDEX
,
232 unexpected_chrome_frame_distribution_value_
);
233 DCHECK(type
== BrowserDistribution::CHROME_BROWSER
||
234 type
== BrowserDistribution::CHROME_FRAME
||
235 type
== BrowserDistribution::CHROME_BINARIES
);
239 void InstallationState::Initialize() {
240 BrowserDistribution
* distribution
;
242 distribution
= BrowserDistribution::GetSpecificDistribution(
243 BrowserDistribution::CHROME_BROWSER
);
244 user_products_
[CHROME_BROWSER_INDEX
].Initialize(false, distribution
);
245 system_products_
[CHROME_BROWSER_INDEX
].Initialize(true, distribution
);
247 distribution
= BrowserDistribution::GetSpecificDistribution(
248 BrowserDistribution::CHROME_FRAME
);
249 user_products_
[CHROME_FRAME_INDEX
].Initialize(false, distribution
);
250 system_products_
[CHROME_FRAME_INDEX
].Initialize(true, distribution
);
252 distribution
= BrowserDistribution::GetSpecificDistribution(
253 BrowserDistribution::CHROME_BINARIES
);
254 user_products_
[CHROME_BINARIES_INDEX
].Initialize(false, distribution
);
255 system_products_
[CHROME_BINARIES_INDEX
].Initialize(true, distribution
);
258 const ProductState
* InstallationState::GetNonVersionedProductState(
260 BrowserDistribution::Type type
) const {
261 const ProductState
& product_state
= (system_install
? system_products_
:
262 user_products_
)[IndexFromDistType(type
)];
263 return &product_state
;
266 const ProductState
* InstallationState::GetProductState(
268 BrowserDistribution::Type type
) const {
269 const ProductState
* product_state
=
270 GetNonVersionedProductState(system_install
, type
);
271 return product_state
->version_
.get() == NULL
? NULL
: product_state
;
273 } // namespace installer