Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(478)

Side by Side Diff: goopdate/install_manager.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « goopdate/install_manager.h ('k') | goopdate/install_manager_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2009-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/goopdate/install_manager.h"
17 #include <vector>
18 #include "omaha/base/debug.h"
19 #include "omaha/base/error.h"
20 #include "omaha/base/logging.h"
21 #include "omaha/base/path.h"
22 #include "omaha/base/safe_format.h"
23 #include "omaha/base/scope_guard.h"
24 #include "omaha/base/synchronized.h"
25 #include "omaha/base/utils.h"
26 #include "omaha/common/config_manager.h"
27 #include "omaha/common/const_cmd_line.h"
28 #include "omaha/common/install_manifest.h"
29 #include "omaha/goopdate/app_manager.h"
30 #include "omaha/goopdate/installer_wrapper.h"
31 #include "omaha/goopdate/model.h"
32 #include "omaha/goopdate/server_resource.h"
33 #include "omaha/goopdate/string_formatter.h"
34
35 namespace omaha {
36
37 namespace {
38
39 // Number of tries when the MSI service is busy.
40 // Updates are silent so we can wait longer.
41 const int kNumMsiAlreadyRunningInteractiveMaxTries = 4; // Up to 35 seconds.
42 const int kNumMsiAlreadyRunningSilentMaxTries = 7; // Up to 6.25 minutes.
43
44 // TODO(omaha): there can be more install actions for each install event.
45 bool GetInstallActionForEvent(
46 const std::vector<xml::InstallAction>& install_actions,
47 xml::InstallAction::InstallEvent install_event,
48 xml::InstallAction* action) {
49 ASSERT1(action);
50
51 for (size_t i = 0; i < install_actions.size(); ++i) {
52 if (install_actions[i].install_event == install_event) {
53 *action = install_actions[i];
54 return true;
55 }
56 }
57
58 return false;
59 }
60
61 } // namespace
62
63 InstallManager::InstallManager(const Lockable* model_lock, bool is_machine)
64 : model_lock_(model_lock),
65 is_machine_(is_machine) {
66 CORE_LOG(L3, (_T("[InstallManager::InstallManager][%d]"), is_machine_));
67
68 install_working_dir_ =
69 is_machine ?
70 ConfigManager::Instance()->GetMachineInstallWorkingDir() :
71 ConfigManager::Instance()->GetUserInstallWorkingDir();
72 CORE_LOG(L3, (_T("[install_working_dir][%s]"), install_working_dir()));
73
74 VERIFY1(SUCCEEDED(DeleteDirectory(install_working_dir_)));
75 VERIFY1(SUCCEEDED(CreateDir(install_working_dir_, NULL)));
76
77 installer_wrapper_.reset(new InstallerWrapper(is_machine_));
78 }
79
80 InstallManager::~InstallManager() {
81 CORE_LOG(L3, (_T("[InstallManager::~InstallManager]")));
82 }
83
84 HRESULT InstallManager::Initialize() {
85 return installer_wrapper_->Initialize();
86 }
87
88 CString InstallManager::install_working_dir() const {
89 __mutexScope(model_lock_);
90 return install_working_dir_;
91 }
92
93 // For each app, set the state to STATE_INSTALLING, install it, and update the
94 // state of the model after it completes.
95 void InstallManager::InstallApp(App* app, const CString& dir) {
96 CORE_LOG(L3, (_T("[InstallManager::InstallApp][0x%p]"), app));
97 ASSERT1(app);
98
99 const ConfigManager& cm = *ConfigManager::Instance();
100 // TODO(omaha): Since we don't currently have is_manual, check the least
101 // restrictive case of true. It would be nice if we had is_manual. We'll see.
102 ASSERT(SUCCEEDED(app->CheckGroupPolicy()),
103 (_T("Installing/updating app for which this is not allowed.")));
104 ASSERT(app->is_eula_accepted() ||
105 app->is_install() && app->app_bundle()->is_offline_install(),
106 (_T("update/online install of app for which EULA is not accepted.")));
107
108 // TODO(omaha3): This needs to be set/passed per app/bundle.
109 const int priority = app->app_bundle()->priority();
110 const int num_tries = (priority < INSTALL_PRIORITY_HIGH) ?
111 kNumMsiAlreadyRunningSilentMaxTries :
112 kNumMsiAlreadyRunningInteractiveMaxTries;
113 installer_wrapper_->set_num_tries_when_msi_busy(num_tries);
114
115 AppVersion* next_version = app->next_version();
116 ASSERT1(app->app_bundle()->is_machine() == is_machine_);
117
118 const CString current_version_string = app->current_version()->version();
119
120 HANDLE primary_token(app->app_bundle()->primary_token());
121
122 HRESULT hr = InstallApp(is_machine_,
123 primary_token,
124 current_version_string,
125 *model_lock_,
126 installer_wrapper_.get(),
127 app,
128 dir);
129 if (FAILED(hr)) {
130 CORE_LOG(LE, (_T("[InstallApp failed][0x%p][0x%08x]"), app, hr));
131 }
132
133 app->LogTextAppendFormat(_T("Install result=0x%08x"), hr);
134
135 ASSERT1(FAILED(hr) == (app->state() == STATE_ERROR));
136 }
137
138 HRESULT InstallManager::InstallApp(bool is_machine,
139 HANDLE user_token,
140 const CString& existing_version,
141 const Lockable& model_lock,
142 InstallerWrapper* installer_wrapper,
143 App* app,
144 const CString& dir) {
145 UNREFERENCED_PARAMETER(is_machine);
146 ASSERT1(installer_wrapper);
147 ASSERT1(app);
148
149 const bool is_update = app->is_update();
150
151 CString display_name;
152 GUID app_guid = {0};
153 CString installer_path;
154 // TODO(omaha3): Consider generating the installerdata file external to the
155 // InstallerWrapper and just adding the path to the arguments.
156 CString manifest_arguments;
157 CString installer_data;
158 CString expected_version;
159
160 AppManager& app_manager = *AppManager::Instance();
161 __mutexScope(app_manager.GetRegistryStableStateLock());
162
163 // TODO(omaha): If this does not get much simpler, extract method.
164 AppVersion& next_version = *(app->next_version());
165 ASSERT1(app->app_bundle()->is_machine() == is_machine);
166
167 CString language = app->app_bundle()->display_language();
168
169 // TODO(omaha): review the need for locking below.
170 __mutexBlock(model_lock) {
171 app->Installing();
172
173 app_guid = app->app_guid();
174
175 // The first package is always the Package Manager for the app.
176 // TODO(omaha3): Use program_to_run here instead of the installer_path. This
177 // will introduce complexity such as having to find the full path and
178 // handling the case where the file is not in the cache.
179 ASSERT1(next_version.GetNumberOfPackages() > 0);
180 if (next_version.GetNumberOfPackages() <= 0) {
181 HRESULT hr = E_FAIL;
182 const CString message = InstallerWrapper::GetMessageForError(hr,
183 CString(),
184 language);
185 app->Error(ErrorContext(hr), message);
186 return hr;
187 }
188 const Package& package_manager = *(next_version.GetPackage(0));
189 installer_path = ConcatenatePath(dir, package_manager.filename());
190
191 xml::InstallAction action;
192 const bool is_event_found = GetInstallActionForEvent(
193 next_version.install_manifest()->install_actions,
194 is_update ? xml::InstallAction::kUpdate : xml::InstallAction::kInstall,
195 &action);
196 ASSERT1(is_event_found);
197 if (is_event_found) {
198 manifest_arguments = action.program_arguments;
199
200 // If this is an Omaha self-update, append a switch to the argument list
201 // to set the session ID.
202 if (is_update && ::IsEqualGUID(app_guid, kGoopdateGuid)) {
203 SafeCStringAppendFormat(&manifest_arguments, _T(" /%s \"%s\""),
204 kCmdLineSessionId,
205 app->app_bundle()->session_id());
206 }
207 }
208
209 installer_data = app->GetInstallData();
210
211 expected_version = next_version.install_manifest()->version;
212
213 // TODO(omaha3): All app key registry writes and reads must be protected by
214 // some lock to prevent race conditions caused by multiple bundles
215 // installing the same app. This includes while writing the pre-install
216 // data, while the installer is running, and while checking application
217 // registration (basically the rest of this method). An app-specific lock
218 // similar to the app install lock in Omaha 2 seems to be appropriate.
219 // (Omaha 2 only took that during install - not updates - though.)
220 // Some app installers may also check the state of other apps (i.e. to check
221 // for version compatibility). Should we protect this case as well?
222 // Is it safest to use the installer lock for this? What is the performance
223 // impact. If we do use the installer lock, it would need to be acquired
224 // here instead of in the InstallerWrapper::InstallApp path.
225 if (!is_update) {
226 HRESULT hr = app_manager.WritePreInstallData(*app);
227 if (FAILED(hr)) {
228 CORE_LOG(LE, (_T("[AppManager::WritePreInstallData failed][0x%08x]")));
229 const CString message =
230 InstallerWrapper::GetMessageForError(hr, CString(), language);
231 app->Error(ErrorContext(hr), message);
232 return hr;
233 }
234 }
235 }
236
237 OPT_LOG(L1, (_T("[Installing][%s][%s][%s][%s][%s]"),
238 app->display_name(),
239 GuidToString(app_guid),
240 installer_path,
241 manifest_arguments,
242 installer_data));
243
244 InstallerResultInfo result_info;
245
246 HRESULT hr = installer_wrapper->InstallApp(user_token,
247 app_guid,
248 installer_path,
249 manifest_arguments,
250 installer_data,
251 language,
252 &result_info);
253
254 OPT_LOG(L1, (_T("[InstallApp returned][0x%x][%s][type:%d][code: %d][%s][%s]"),
255 hr, GuidToString(app_guid), result_info.type, result_info.code,
256 result_info.text, result_info.post_install_launch_command_line));
257
258 __mutexScope(model_lock);
259
260 if (SUCCEEDED(hr)) {
261 ASSERT1(result_info.type == INSTALLER_RESULT_SUCCESS);
262 // Skip checking application registration for Omaha self-updates because the
263 // installer has not completed.
264 if (!::IsEqualGUID(kGoopdateGuid, app_guid)) {
265 hr = app_manager.ReadInstallerRegistrationValues(app);
266 if (SUCCEEDED(hr)) {
267 hr = installer_wrapper->CheckApplicationRegistration(
268 app_guid,
269 next_version.version(),
270 expected_version,
271 existing_version,
272 is_update);
273 }
274 }
275 } else {
276 ASSERT1(result_info.type != INSTALLER_RESULT_SUCCESS);
277 ASSERT1(!result_info.text.IsEmpty() ||
278 result_info.type == INSTALLER_RESULT_UNKNOWN);
279 }
280
281 if (FAILED(hr)) {
282 // If we failed the install job and the product wasn't registered, it's safe
283 // to delete the ClientState key. We need to remove it because it contains
284 // data like "ap", browsertype, language, etc. that need to be cleaned up in
285 // case user tries to install again in the future.
286 if (!is_update && !app_manager.IsAppRegistered(app->app_guid())) {
287 app_manager.RemoveClientState(app->app_guid());
288 }
289
290 if (hr == GOOPDATEINSTALL_E_INSTALLER_FAILED) {
291 ASSERT1(!result_info.text.IsEmpty());
292 app->ReportInstallerComplete(result_info);
293 } else {
294 // TODO(omaha3): If we end up having the installer filename above, pass it
295 // instead of installer_path.
296 const CString message = InstallerWrapper::GetMessageForError(
297 hr, installer_path, language);
298 app->Error(ErrorContext(hr), message);
299 }
300
301 return hr;
302 }
303
304 PopulateSuccessfulInstallResultInfo(app, &result_info);
305
306 app->ReportInstallerComplete(result_info);
307 return S_OK;
308 }
309
310 // Call this function only when installer succeeded.
311 // This function sets the post install action and url based on installer result
312 // info and app manifest. Note that the action may already have been set by
313 // InstallerWrapper::GetInstallerResultHelper() in some cases. This function
314 // only sets the action when necessary.
315 void InstallManager::PopulateSuccessfulInstallResultInfo(
316 const App* app,
317 InstallerResultInfo* result_info) {
318 ASSERT1(result_info);
319 ASSERT1(result_info->type == INSTALLER_RESULT_SUCCESS);
320 ASSERT1(app);
321 ASSERT1(app->next_version()->install_manifest());
322
323 xml::InstallAction action;
324 if (GetInstallActionForEvent(
325 app->next_version()->install_manifest()->install_actions,
326 xml::InstallAction::kPostInstall,
327 &action)) {
328 result_info->post_install_url = action.success_url;
329
330 if (result_info->post_install_launch_command_line.IsEmpty() &&
331 action.success_action == SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD) {
332 CORE_LOG(LW, (_T("[Success action specified launchcmd, but cmd empty]")));
333 }
334
335 if (result_info->post_install_action ==
336 POST_INSTALL_ACTION_LAUNCH_COMMAND &&
337 action.success_action == SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD) {
338 result_info->post_install_action =
339 POST_INSTALL_ACTION_EXIT_SILENTLY_ON_LAUNCH_COMMAND;
340 } else if (result_info->post_install_action ==
341 POST_INSTALL_ACTION_DEFAULT) {
342 if (action.success_action == SUCCESS_ACTION_EXIT_SILENTLY) {
343 result_info->post_install_action = POST_INSTALL_ACTION_EXIT_SILENTLY;
344 } else if (!result_info->post_install_url.IsEmpty()) {
345 result_info->post_install_action = action.terminate_all_browsers ?
346 POST_INSTALL_ACTION_RESTART_ALL_BROWSERS :
347 POST_INSTALL_ACTION_RESTART_BROWSER;
348 }
349 }
350 }
351
352 // Load message based on post install action if not overridden.
353 if (result_info->text.IsEmpty()) {
354 StringFormatter formatter(app->app_bundle()->display_language());
355 VERIFY1(SUCCEEDED(formatter.LoadString(
356 IDS_APPLICATION_INSTALLED_SUCCESSFULLY,
357 &result_info->text)));
358 }
359 }
360
361 } // namespace omaha
OLDNEW
« no previous file with comments | « goopdate/install_manager.h ('k') | goopdate/install_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698