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/version.h"
10 #include "base/win/registry.h"
11 #include "chrome/installer/util/google_update_constants.h"
12 #include "chrome/installer/util/install_util.h"
16 ProductState::ProductState()
17 : uninstall_command_(CommandLine::NO_PROGRAM
),
21 multi_install_(false),
22 has_eula_accepted_(false),
23 has_oem_install_(false),
24 has_usagestats_(false) {
27 bool ProductState::Initialize(bool system_install
,
28 BrowserDistribution::Type type
) {
29 return Initialize(system_install
,
30 BrowserDistribution::GetSpecificDistribution(type
));
33 // Initializes |commands| from the "Commands" subkey of |version_key|.
34 // Returns false if there is no "Commands" subkey or on error.
36 bool ProductState::InitializeCommands(const base::win::RegKey
& version_key
,
37 AppCommands
* commands
) {
38 static const DWORD kAccess
= KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
;
39 base::win::RegKey commands_key
;
41 if (commands_key
.Open(version_key
.Handle(), google_update::kRegCommandsKey
,
42 kAccess
) == ERROR_SUCCESS
)
43 return commands
->Initialize(commands_key
);
47 bool ProductState::Initialize(bool system_install
,
48 BrowserDistribution
* distribution
) {
49 const std::wstring
version_key(distribution
->GetVersionKey());
50 const std::wstring
state_key(distribution
->GetStateKey());
51 const HKEY root_key
= system_install
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
52 base::win::RegKey key
;
57 // Read from the Clients key.
58 if (key
.Open(root_key
, version_key
.c_str(),
59 KEY_QUERY_VALUE
) == ERROR_SUCCESS
) {
60 std::wstring version_str
;
61 if (key
.ReadValue(google_update::kRegVersionField
,
62 &version_str
) == ERROR_SUCCESS
) {
63 version_
.reset(new Version(WideToASCII(version_str
)));
64 if (!version_
->IsValid())
68 // Attempt to read the other values even if the "pv" version value was
69 // absent. Note that ProductState instances containing these values will
70 // only be accessible via InstallationState::GetNonVersionedProductState.
71 if (key
.ReadValue(google_update::kRegOldVersionField
,
72 &version_str
) == ERROR_SUCCESS
) {
73 old_version_
.reset(new Version(WideToASCII(version_str
)));
74 if (!old_version_
->IsValid())
78 key
.ReadValue(google_update::kRegRenameCmdField
, &rename_cmd_
);
79 if (!InitializeCommands(key
, &commands_
))
83 // Read from the ClientState key.
84 if (key
.Open(root_key
, state_key
.c_str(),
85 KEY_QUERY_VALUE
) == ERROR_SUCCESS
) {
86 std::wstring setup_path
;
87 std::wstring uninstall_arguments
;
88 // "ap" will be absent if not managed by Google Update.
89 channel_
.Initialize(key
);
91 // Read in the brand code, it may be absent
92 key
.ReadValue(google_update::kRegBrandField
, &brand_
);
94 // "UninstallString" will be absent for the multi-installer package.
95 key
.ReadValue(kUninstallStringField
, &setup_path
);
96 // "UninstallArguments" will be absent for the multi-installer package.
97 key
.ReadValue(kUninstallArgumentsField
, &uninstall_arguments
);
98 InstallUtil::MakeUninstallCommand(setup_path
, uninstall_arguments
,
101 // "usagestats" may be absent, 0 (false), or 1 (true). On the chance that
102 // different values are permitted in the future, we'll simply hold whatever
104 has_usagestats_
= (key
.ReadValueDW(google_update::kRegUsageStatsField
,
105 &usagestats_
) == ERROR_SUCCESS
);
106 // "oeminstall" may be present with any value or absent.
107 has_oem_install_
= (key
.ReadValue(google_update::kRegOemInstallField
,
108 &oem_install_
) == ERROR_SUCCESS
);
109 // "eulaaccepted" may be absent, 0 or 1.
110 has_eula_accepted_
= (key
.ReadValueDW(google_update::kRegEULAAceptedField
,
111 &eula_accepted_
) == ERROR_SUCCESS
);
112 // "msi" may be absent, 0 or 1
114 msi_
= (key
.ReadValueDW(google_update::kRegMSIField
,
115 &dw_value
) == ERROR_SUCCESS
) && (dw_value
!= 0);
116 // Multi-install is implied or is derived from the command-line.
117 if (distribution
->GetType() == BrowserDistribution::CHROME_BINARIES
)
118 multi_install_
= true;
120 multi_install_
= uninstall_command_
.HasSwitch(switches::kMultiInstall
);
123 // Read from the ClientStateMedium key. Values here override those in
125 if (system_install
&&
126 key
.Open(root_key
, distribution
->GetStateMediumKey().c_str(),
127 KEY_QUERY_VALUE
) == ERROR_SUCCESS
) {
128 DWORD dword_value
= 0;
130 if (key
.ReadValueDW(google_update::kRegUsageStatsField
,
131 &dword_value
) == ERROR_SUCCESS
) {
132 has_usagestats_
= true;
133 usagestats_
= dword_value
;
136 if (key
.ReadValueDW(google_update::kRegEULAAceptedField
,
137 &dword_value
) == ERROR_SUCCESS
) {
138 has_eula_accepted_
= true;
139 eula_accepted_
= dword_value
;
143 return version_
.get() != NULL
;
146 base::FilePath
ProductState::GetSetupPath() const {
147 return uninstall_command_
.GetProgram();
150 const Version
& ProductState::version() const {
151 DCHECK(version_
.get() != NULL
);
155 ProductState
& ProductState::CopyFrom(const ProductState
& other
) {
156 channel_
.set_value(other
.channel_
.value());
157 version_
.reset(other
.version_
.get() ? new Version(*other
.version_
) : NULL
);
159 other
.old_version_
.get() ? new Version(*other
.old_version_
) : NULL
);
160 brand_
= other
.brand_
;
161 rename_cmd_
= other
.rename_cmd_
;
162 uninstall_command_
= other
.uninstall_command_
;
163 oem_install_
= other
.oem_install_
;
164 commands_
.CopyFrom(other
.commands_
);
165 eula_accepted_
= other
.eula_accepted_
;
166 usagestats_
= other
.usagestats_
;
168 multi_install_
= other
.multi_install_
;
169 has_eula_accepted_
= other
.has_eula_accepted_
;
170 has_oem_install_
= other
.has_oem_install_
;
171 has_usagestats_
= other
.has_usagestats_
;
176 void ProductState::Clear() {
177 channel_
.set_value(std::wstring());
179 old_version_
.reset();
182 oem_install_
.clear();
183 uninstall_command_
= CommandLine(CommandLine::NO_PROGRAM
);
188 multi_install_
= false;
189 has_eula_accepted_
= false;
190 has_oem_install_
= false;
191 has_usagestats_
= false;
194 bool ProductState::GetEulaAccepted(DWORD
* eula_accepted
) const {
195 DCHECK(eula_accepted
);
196 if (!has_eula_accepted_
)
198 *eula_accepted
= eula_accepted_
;
202 bool ProductState::GetOemInstall(std::wstring
* oem_install
) const {
204 if (!has_oem_install_
)
206 *oem_install
= oem_install_
;
210 bool ProductState::GetUsageStats(DWORD
* usagestats
) const {
212 if (!has_usagestats_
)
214 *usagestats
= usagestats_
;
218 InstallationState::InstallationState() {
222 int InstallationState::IndexFromDistType(BrowserDistribution::Type type
) {
223 COMPILE_ASSERT(BrowserDistribution::CHROME_BROWSER
== CHROME_BROWSER_INDEX
,
224 unexpected_chrome_browser_distribution_value_
);
225 COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME
== CHROME_FRAME_INDEX
,
226 unexpected_chrome_frame_distribution_value_
);
227 COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES
== CHROME_BINARIES_INDEX
,
228 unexpected_chrome_frame_distribution_value_
);
229 COMPILE_ASSERT(BrowserDistribution::CHROME_APP_HOST
== CHROME_APP_HOST_INDEX
,
230 unexpected_chrome_frame_distribution_value_
);
231 DCHECK(type
== BrowserDistribution::CHROME_BROWSER
||
232 type
== BrowserDistribution::CHROME_FRAME
||
233 type
== BrowserDistribution::CHROME_BINARIES
||
234 type
== BrowserDistribution::CHROME_APP_HOST
);
238 void InstallationState::Initialize() {
239 BrowserDistribution
* distribution
;
241 distribution
= BrowserDistribution::GetSpecificDistribution(
242 BrowserDistribution::CHROME_BROWSER
);
243 user_products_
[CHROME_BROWSER_INDEX
].Initialize(false, distribution
);
244 system_products_
[CHROME_BROWSER_INDEX
].Initialize(true, distribution
);
246 distribution
= BrowserDistribution::GetSpecificDistribution(
247 BrowserDistribution::CHROME_FRAME
);
248 user_products_
[CHROME_FRAME_INDEX
].Initialize(false, distribution
);
249 system_products_
[CHROME_FRAME_INDEX
].Initialize(true, distribution
);
251 distribution
= BrowserDistribution::GetSpecificDistribution(
252 BrowserDistribution::CHROME_BINARIES
);
253 user_products_
[CHROME_BINARIES_INDEX
].Initialize(false, distribution
);
254 system_products_
[CHROME_BINARIES_INDEX
].Initialize(true, distribution
);
256 distribution
= BrowserDistribution::GetSpecificDistribution(
257 BrowserDistribution::CHROME_APP_HOST
);
258 user_products_
[CHROME_APP_HOST_INDEX
].Initialize(false, distribution
);
259 system_products_
[CHROME_APP_HOST_INDEX
].Initialize(true, distribution
);
262 const ProductState
* InstallationState::GetNonVersionedProductState(
264 BrowserDistribution::Type type
) const {
265 const ProductState
& product_state
= (system_install
? system_products_
:
266 user_products_
)[IndexFromDistType(type
)];
267 return &product_state
;
270 const ProductState
* InstallationState::GetProductState(
272 BrowserDistribution::Type type
) const {
273 const ProductState
* product_state
=
274 GetNonVersionedProductState(system_install
, type
);
275 return product_state
->version_
.get() == NULL
? NULL
: product_state
;
277 } // namespace installer