| 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 // Core is the long-lived Omaha process. It runs one instance for the | |
| 17 // machine and one instance for each user session, including console and TS | |
| 18 // sessions. | |
| 19 // If the same user is logged in multiple times, only one core process will | |
| 20 // be running. | |
| 21 | |
| 22 #include "omaha/core/core.h" | |
| 23 #include <lmsname.h> | |
| 24 #include <atlsecurity.h> | |
| 25 #include <algorithm> | |
| 26 #include <map> | |
| 27 #include <string> | |
| 28 #include <vector> | |
| 29 #include "omaha/base/app_util.h" | |
| 30 #include "omaha/base/const_object_names.h" | |
| 31 #include "omaha/base/debug.h" | |
| 32 #include "omaha/base/error.h" | |
| 33 #include "omaha/base/logging.h" | |
| 34 #include "omaha/base/module_utils.h" | |
| 35 #include "omaha/base/path.h" | |
| 36 #include "omaha/base/program_instance.h" | |
| 37 #include "omaha/base/reactor.h" | |
| 38 #include "omaha/base/reg_key.h" | |
| 39 #include "omaha/base/service_utils.h" | |
| 40 #include "omaha/base/shutdown_handler.h" | |
| 41 #include "omaha/base/system.h" | |
| 42 #include "omaha/base/time.h" | |
| 43 #include "omaha/base/user_info.h" | |
| 44 #include "omaha/base/utils.h" | |
| 45 #include "omaha/base/vistautil.h" | |
| 46 #include "omaha/common/app_registry_utils.h" | |
| 47 #include "omaha/common/const_cmd_line.h" | |
| 48 #include "omaha/common/command_line_builder.h" | |
| 49 #include "omaha/common/config_manager.h" | |
| 50 #include "omaha/common/oem_install_utils.h" | |
| 51 #include "omaha/common/scheduled_task_utils.h" | |
| 52 #include "omaha/common/stats_uploader.h" | |
| 53 #include "omaha/core/core_metrics.h" | |
| 54 #include "omaha/core/scheduler.h" | |
| 55 #include "omaha/core/system_monitor.h" | |
| 56 #include "omaha/goopdate/resource_manager.h" | |
| 57 #include "omaha/goopdate/worker.h" | |
| 58 #include "omaha/net/network_config.h" | |
| 59 #include "omaha/setup/setup_service.h" | |
| 60 | |
| 61 namespace omaha { | |
| 62 | |
| 63 Core::Core() | |
| 64 : is_system_(false), | |
| 65 is_crash_handler_enabled_(false), | |
| 66 main_thread_id_(0) { | |
| 67 CORE_LOG(L1, (_T("[Core::Core]"))); | |
| 68 } | |
| 69 | |
| 70 Core::~Core() { | |
| 71 CORE_LOG(L1, (_T("[Core::~Core]"))); | |
| 72 scheduler_.reset(NULL); | |
| 73 system_monitor_.reset(NULL); | |
| 74 } | |
| 75 | |
| 76 // We always return S_OK, because the core can be invoked from the system | |
| 77 // scheduler, and the scheduler does not work well if the process returns | |
| 78 // an error. We do not depend on the return values from the Core elsewhere. | |
| 79 HRESULT Core::Main(bool is_system, bool is_crash_handler_enabled) { | |
| 80 HRESULT hr = DoMain(is_system, is_crash_handler_enabled); | |
| 81 if (FAILED(hr)) { | |
| 82 OPT_LOG(LW, (_T("[Core::DoMain failed][0x%x]"), hr)); | |
| 83 } | |
| 84 | |
| 85 return S_OK; | |
| 86 } | |
| 87 | |
| 88 bool Core::AreScheduledTasksHealthy() const { | |
| 89 if (!ServiceUtils::IsServiceRunning(SERVICE_SCHEDULE)) { | |
| 90 ++metric_core_run_task_scheduler_not_running; | |
| 91 CORE_LOG(LE, (_T("[Task Scheduler Service is not running]"))); | |
| 92 return false; | |
| 93 } | |
| 94 | |
| 95 if (!scheduled_task_utils::IsInstalledGoopdateTaskUA(is_system_)) { | |
| 96 ++metric_core_run_scheduled_task_missing; | |
| 97 CORE_LOG(LE, (_T("[UA Task not installed]"))); | |
| 98 return false; | |
| 99 } | |
| 100 | |
| 101 if (scheduled_task_utils::IsDisabledGoopdateTaskUA(is_system_)) { | |
| 102 ++metric_core_run_scheduled_task_disabled; | |
| 103 CORE_LOG(LE, (_T("[UA Task disabled]"))); | |
| 104 return false; | |
| 105 } | |
| 106 | |
| 107 HRESULT ua_task_last_exit_code = | |
| 108 scheduled_task_utils::GetExitCodeGoopdateTaskUA(is_system_); | |
| 109 | |
| 110 if (ua_task_last_exit_code == SCHED_S_TASK_HAS_NOT_RUN && | |
| 111 !ConfigManager::Is24HoursSinceInstall(is_system_)) { | |
| 112 // Not 24 hours yet since install or update. Let us give the UA task the | |
| 113 // benefit of the doubt, and assume all is well for right now. | |
| 114 CORE_LOG(L3, (_T("[Core::AreScheduledTasksHealthy]") | |
| 115 _T("[Not yet 24 hours since install/update]"))); | |
| 116 ua_task_last_exit_code = S_OK; | |
| 117 } | |
| 118 | |
| 119 metric_core_run_scheduled_task_exit_code = ua_task_last_exit_code; | |
| 120 | |
| 121 if (S_OK != ua_task_last_exit_code) { | |
| 122 CORE_LOG(LE, (_T("[UA Task exit code][0x%x]"), ua_task_last_exit_code)); | |
| 123 return false; | |
| 124 } | |
| 125 | |
| 126 return true; | |
| 127 } | |
| 128 | |
| 129 bool Core::IsCheckingForUpdates() const { | |
| 130 if (!ConfigManager::Is24HoursSinceInstall(is_system_)) { | |
| 131 CORE_LOG(L3, (_T("[Core::IsCheckingForUpdates]") | |
| 132 _T("[Not yet 24 hours since install/update]"))); | |
| 133 return true; | |
| 134 } | |
| 135 | |
| 136 const ConfigManager& cm = *ConfigManager::Instance(); | |
| 137 const int k14DaysSec = 14 * 24 * 60 * 60; | |
| 138 | |
| 139 if (cm.GetTimeSinceLastCheckedSec(is_system_) >= k14DaysSec) { | |
| 140 ++metric_core_run_not_checking_for_updates; | |
| 141 CORE_LOG(LE, (_T("[LastChecked older than 14 days]"))); | |
| 142 return false; | |
| 143 } | |
| 144 | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 // The Core will run all the time under the following conditions: | |
| 149 // | |
| 150 // * the task scheduler is not running, or | |
| 151 // * the UA task is not installed, or | |
| 152 // * the UA task is disabled, or | |
| 153 // * the last exit code for the UA task is non-zero, or | |
| 154 // * LastChecked time is older than 14 days. | |
| 155 // | |
| 156 // Under these conditions, Omaha uses the built-in scheduler hosted by the core | |
| 157 // and it keeps the core running. | |
| 158 bool Core::ShouldRunForever() const { | |
| 159 CORE_LOG(L3, (_T("[Core::ShouldRunForever]"))); | |
| 160 | |
| 161 // The methods are being called individually to enable metrics capture. | |
| 162 bool are_scheduled_tasks_healthy(AreScheduledTasksHealthy()); | |
| 163 bool is_checking_for_updates(IsCheckingForUpdates()); | |
| 164 | |
| 165 bool result = !are_scheduled_tasks_healthy || | |
| 166 !is_checking_for_updates; | |
| 167 CORE_LOG(L1, (_T("[Core::ShouldRunForever][%u]"), result)); | |
| 168 return result; | |
| 169 } | |
| 170 | |
| 171 | |
| 172 HRESULT Core::DoMain(bool is_system, bool is_crash_handler_enabled) { | |
| 173 main_thread_id_ = ::GetCurrentThreadId(); | |
| 174 is_system_ = is_system; | |
| 175 is_crash_handler_enabled_ = is_crash_handler_enabled; | |
| 176 | |
| 177 CORE_LOG(L1, (_T("[is_system_: %d][is_crash_handler_enabled_: %d]"), | |
| 178 is_system_, is_crash_handler_enabled_)); | |
| 179 | |
| 180 const ConfigManager& cm = *ConfigManager::Instance(); | |
| 181 if (oem_install_utils::IsOemInstalling(is_system_)) { | |
| 182 // Exit immediately while an OEM is installing Windows. This prevents cores | |
| 183 // or update workers from being started by the Scheduled Task or other means | |
| 184 // before the system is sealed. | |
| 185 OPT_LOG(L1, (_T("[Exiting because an OEM is installing Windows]"))); | |
| 186 ASSERT1(is_system_); | |
| 187 return S_OK; | |
| 188 } | |
| 189 | |
| 190 // Do a code red check as soon as possible. | |
| 191 StartCodeRed(); | |
| 192 | |
| 193 CORE_LOG(L2, (_T("[IsInternalUser: %d]"), cm.IsInternalUser())); | |
| 194 | |
| 195 NamedObjectAttributes single_core_attr; | |
| 196 GetNamedObjectAttributes(kCoreSingleInstance, is_system_, &single_core_attr); | |
| 197 ProgramInstance instance(single_core_attr.name); | |
| 198 bool is_already_running = !instance.EnsureSingleInstance(); | |
| 199 if (is_already_running) { | |
| 200 OPT_LOG(L1, (_T("[Another core instance is already running]"))); | |
| 201 return S_OK; | |
| 202 } | |
| 203 | |
| 204 // TODO(omaha): the user Omaha core should run at medium integrity level and | |
| 205 // it should deelevate itself if it does not, see bug 1549842. | |
| 206 | |
| 207 // Start the crash handler if necessary. | |
| 208 if (is_crash_handler_enabled_) { | |
| 209 HRESULT hr = StartCrashHandler(); | |
| 210 if (FAILED(hr)) { | |
| 211 OPT_LOG(LW, (_T("[Failed to start crash handler][0x%08x]"), hr)); | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 if (!ShouldRunForever()) { | |
| 216 return S_OK; | |
| 217 } | |
| 218 | |
| 219 // TODO(omaha): Delay starting update worker when run at startup. | |
| 220 StartUpdateWorkerInternal(); | |
| 221 | |
| 222 // Force the main thread to create a message queue so any future WM_QUIT | |
| 223 // message posted by the ShutdownHandler will be received. If the main | |
| 224 // thread does not have a message queue, the message can be lost. | |
| 225 MSG msg = {0}; | |
| 226 ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); | |
| 227 | |
| 228 reactor_.reset(new Reactor); | |
| 229 shutdown_handler_.reset(new ShutdownHandler); | |
| 230 HRESULT hr = shutdown_handler_->Initialize(reactor_.get(), this, is_system_); | |
| 231 if (FAILED(hr)) { | |
| 232 return hr; | |
| 233 } | |
| 234 | |
| 235 scheduler_.reset(new Scheduler(*this)); | |
| 236 hr = scheduler_->Initialize(); | |
| 237 if (FAILED(hr)) { | |
| 238 return hr; | |
| 239 } | |
| 240 | |
| 241 system_monitor_.reset(new SystemMonitor(is_system_)); | |
| 242 VERIFY1(SUCCEEDED(system_monitor_->Initialize(true))); | |
| 243 system_monitor_->set_observer(this); | |
| 244 | |
| 245 // Start processing messages and events from the system. | |
| 246 return DoRun(); | |
| 247 } | |
| 248 | |
| 249 // Signals the core to shutdown. The shutdown method is called by a thread | |
| 250 // running in the thread pool. It posts a WM_QUIT to the main thread, which | |
| 251 // causes it to break out of the message loop. If the message can't be posted, | |
| 252 // it terminates the process unconditionally. | |
| 253 HRESULT Core::Shutdown() { | |
| 254 return ShutdownInternal(); | |
| 255 } | |
| 256 | |
| 257 HRESULT Core::ShutdownInternal() const { | |
| 258 LONG atl_module_count(const_cast<Core*>(this)->GetLockCount()); | |
| 259 if (atl_module_count > 0) { | |
| 260 CORE_LOG(L1, (_T("[Core COM server in use][%d]"), atl_module_count)); | |
| 261 return S_OK; | |
| 262 } | |
| 263 | |
| 264 OPT_LOG(L1, (_T("[Google Update core is shutting down...]"))); | |
| 265 ASSERT1(::GetCurrentThreadId() != main_thread_id_); | |
| 266 if (::PostThreadMessage(main_thread_id_, WM_QUIT, 0, 0)) { | |
| 267 return S_OK; | |
| 268 } | |
| 269 | |
| 270 ASSERT(false, (_T("Failed to post WM_QUIT"))); | |
| 271 uint32 exit_code = static_cast<uint32>(E_ABORT); | |
| 272 VERIFY1(::TerminateProcess(::GetCurrentProcess(), exit_code)); | |
| 273 return S_OK; | |
| 274 } | |
| 275 | |
| 276 void Core::LastCheckedDeleted() { | |
| 277 OPT_LOG(L1, (_T("[Core::LastCheckedDeleted]"))); | |
| 278 VERIFY1(SUCCEEDED(StartUpdateWorker())); | |
| 279 } | |
| 280 | |
| 281 void Core::NoRegisteredClients() { | |
| 282 OPT_LOG(L1, (_T("[Core::NoRegisteredClients]"))); | |
| 283 VERIFY1(SUCCEEDED(StartUpdateWorker())); | |
| 284 } | |
| 285 | |
| 286 HRESULT Core::DoRun() { | |
| 287 OPT_LOG(L1, (_T("[Core::DoRun]"))); | |
| 288 | |
| 289 // Trim the process working set to minimum. It does not need a more complex | |
| 290 // algorithm for now. Likely the working set will increase slightly over time | |
| 291 // as the core is handling events. | |
| 292 VERIFY1(::SetProcessWorkingSetSize(::GetCurrentProcess(), | |
| 293 static_cast<uint32>(-1), | |
| 294 static_cast<uint32>(-1))); | |
| 295 return DoHandleEvents(); | |
| 296 } | |
| 297 | |
| 298 HRESULT Core::DoHandleEvents() { | |
| 299 CORE_LOG(L1, (_T("[Core::DoHandleEvents]"))); | |
| 300 MSG msg = {0}; | |
| 301 int result = 0; | |
| 302 while ((result = ::GetMessage(&msg, 0, 0, 0)) != 0) { | |
| 303 ::DispatchMessage(&msg); | |
| 304 if (result == -1) { | |
| 305 break; | |
| 306 } | |
| 307 } | |
| 308 CORE_LOG(L3, (_T("[GetMessage returned %d]"), result)); | |
| 309 return (result != -1) ? S_OK : HRESULTFromLastError(); | |
| 310 } | |
| 311 | |
| 312 HRESULT Core::StartUpdateWorker() const { | |
| 313 if (!ShouldRunForever()) { | |
| 314 return ShutdownInternal(); | |
| 315 } | |
| 316 | |
| 317 return StartUpdateWorkerInternal(); | |
| 318 } | |
| 319 | |
| 320 HRESULT Core::StartUpdateWorkerInternal() const { | |
| 321 CORE_LOG(L2, (_T("[Core::StartUpdateWorkerInternal]"))); | |
| 322 | |
| 323 CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_system_); | |
| 324 CommandLineBuilder builder(COMMANDLINE_MODE_UA); | |
| 325 builder.set_install_source(kCmdLineInstallSource_Core); | |
| 326 CString cmd_line = builder.GetCommandLineArgs(); | |
| 327 HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line); | |
| 328 if (SUCCEEDED(hr)) { | |
| 329 ++metric_core_worker_succeeded; | |
| 330 } else { | |
| 331 CORE_LOG(LE, (_T("[can't start update worker][0x%08x]"), hr)); | |
| 332 } | |
| 333 ++metric_core_worker_total; | |
| 334 return hr; | |
| 335 } | |
| 336 | |
| 337 HRESULT Core::StartCodeRed() const { | |
| 338 if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueNoCodeRedCheck)) { | |
| 339 CORE_LOG(LW, (_T("[Code Red is disabled for this system]"))); | |
| 340 return E_ABORT; | |
| 341 } | |
| 342 | |
| 343 CORE_LOG(L2, (_T("[Core::StartCodeRed]"))); | |
| 344 | |
| 345 CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_system_); | |
| 346 CommandLineBuilder builder(COMMANDLINE_MODE_CODE_RED_CHECK); | |
| 347 CString cmd_line = builder.GetCommandLineArgs(); | |
| 348 HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line); | |
| 349 if (SUCCEEDED(hr)) { | |
| 350 ++metric_core_cr_succeeded; | |
| 351 } else { | |
| 352 CORE_LOG(LE, (_T("[can't start Code Red worker][0x%08x]"), hr)); | |
| 353 } | |
| 354 ++metric_core_cr_total; | |
| 355 return hr; | |
| 356 } | |
| 357 | |
| 358 HRESULT Core::StartCrashHandler() const { | |
| 359 CORE_LOG(L2, (_T("[Core::StartCrashHandler]"))); | |
| 360 | |
| 361 HRESULT hr = goopdate_utils::StartCrashHandler(is_system_); | |
| 362 if (SUCCEEDED(hr)) { | |
| 363 ++metric_core_start_crash_handler_succeeded; | |
| 364 } else { | |
| 365 CORE_LOG(LE, (_T("[Cannot start Crash Handler][0x%08x]"), hr)); | |
| 366 } | |
| 367 ++metric_core_start_crash_handler_total; | |
| 368 return hr; | |
| 369 } | |
| 370 | |
| 371 void Core::AggregateMetrics() const { | |
| 372 CORE_LOG(L2, (_T("[aggregate core metrics]"))); | |
| 373 CollectMetrics(); | |
| 374 VERIFY1(SUCCEEDED(omaha::AggregateMetrics(is_system_))); | |
| 375 } | |
| 376 | |
| 377 // Collects: working set, peak working set, handle count, process uptime, | |
| 378 // user disk free space on the current drive, process kernel time, and process | |
| 379 // user time. | |
| 380 void Core::CollectMetrics() const { | |
| 381 uint64 working_set(0), peak_working_set(0); | |
| 382 VERIFY1(SUCCEEDED(System::GetProcessMemoryStatistics(&working_set, | |
| 383 &peak_working_set, | |
| 384 NULL, | |
| 385 NULL))); | |
| 386 metric_core_working_set = working_set; | |
| 387 metric_core_peak_working_set = peak_working_set; | |
| 388 | |
| 389 metric_core_handle_count = System::GetProcessHandleCount(); | |
| 390 | |
| 391 FILETIME now = {0}; | |
| 392 FILETIME creation_time = {0}; | |
| 393 FILETIME exit_time = {0}; | |
| 394 FILETIME kernel_time = {0}; | |
| 395 FILETIME user_time = {0}; | |
| 396 | |
| 397 ::GetSystemTimeAsFileTime(&now); | |
| 398 | |
| 399 VERIFY1(::GetProcessTimes(::GetCurrentProcess(), | |
| 400 &creation_time, | |
| 401 &exit_time, | |
| 402 &kernel_time, | |
| 403 &user_time)); | |
| 404 | |
| 405 ASSERT1(FileTimeToInt64(now) >= FileTimeToInt64(creation_time)); | |
| 406 uint64 uptime_100ns = FileTimeToInt64(now) - FileTimeToInt64(creation_time); | |
| 407 | |
| 408 metric_core_uptime_ms = uptime_100ns / kMillisecsTo100ns; | |
| 409 metric_core_kernel_time_ms = FileTimeToInt64(kernel_time) / kMillisecsTo100ns; | |
| 410 metric_core_user_time_ms = FileTimeToInt64(user_time) / kMillisecsTo100ns; | |
| 411 | |
| 412 uint64 free_bytes_current_user(0); | |
| 413 uint64 total_bytes_current_user(0); | |
| 414 uint64 free_bytes_all_users(0); | |
| 415 | |
| 416 CString directory_name(app_util::GetCurrentModuleDirectory()); | |
| 417 VERIFY1(SUCCEEDED(System::GetDiskStatistics(directory_name, | |
| 418 &free_bytes_current_user, | |
| 419 &total_bytes_current_user, | |
| 420 &free_bytes_all_users))); | |
| 421 metric_core_disk_space_available = free_bytes_current_user; | |
| 422 } | |
| 423 | |
| 424 } // namespace omaha | |
| OLD | NEW |