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 bool ProductState::Initialize(bool system_install
,
29 BrowserDistribution::Type type
) {
30 return Initialize(system_install
,
31 BrowserDistribution::GetSpecificDistribution(type
));
34 // Initializes |commands| from the "Commands" subkey of |version_key|.
35 // Returns false if there is no "Commands" subkey or on error.
37 bool ProductState::InitializeCommands(const base::win::RegKey
& version_key
,
38 AppCommands
* commands
) {
39 static const DWORD kAccess
=
40 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
| KEY_WOW64_32KEY
;
41 base::win::RegKey commands_key
;
43 if (commands_key
.Open(version_key
.Handle(), google_update::kRegCommandsKey
,
44 kAccess
) == ERROR_SUCCESS
)
45 return commands
->Initialize(commands_key
, KEY_WOW64_32KEY
);
49 bool ProductState::Initialize(bool system_install
,
50 BrowserDistribution
* distribution
) {
51 static const DWORD kAccess
= KEY_QUERY_VALUE
| KEY_WOW64_32KEY
;
52 const std::wstring
version_key(distribution
->GetVersionKey());
53 const std::wstring
state_key(distribution
->GetStateKey());
54 const HKEY root_key
= system_install
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
55 base::win::RegKey key
;
60 // Read from the Clients key.
61 if (key
.Open(root_key
, version_key
.c_str(), kAccess
) == ERROR_SUCCESS
) {
62 base::string16 version_str
;
63 if (key
.ReadValue(google_update::kRegVersionField
,
64 &version_str
) == ERROR_SUCCESS
) {
65 version_
.reset(new Version(base::UTF16ToASCII(version_str
)));
66 if (!version_
->IsValid())
70 // Attempt to read the other values even if the "pv" version value was
71 // absent. Note that ProductState instances containing these values will
72 // only be accessible via InstallationState::GetNonVersionedProductState.
73 if (key
.ReadValue(google_update::kRegOldVersionField
,
74 &version_str
) == ERROR_SUCCESS
) {
75 old_version_
.reset(new Version(base::UTF16ToASCII(version_str
)));
76 if (!old_version_
->IsValid())
80 key
.ReadValue(google_update::kRegRenameCmdField
, &rename_cmd_
);
81 if (!InitializeCommands(key
, &commands_
))
85 // Read from the ClientState key.
86 if (key
.Open(root_key
, state_key
.c_str(), kAccess
) == ERROR_SUCCESS
) {
87 std::wstring setup_path
;
88 std::wstring uninstall_arguments
;
89 // "ap" will be absent if not managed by Google Update.
90 channel_
.Initialize(key
);
92 // Read in the brand code, it may be absent
93 key
.ReadValue(google_update::kRegBrandField
, &brand_
);
95 // "UninstallString" will be absent for the multi-installer package.
96 key
.ReadValue(kUninstallStringField
, &setup_path
);
97 // "UninstallArguments" will be absent for the multi-installer package.
98 key
.ReadValue(kUninstallArgumentsField
, &uninstall_arguments
);
99 InstallUtil::MakeUninstallCommand(setup_path
, uninstall_arguments
,
100 &uninstall_command_
);
102 // "usagestats" may be absent, 0 (false), or 1 (true). On the chance that
103 // different values are permitted in the future, we'll simply hold whatever
105 has_usagestats_
= (key
.ReadValueDW(google_update::kRegUsageStatsField
,
106 &usagestats_
) == ERROR_SUCCESS
);
107 // "oeminstall" may be present with any value or absent.
108 has_oem_install_
= (key
.ReadValue(google_update::kRegOemInstallField
,
109 &oem_install_
) == ERROR_SUCCESS
);
110 // "eulaaccepted" may be absent, 0 or 1.
111 has_eula_accepted_
= (key
.ReadValueDW(google_update::kRegEULAAceptedField
,
112 &eula_accepted_
) == ERROR_SUCCESS
);
113 // "msi" may be absent, 0 or 1
115 msi_
= (key
.ReadValueDW(google_update::kRegMSIField
,
116 &dw_value
) == ERROR_SUCCESS
) && (dw_value
!= 0);
117 // Multi-install is implied or is derived from the command-line.
118 if (distribution
->GetType() == BrowserDistribution::CHROME_BINARIES
)
119 multi_install_
= true;
121 multi_install_
= uninstall_command_
.HasSwitch(switches::kMultiInstall
);
124 // Read from the ClientStateMedium key. Values here override those in
126 if (system_install
&&
127 key
.Open(root_key
, distribution
->GetStateMediumKey().c_str(), kAccess
) ==
129 DWORD dword_value
= 0;
131 if (key
.ReadValueDW(google_update::kRegUsageStatsField
,
132 &dword_value
) == ERROR_SUCCESS
) {
133 has_usagestats_
= true;
134 usagestats_
= dword_value
;
137 if (key
.ReadValueDW(google_update::kRegEULAAceptedField
,
138 &dword_value
) == ERROR_SUCCESS
) {
139 has_eula_accepted_
= true;
140 eula_accepted_
= dword_value
;
144 return version_
.get() != NULL
;
147 base::FilePath
ProductState::GetSetupPath() const {
148 return uninstall_command_
.GetProgram();
151 const Version
& ProductState::version() const {
152 DCHECK(version_
.get() != NULL
);
156 ProductState
& ProductState::CopyFrom(const ProductState
& other
) {
157 channel_
.set_value(other
.channel_
.value());
158 version_
.reset(other
.version_
.get() ? new Version(*other
.version_
) : NULL
);
160 other
.old_version_
.get() ? new Version(*other
.old_version_
) : NULL
);
161 brand_
= other
.brand_
;
162 rename_cmd_
= other
.rename_cmd_
;
163 uninstall_command_
= other
.uninstall_command_
;
164 oem_install_
= other
.oem_install_
;
165 commands_
.CopyFrom(other
.commands_
);
166 eula_accepted_
= other
.eula_accepted_
;
167 usagestats_
= other
.usagestats_
;
169 multi_install_
= other
.multi_install_
;
170 has_eula_accepted_
= other
.has_eula_accepted_
;
171 has_oem_install_
= other
.has_oem_install_
;
172 has_usagestats_
= other
.has_usagestats_
;
177 void ProductState::Clear() {
178 channel_
.set_value(std::wstring());
180 old_version_
.reset();
183 oem_install_
.clear();
184 uninstall_command_
= base::CommandLine(base::CommandLine::NO_PROGRAM
);
189 multi_install_
= false;
190 has_eula_accepted_
= false;
191 has_oem_install_
= false;
192 has_usagestats_
= false;
195 bool ProductState::GetEulaAccepted(DWORD
* eula_accepted
) const {
196 DCHECK(eula_accepted
);
197 if (!has_eula_accepted_
)
199 *eula_accepted
= eula_accepted_
;
203 bool ProductState::GetOemInstall(std::wstring
* oem_install
) const {
205 if (!has_oem_install_
)
207 *oem_install
= oem_install_
;
211 bool ProductState::GetUsageStats(DWORD
* usagestats
) const {
213 if (!has_usagestats_
)
215 *usagestats
= usagestats_
;
219 InstallationState::InstallationState() {
223 int InstallationState::IndexFromDistType(BrowserDistribution::Type type
) {
224 COMPILE_ASSERT(BrowserDistribution::CHROME_BROWSER
== CHROME_BROWSER_INDEX
,
225 unexpected_chrome_browser_distribution_value_
);
226 COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME
== CHROME_FRAME_INDEX
,
227 unexpected_chrome_frame_distribution_value_
);
228 COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES
== CHROME_BINARIES_INDEX
,
229 unexpected_chrome_frame_distribution_value_
);
230 DCHECK(type
== BrowserDistribution::CHROME_BROWSER
||
231 type
== BrowserDistribution::CHROME_FRAME
||
232 type
== BrowserDistribution::CHROME_BINARIES
);
236 void InstallationState::Initialize() {
237 BrowserDistribution
* distribution
;
239 distribution
= BrowserDistribution::GetSpecificDistribution(
240 BrowserDistribution::CHROME_BROWSER
);
241 user_products_
[CHROME_BROWSER_INDEX
].Initialize(false, distribution
);
242 system_products_
[CHROME_BROWSER_INDEX
].Initialize(true, distribution
);
244 distribution
= BrowserDistribution::GetSpecificDistribution(
245 BrowserDistribution::CHROME_FRAME
);
246 user_products_
[CHROME_FRAME_INDEX
].Initialize(false, distribution
);
247 system_products_
[CHROME_FRAME_INDEX
].Initialize(true, distribution
);
249 distribution
= BrowserDistribution::GetSpecificDistribution(
250 BrowserDistribution::CHROME_BINARIES
);
251 user_products_
[CHROME_BINARIES_INDEX
].Initialize(false, distribution
);
252 system_products_
[CHROME_BINARIES_INDEX
].Initialize(true, distribution
);
255 const ProductState
* InstallationState::GetNonVersionedProductState(
257 BrowserDistribution::Type type
) const {
258 const ProductState
& product_state
= (system_install
? system_products_
:
259 user_products_
)[IndexFromDistType(type
)];
260 return &product_state
;
263 const ProductState
* InstallationState::GetProductState(
265 BrowserDistribution::Type type
) const {
266 const ProductState
* product_state
=
267 GetNonVersionedProductState(system_install
, type
);
268 return product_state
->version_
.get() == NULL
? NULL
: product_state
;
270 } // namespace installer