OLD | NEW |
| (Empty) |
1 // Copyright 2007-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 // TODO(omaha): Dig out the RefHolder in scope_guard.h so we can use const | |
17 // references instead pointers. This TODO was added for some code that no longer | |
18 // exists, but it is still a good idea. | |
19 | |
20 #include "omaha/client/ua.h" | |
21 #include "omaha/client/ua_internal.h" | |
22 #include <windows.h> | |
23 #include <atlstr.h> | |
24 #include "omaha/base/const_object_names.h" | |
25 #include "omaha/base/debug.h" | |
26 #include "omaha/base/error.h" | |
27 #include "omaha/base/logging.h" | |
28 #include "omaha/base/program_instance.h" | |
29 #include "omaha/base/safe_format.h" | |
30 #include "omaha/base/scoped_ptr_address.h" | |
31 #include "omaha/base/utils.h" | |
32 #include "omaha/client/install_apps.h" | |
33 #include "omaha/client/install_self.h" | |
34 #include "omaha/client/client_metrics.h" | |
35 #include "omaha/common/app_registry_utils.h" | |
36 #include "omaha/common/config_manager.h" | |
37 #include "omaha/common/const_goopdate.h" | |
38 #include "omaha/common/event_logger.h" | |
39 #include "omaha/common/goopdate_utils.h" | |
40 #include "omaha/common/ping.h" | |
41 | |
42 // Design Notes: | |
43 // Following are the mutexes that are taken by the worker | |
44 // 1. SingleUpdateWorker. Only taken by the update worker. | |
45 // 2. SingleInstallWorker. This is application specific. Only taken by the | |
46 // install worker and for the specific application. | |
47 // 3. Before install, the install manager takes the global install lock. | |
48 // 4. A key thing to add to this code is after taking the install lock, | |
49 // to validate that the version of the applicaion that is present in the | |
50 // registry is the same as that we queried for. The reason to do this | |
51 // is to ensure that there are no races between update and install workers. | |
52 // 5. Termination of the worker happens because of four reasons: | |
53 // a. Shutdown event - Only applicable to the update worker. When this event | |
54 // is signalled, the main thread comes out of the wait. It then tries to | |
55 // destroy the contained thread pool, which causes a timed wait for the | |
56 // worker thread. The worker thread is notified by setting a | |
57 // cancelled flag on the worker. | |
58 // b. Install completes, user closes UI - Only applicable for the | |
59 // interactive installs. In this case the main thread comes out of | |
60 // the message loop and deletes the thread pool. The delete happens | |
61 // immediately, since the worker is doing nothing. | |
62 // c. User cancels install - Only applicable in case if interactive installs. | |
63 // The main thread sets the cancelled flag on the workerjob and comes out | |
64 // of the message loop. It then tries to delete the thread pool, causing | |
65 // a timed wait. The worker job queries the cancelled flag periodically | |
66 // and quits as soon as possible. | |
67 // d. The update worker completes - In this case we do not run on a thread | |
68 // pool. | |
69 | |
70 namespace omaha { | |
71 | |
72 namespace { | |
73 | |
74 void WriteUpdateAppsStartEvent(bool is_machine) { | |
75 GoogleUpdateLogEvent update_event(EVENTLOG_INFORMATION_TYPE, | |
76 kWorkerStartEventId, | |
77 is_machine); | |
78 update_event.set_event_desc(_T("Update Apps start")); | |
79 | |
80 ConfigManager& cm = *ConfigManager::Instance(); | |
81 | |
82 int au_check_period_ms = cm.GetAutoUpdateTimerIntervalMs(); | |
83 int time_since_last_checked_sec = cm.GetTimeSinceLastCheckedSec(is_machine); | |
84 bool is_period_overridden = false; | |
85 int last_check_period_ms = cm.GetLastCheckPeriodSec(&is_period_overridden); | |
86 | |
87 CString event_text; | |
88 SafeCStringFormat(&event_text, | |
89 _T("AuCheckPeriodMs=%d, TimeSinceLastCheckedSec=%d, ") | |
90 _T("LastCheckedPeriodSec=%d"), | |
91 au_check_period_ms, time_since_last_checked_sec, last_check_period_ms); | |
92 | |
93 update_event.set_event_text(event_text); | |
94 update_event.WriteEvent(); | |
95 } | |
96 | |
97 } // namespace | |
98 | |
99 namespace internal { | |
100 | |
101 // Ensures there is only one instance of /ua per session per Omaha instance. | |
102 bool EnsureSingleUAProcess(bool is_machine, ProgramInstance** instance) { | |
103 ASSERT1(instance); | |
104 ASSERT1(!*instance); | |
105 NamedObjectAttributes single_ua_process_attr; | |
106 GetNamedObjectAttributes(kUpdateAppsSingleInstance, | |
107 is_machine, | |
108 &single_ua_process_attr); | |
109 | |
110 *instance = new ProgramInstance(single_ua_process_attr.name); | |
111 return !(*instance)->EnsureSingleInstance(); | |
112 } | |
113 | |
114 } // namespace internal | |
115 | |
116 // Always checks whether it should uninstall. | |
117 // Checks for updates of all apps if the required period has elapsed, it is | |
118 // being run on-demand, or an uninstall seems necessary. It will also send a | |
119 // self-update failure ping in these cases if necessary. | |
120 // | |
121 // Calls UpdateAllApps(), which will call IAppBundle::updateAllApps(), even in | |
122 // cases where an uninstall seems necessary. This allows an uninstall ping to | |
123 // be sent for any uninstalled apps. Because the COM server does not know about | |
124 // uninstall, the COM server will also do a final update check for the remaining | |
125 // app - should be Omaha. It's possible that this update check could result in | |
126 // a self-update, in which case the uninstall may fail and be delayed an hour. | |
127 // See http://b/2814535. | |
128 // Since all pings are sent by the AppBundle destructor, if the bundle has | |
129 // normal or uninstall pings need, the network request could delay the exiting | |
130 // of the COM server beyond the point where this client releases the IAppBundle. | |
131 // and launches /uninstall. This could cause uninstall to fail if the ping takes | |
132 // a long time. | |
133 // | |
134 // TODO(omaha): Test this method as it is very important. | |
135 HRESULT UpdateApps(bool is_machine, | |
136 bool is_interactive, | |
137 bool is_on_demand, | |
138 const CString& install_source, | |
139 const CString& display_language, | |
140 bool* has_ui_been_displayed) { | |
141 CORE_LOG(L1, (_T("[UpdateApps]"))); | |
142 ASSERT1(has_ui_been_displayed); | |
143 | |
144 WriteUpdateAppsStartEvent(is_machine); | |
145 | |
146 scoped_ptr<ProgramInstance> single_ua_process; | |
147 | |
148 if (internal::EnsureSingleUAProcess(is_machine, address(single_ua_process))) { | |
149 OPT_LOG(L1, (_T("[Another worker is already running. Exiting.]"))); | |
150 ++metric_client_another_update_in_progress; | |
151 return GOOPDATE_E_UA_ALREADY_RUNNING; | |
152 } | |
153 | |
154 if (ConfigManager::Instance()->CanUseNetwork(is_machine)) { | |
155 VERIFY1(SUCCEEDED(Ping::SendPersistedPings(is_machine))); | |
156 } | |
157 | |
158 // Generate a session ID for network accesses. | |
159 CString session_id; | |
160 VERIFY1(SUCCEEDED(GetGuid(&session_id))); | |
161 | |
162 // A tentative uninstall check is done here. There are stronger checks, | |
163 // protected by locks, which are done by Setup. | |
164 size_t num_clients(0); | |
165 const bool is_uninstall = | |
166 FAILED(app_registry_utils::GetNumClients(is_machine, &num_clients)) || | |
167 num_clients <= 1; | |
168 CORE_LOG(L4, (_T("[UpdateApps][registered apps: %u]"), num_clients)); | |
169 | |
170 const bool should_check_for_updates = | |
171 goopdate_utils::ShouldCheckForUpdates(is_machine); | |
172 | |
173 if (is_uninstall) { | |
174 // TODO(omaha3): The interactive /ua process will not exit without user | |
175 // interaction. This could cause the uninstall to fail. | |
176 CORE_LOG(L1, (_T("[/ua launching /uninstall]"))); | |
177 return goopdate_utils::LaunchUninstallProcess(is_machine); | |
178 } | |
179 | |
180 if (!(is_on_demand || should_check_for_updates)) { | |
181 OPT_LOG(L1, (_T("[Update check not needed at this time]"))); | |
182 return S_OK; | |
183 } | |
184 | |
185 HRESULT hr = UpdateAllApps(is_machine, | |
186 is_interactive, | |
187 install_source, | |
188 display_language, | |
189 session_id, | |
190 has_ui_been_displayed); | |
191 if (FAILED(hr)) { | |
192 CORE_LOG(LW, (_T("[UpdateAllApps failed][0x%08x]"), hr)); | |
193 } | |
194 return hr; | |
195 } | |
196 | |
197 } // namespace omaha | |
OLD | NEW |