| 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 |