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

Side by Side Diff: base/system.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 | « base/system.h ('k') | base/system_info.h » ('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 2004-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/base/system.h"
17
18 #include <objidl.h>
19 #include <psapi.h>
20 #include <winioctl.h>
21 #include <wtsapi32.h>
22 #include "omaha/base/commands.h"
23 #include "omaha/base/commontypes.h"
24 #include "omaha/base/const_config.h"
25 #include "omaha/base/debug.h"
26 #include "omaha/base/disk.h"
27 #include "omaha/base/dynamic_link_kernel32.h"
28 #include "omaha/base/error.h"
29 #include "omaha/base/file.h"
30 #include "omaha/base/logging.h"
31 #include "omaha/base/module_utils.h"
32 #include "omaha/base/path.h"
33 #include "omaha/base/scope_guard.h"
34 #include "omaha/base/scoped_any.h"
35 #include "omaha/base/string.h"
36 #include "omaha/base/system_info.h"
37 #include "omaha/base/utils.h"
38 #include "omaha/base/vistautil.h"
39
40 namespace omaha {
41
42 // Constant
43 const TCHAR kNeedRebootHiddenFileSuffix[] = _T(".needreboot");
44
45 HRESULT System::WaitForDiskActivity(const uint32 max_delay_milliseconds,
46 const uint32 sleep_time_ms,
47 uint32 *time_waited) {
48 ASSERT(time_waited, (L""));
49 uint32 sleep_time = sleep_time_ms;
50 if (sleep_time < 20) { sleep_time = 20; }
51 else if (sleep_time > 1000) { sleep_time = 1000; }
52 HRESULT r;
53 *time_waited = 0;
54 uint64 writes = 0;
55 uint64 new_writes = 0;
56 // get current counters
57 if (FAILED(r=GetDiskActivityCounters(NULL, &writes, NULL, NULL))) {
58 return r;
59 }
60
61 // wait until a write - reads may be cached
62 while (1) {
63 if (FAILED(r=GetDiskActivityCounters(NULL, &new_writes, NULL, NULL))) {
64 return r;
65 }
66 if (new_writes > writes) { return S_OK; }
67 if (*time_waited > max_delay_milliseconds) { return E_FAIL; }
68 SleepEx(sleep_time, TRUE);
69 *time_waited += sleep_time;
70 }
71 }
72
73 HRESULT System::GetDiskActivityCounters(uint64* reads,
74 uint64* writes,
75 uint64* bytes_read,
76 uint64* bytes_written) {
77 if (reads) {
78 *reads = 0;
79 }
80
81 if (writes) {
82 *writes = 0;
83 }
84
85 if (bytes_read) {
86 *bytes_read = 0;
87 }
88
89 if (bytes_written) {
90 *bytes_written = 0;
91 }
92
93 // Don't want to risk displaying UI errors here
94 DisableThreadErrorUI disable_error_dialog_box;
95
96 // for all drives
97 for (int drive = 0; ; drive++) {
98 struct _DISK_PERFORMANCE perf_data;
99 const int max_device_len = 50;
100
101 // check whether we can access this device
102 CString device_name;
103 device_name.Format(_T("\\\\.\\PhysicalDrive%d"), drive);
104 scoped_handle device(::CreateFile(device_name, 0,
105 FILE_SHARE_READ | FILE_SHARE_WRITE,
106 NULL, OPEN_EXISTING, 0, NULL));
107
108 if (get(device) == INVALID_HANDLE_VALUE) {
109 if (!drive) {
110 UTIL_LOG(LEVEL_ERROR, (_T("[Failed to access drive %i][0x%x]"),
111 drive,
112 HRESULTFromLastError()));
113 }
114 break;
115 }
116
117 // disk performance counters must be on (diskperf -y on older machines;
118 // defaults to on on newer windows)
119 DWORD size = 0;
120 if (::DeviceIoControl(get(device),
121 IOCTL_DISK_PERFORMANCE,
122 NULL,
123 0,
124 &perf_data,
125 sizeof(_DISK_PERFORMANCE),
126 &size,
127 NULL)) {
128 if (reads) {
129 *reads += perf_data.ReadCount;
130 }
131
132 if (writes) {
133 *writes += perf_data.WriteCount;
134 }
135
136 if (bytes_read) {
137 *bytes_read += perf_data.BytesRead.QuadPart;
138 }
139
140 if (bytes_written) {
141 *bytes_written += perf_data.BytesWritten.QuadPart;
142 }
143 } else {
144 HRESULT hr = HRESULTFromLastError();
145 UTIL_LOG(LEVEL_ERROR,
146 (_T("[System::GetDiskActivityCounters - failed to ")
147 _T("DeviceIoControl][0x%x]"), hr));
148 return hr;
149 }
150 }
151
152 return S_OK;
153 }
154
155 HRESULT System::GetDiskStatistics(const TCHAR* path,
156 uint64 *free_bytes_current_user,
157 uint64 *total_bytes_current_user,
158 uint64 *free_bytes_all_users) {
159 ASSERT1(path);
160 ASSERT1(free_bytes_current_user);
161 ASSERT1(total_bytes_current_user);
162 ASSERT1(free_bytes_all_users);
163 ASSERT1(sizeof(LARGE_INTEGER) == sizeof(uint64)); // NOLINT
164
165 DisableThreadErrorUI disable_error_dialog_box;
166
167 if (!::GetDiskFreeSpaceEx(
168 path,
169 reinterpret_cast<PULARGE_INTEGER>(free_bytes_current_user),
170 reinterpret_cast<PULARGE_INTEGER>(total_bytes_current_user),
171 reinterpret_cast<PULARGE_INTEGER>(free_bytes_all_users))) {
172 HRESULT hr = HRESULTFromLastError();
173 UTIL_LOG(LEVEL_ERROR,
174 (_T("[Failed to GetDiskFreeSpaceEx][%s][0x%x]"), path, hr));
175 return hr;
176 }
177
178 return S_OK;
179 }
180
181 HRESULT System::GetProcessMemoryStatistics(uint64 *current_working_set,
182 uint64 *peak_working_set,
183 uint64 *min_working_set_size,
184 uint64 *max_working_set_size) {
185 HANDLE process_handle = GetCurrentProcess();
186 HRESULT hr = S_OK;
187
188 DWORD min_size(0), max_size(0);
189 if (GetProcessWorkingSetSize(process_handle, &min_size, &max_size)) {
190 UTIL_LOG(L2, (_T("[working set][min: %lu][max: %lu]"), min_size, max_size));
191 if (min_working_set_size) {
192 *min_working_set_size = min_size;
193 }
194 if (max_working_set_size) {
195 *max_working_set_size = max_size;
196 }
197 } else {
198 if (min_working_set_size) {
199 *min_working_set_size = 0;
200 }
201 if (max_working_set_size) {
202 *max_working_set_size = 0;
203 }
204 hr = E_FAIL;
205 }
206
207 if (current_working_set) { *current_working_set = 0; }
208 if (peak_working_set) { *peak_working_set = 0; }
209
210 // including this call (w/psapi.lib) adds 24k to the process memory
211 // according to task manager in one test, memory usage according to task
212 // manager increased by 4k after calling this
213 PROCESS_MEMORY_COUNTERS counters = { sizeof(counters), 0 };
214 if (GetProcessMemoryInfo(process_handle,
215 &counters,
216 sizeof(PROCESS_MEMORY_COUNTERS))) {
217 if (current_working_set) {
218 *current_working_set = counters.WorkingSetSize;
219 }
220 if (peak_working_set) {
221 *peak_working_set = counters.PeakWorkingSetSize;
222 }
223 UTIL_LOG(L2, (_T("[working set][current: %s][peak: %s]"),
224 String_Int64ToString(*current_working_set, 10),
225 String_Int64ToString(*peak_working_set, 10)));
226 } else {
227 if (current_working_set) {
228 *current_working_set = 0;
229 }
230 if (peak_working_set) {
231 *peak_working_set = 0;
232 }
233 hr = E_FAIL;
234 }
235
236 return hr;
237 }
238
239 HRESULT System::MaxPhysicalMemoryAvailable(uint64* max_bytes) {
240 ASSERT1(max_bytes);
241
242 *max_bytes = 0;
243
244 uint32 memory_load_percentage = 0;
245 uint64 free_physical_memory = 0;
246
247 RET_IF_FAILED(System::GetGlobalMemoryStatistics(&memory_load_percentage,
248 &free_physical_memory, NULL, NULL, NULL, NULL, NULL));
249
250 UTIL_LOG(L4, (_T("mem load %u max physical memory available %s"),
251 memory_load_percentage,
252 String_Int64ToString(free_physical_memory, 10)));
253
254 *max_bytes = free_physical_memory;
255
256 return S_OK;
257 }
258
259 HRESULT System::GetGlobalMemoryStatistics(uint32 *memory_load_percentage,
260 uint64 *free_physical_memory,
261 uint64 *total_physical_memory,
262 uint64 *free_paged_memory,
263 uint64 *total_paged_memory,
264 uint64 *process_free_virtual_memory,
265 uint64 *process_total_virtual_mem) {
266 MEMORYSTATUSEX status;
267 status.dwLength = sizeof(status);
268 if (!GlobalMemoryStatusEx(&status)) {
269 UTIL_LOG(LEVEL_ERROR, (_T("memory status error %u"), GetLastError()));
270 return E_FAIL;
271 }
272 if (memory_load_percentage) { *memory_load_percentage = status.dwMemoryLoad; }
273 if (free_physical_memory) { *free_physical_memory = status.ullAvailPhys; }
274 if (total_physical_memory) { *total_physical_memory = status.ullTotalPhys; }
275 if (free_paged_memory) { *free_paged_memory = status.ullAvailPageFile; }
276 if (total_paged_memory) { *total_paged_memory = status.ullTotalPageFile; }
277 if (process_free_virtual_memory) {
278 *process_free_virtual_memory = status.ullAvailVirtual;
279 }
280 if (process_total_virtual_mem) {
281 *process_total_virtual_mem = status.ullTotalVirtual;
282 }
283 // GetPerformanceInfo;
284 return S_OK;
285 }
286
287 void System::FreeProcessWorkingSet() {
288 // -1,-1 is a special signal to the OS to temporarily trim the working set
289 // size to 0. See MSDN for further information.
290 ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1);
291 }
292
293 HRESULT System::SetThreadPriority(enum Priority priority) {
294 int pri;
295
296 switch (priority) {
297 case LOW: pri = THREAD_PRIORITY_BELOW_NORMAL; break;
298 case HIGH: pri = THREAD_PRIORITY_HIGHEST; break;
299 case NORMAL: pri = THREAD_PRIORITY_NORMAL; break;
300 case IDLE: pri = THREAD_PRIORITY_IDLE; break;
301 default: return E_FAIL;
302 }
303
304 if (::SetThreadPriority(GetCurrentThread(), pri)) {
305 return S_OK;
306 } else {
307 return E_FAIL;
308 }
309 }
310
311 HRESULT System::SetProcessPriority(enum Priority priority) {
312 DWORD pri = 0;
313 switch (priority) {
314 case LOW: pri = BELOW_NORMAL_PRIORITY_CLASS; break;
315 case HIGH: pri = ABOVE_NORMAL_PRIORITY_CLASS; break;
316 case NORMAL: pri = NORMAL_PRIORITY_CLASS; break;
317 case IDLE: return E_INVALIDARG;
318 default: return E_INVALIDARG;
319 }
320
321 DWORD pid = ::GetCurrentProcessId();
322
323 scoped_handle handle(::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid));
324 if (!valid(handle)) {
325 HRESULT hr = HRESULTFromLastError();
326 UTIL_LOG(LE, (_T("[::OpenProcess failed][%u][0x%x]"), pid, hr));
327 return hr;
328 }
329
330 if (!::SetPriorityClass(get(handle), pri)) {
331 HRESULT hr = HRESULTFromLastError();
332 UTIL_LOG(LE, (_T("[::SetPriorityClass failed][%u][0x%x]"), pid, hr));
333 return hr;
334 }
335
336 return S_OK;
337 }
338
339 // start another process painlessly via ::CreateProcess. Use the
340 // ShellExecuteProcessXXX variants instead of these methods where possible,
341 // since ::ShellExecuteEx has better behavior on Windows Vista.
342 // When using this method, avoid using process_name - see
343 // http://blogs.msdn.com/oldnewthing/archive/2006/05/15/597984.aspx.
344 HRESULT System::StartProcess(const TCHAR* process_name,
345 TCHAR* command_line,
346 PROCESS_INFORMATION* pi) {
347 ASSERT1(pi);
348 ASSERT1(command_line || process_name);
349 ASSERT(!process_name, (_T("Avoid using process_name. See method comment.")));
350
351 STARTUPINFO si = {sizeof(si), 0};
352
353 // Feedback cursor is off while the process is starting.
354 si.dwFlags = STARTF_FORCEOFFFEEDBACK;
355
356 UTIL_LOG(L3, (_T("[System::StartProcess][process %s][cmd %s]"),
357 process_name, command_line));
358
359 BOOL success = ::CreateProcess(
360 process_name, // Module name
361 command_line, // Command line
362 NULL, // Process handle not inheritable
363 NULL, // Thread handle not inheritable
364 FALSE, // Set handle inheritance to FALSE
365 0, // No creation flags
366 NULL, // Use parent's environment block
367 NULL, // Use parent's starting directory
368 &si, // Pointer to STARTUPINFO structure
369 pi); // Pointer to PROCESS_INFORMATION structure
370
371 if (!success) {
372 HRESULT hr = HRESULTFromLastError();
373 UTIL_LOG(LEVEL_ERROR,
374 (_T("[System::StartProcess][::CreateProcess failed][0x%x]"), hr));
375 return hr;
376 }
377
378 OPT_LOG(L1, (_T("[Started process][%u]"), pi->dwProcessId));
379
380 return S_OK;
381 }
382
383 // start another process painlessly via ::CreateProcess. Use the
384 // ShellExecuteProcessXXX variants instead of these methods where possible,
385 // since ::ShellExecuteEx has better behavior on Windows Vista.
386 HRESULT System::StartProcessWithArgsAndInfo(const TCHAR *process_name,
387 const TCHAR *cmd_line_arguments,
388 PROCESS_INFORMATION *pi) {
389 ASSERT1(process_name && cmd_line_arguments && pi);
390
391 CString command_line(process_name);
392 EnclosePath(&command_line);
393 command_line.AppendChar(_T(' '));
394 command_line.Append(cmd_line_arguments);
395 return System::StartProcess(NULL, CStrBuf(command_line), pi);
396 }
397
398 // start another process painlessly via ::CreateProcess. Use the
399 // ShellExecuteProcessXXX variants instead of these methods where possible,
400 // since ::ShellExecuteEx has better behavior on Windows Vista.
401 HRESULT System::StartProcessWithArgs(const TCHAR *process_name,
402 const TCHAR *cmd_line_arguments) {
403 ASSERT1(process_name && cmd_line_arguments);
404 PROCESS_INFORMATION pi = {0};
405 HRESULT hr = System::StartProcessWithArgsAndInfo(process_name,
406 cmd_line_arguments,
407 &pi);
408 if (SUCCEEDED(hr)) {
409 ::CloseHandle(pi.hProcess);
410 ::CloseHandle(pi.hThread);
411 }
412 return hr;
413 }
414
415 HRESULT System::StartCommandLine(const TCHAR* command_line_to_execute) {
416 ASSERT1(command_line_to_execute);
417
418 CString command_line(command_line_to_execute);
419 PROCESS_INFORMATION pi = {0};
420 HRESULT hr = System::StartProcess(NULL, CStrBuf(command_line), &pi);
421 if (SUCCEEDED(hr)) {
422 ::CloseHandle(pi.hProcess);
423 ::CloseHandle(pi.hThread);
424 }
425 return hr;
426 }
427
428 // TODO(omaha3): Unit test this method.
429 HRESULT System::StartProcessAsUser(HANDLE user_token,
430 const CString& executable_path,
431 const CString& parameters,
432 LPWSTR desktop,
433 PROCESS_INFORMATION* pi) {
434 UTIL_LOG(L3, (_T("[StartProcessAsUser][%s][%s][%s]"),
435 executable_path, parameters, desktop));
436 ASSERT1(pi);
437
438 CString cmd(executable_path);
439 EnclosePath(&cmd);
440 cmd.AppendChar(_T(' '));
441 cmd.Append(parameters);
442
443 STARTUPINFO startup_info = { sizeof(startup_info) };
444 startup_info.lpDesktop = desktop;
445 DWORD creation_flags(0);
446
447 void* environment_block(NULL);
448 if (!::CreateEnvironmentBlock(&environment_block, user_token, TRUE)) {
449 HRESULT hr = HRESULTFromLastError();
450 ASSERT(false, (_T("[::CreateEnvironmentBlock failed][0x%x]"), hr));
451 return hr;
452 }
453
454 ON_SCOPE_EXIT(::DestroyEnvironmentBlock, environment_block);
455
456 creation_flags |= CREATE_UNICODE_ENVIRONMENT;
457 BOOL success = ::CreateProcessAsUser(user_token,
458 0,
459 CStrBuf(cmd, MAX_PATH),
460 0,
461 0,
462 false,
463 creation_flags,
464 environment_block,
465 0,
466 &startup_info,
467 pi);
468
469 if (!success) {
470 HRESULT hr(HRESULTFromLastError());
471 UTIL_LOG(LE, (_T("[::CreateProcessAsUser failed][%s][0x%x]"), cmd, hr));
472 return hr;
473 }
474
475 return S_OK;
476 }
477
478 // start another process painlessly via ::ShellExecuteEx. Use this method
479 // instead of the StartProcessXXX methods that use ::CreateProcess where
480 // possible, since ::ShellExecuteEx has better behavior on Windows Vista.
481 //
482 // ShellExecuteExEnsureParent displays the PID of the started process if it is
483 // returned. It is only returned if the mask includes SEE_MASK_NOCLOSEPROCESS.
484 // Therefore, we always set this flag and pass a handle. If the caller did not
485 // request the handle, we close it.
486 HRESULT System::ShellExecuteProcess(const TCHAR* file_name_to_execute,
487 const TCHAR* command_line_parameters,
488 HWND hwnd,
489 HANDLE* process_handle) {
490 ASSERT1(file_name_to_execute);
491
492 UTIL_LOG(L3, (_T("[System::ShellExecuteProcess]")
493 _T("[file_name_to_execute '%s' command_line_parameters '%s']"),
494 file_name_to_execute, command_line_parameters));
495
496 SHELLEXECUTEINFO sei = {0};
497 sei.cbSize = sizeof(sei);
498 // SEE_MASK_NOZONECHECKS is set below to work around a problem in systems that
499 // had Internet Explorer 7 Beta installed. See http://b/804674.
500 // This only works for Windows XP SP1 and later.
501 sei.fMask = SEE_MASK_NOCLOSEPROCESS | // Set hProcess to process handle.
502 SEE_MASK_FLAG_NO_UI | // Do not display an error message box.
503 SEE_MASK_NOZONECHECKS | // Do not perform a zone check.
504 SEE_MASK_NOASYNC; // Wait to complete before returning.
505 sei.lpVerb = _T("open");
506 sei.lpFile = file_name_to_execute;
507 sei.lpParameters = command_line_parameters;
508 sei.nShow = SW_SHOWNORMAL;
509 sei.hwnd = hwnd;
510
511 // Use ShellExecuteExEnsureParent to ensure that we always have a parent
512 // window. We need to use the HWND property to be acknowledged as a foreground
513 // application on Windows Vista. Otherwise, the elevation prompt will appear
514 // minimized on the taskbar.
515 if (!ShellExecuteExEnsureParent(&sei)) {
516 HRESULT hr(HRESULTFromLastError());
517 OPT_LOG(LEVEL_ERROR, (_T("[Failed to ::ShellExecuteEx][%s][%s][0x%08x]"),
518 file_name_to_execute, command_line_parameters, hr));
519 return hr;
520 }
521
522 if (process_handle) {
523 *process_handle = sei.hProcess;
524 } else {
525 ::CloseHandle(sei.hProcess);
526 }
527
528 return S_OK;
529 }
530
531 // start another process painlessly via ::ShellExecuteEx. Use this method
532 // instead of the StartProcessXXX methods that use ::CreateProcess where
533 // possible, since ::ShellExecuteEx has better behavior on Windows Vista.
534 HRESULT System::ShellExecuteCommandLine(const TCHAR* command_line_to_execute,
535 HWND hwnd,
536 HANDLE* process_handle) {
537 ASSERT1(command_line_to_execute);
538
539 CString exe;
540 CString args;
541
542 HRESULT hr = CommandParsingSimple::SplitExeAndArgs(command_line_to_execute,
543 &exe,
544 &args);
545
546 if (SUCCEEDED(hr)) {
547 hr = System::ShellExecuteProcess(exe, args, hwnd, process_handle);
548 if (FAILED(hr)) {
549 UTIL_LOG(LEVEL_ERROR, (_T("[System::ShellExecuteProcess failed]")
550 _T("[%s][%s][0x%08x]"), exe, args, hr));
551 }
552 }
553
554 return hr;
555 }
556
557 // returns the number of ms the system has had no user input
558 int System::GetUserIdleTime() {
559 LASTINPUTINFO last_input_info;
560 last_input_info.cbSize = sizeof(LASTINPUTINFO);
561 // get time in windows ticks since system start of last activity
562 BOOL b = GetLastInputInfo(&last_input_info);
563 if (b == TRUE) {
564 return (GetTickCount()-last_input_info.dwTime); // compute idle time
565 }
566 return 0;
567 }
568
569 bool System::IsUserIdle() {
570 // Only notify when the user has been idle less than this time
571 static int user_idle_threshold_ms = kUserIdleThresholdMs;
572
573 bool is_user_idle = (GetUserIdleTime() > user_idle_threshold_ms);
574 UTIL_LOG(L2, (_T("System::IsUserIdle() %s; user_idle_threshold_ms = %d"),
575 is_user_idle ? _T("TRUE") : _T("FALSE"),
576 user_idle_threshold_ms));
577 return is_user_idle;
578 }
579
580 bool System::IsUserBusy() {
581 // The user is busy typing or interacting with another application
582 // if the user is below the minimum threshold:
583 static int user_idle_min_threshold_ms = kUserIdleMinThresholdMs;
584 // The user is probably not paying attention
585 // if the user is above the maximum threshold:
586 static int user_idle_max_threshold_ms = kUserIdleMaxThresholdMs;
587
588 int user_idle_time = GetUserIdleTime();
589 bool is_user_busy = user_idle_time < user_idle_min_threshold_ms ||
590 user_idle_time > user_idle_max_threshold_ms;
591 UTIL_LOG(L2, (_T("[System::IsUserBusy() %s][user_idle_time = %d]")
592 _T("[user_idle_min_threshold_ms = %d]")
593 _T("[user_idle_max_threshold_ms = %d]"),
594 is_user_busy? _T("TRUE") : _T("FALSE"),
595 user_idle_time,
596 user_idle_min_threshold_ms,
597 user_idle_max_threshold_ms));
598 return is_user_busy;
599 }
600
601 bool System::IsScreensaverRunning() {
602 // NT 4.0 and below require testing OpenDesktop("screen-saver")
603 // We require W2K or better so we have an easier way
604 DWORD result = 0;
605 ::SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &result, 0);
606 bool is_screensaver_running = (result != FALSE);
607 UTIL_LOG(L2, (_T("System::IsScreensaverRunning() %s"),
608 is_screensaver_running? _T("TRUE") : _T("FALSE")));
609 return is_screensaver_running;
610 }
611
612 bool System::IsWorkstationLocked() {
613 bool is_workstation_locked = true;
614 HDESK inputdesk = ::OpenInputDesktop(0, 0, GENERIC_READ);
615 if (NULL != inputdesk) {
616 TCHAR name[256];
617 DWORD needed = arraysize(name);
618 BOOL ok = ::GetUserObjectInformation(inputdesk,
619 UOI_NAME,
620 name,
621 sizeof(name),
622 &needed);
623 ::CloseDesktop(inputdesk);
624 if (ok) {
625 is_workstation_locked = (0 != lstrcmpi(name, NOTRANSL(_T("default"))));
626 }
627 }
628
629 UTIL_LOG(L2, (_T("System::IsWorkstationLocked() %s"),
630 is_workstation_locked? _T("TRUE") : _T("FALSE")));
631 return is_workstation_locked;
632 }
633
634 bool System::IsUserAway() {
635 return IsScreensaverRunning() || IsWorkstationLocked();
636 }
637
638 uint32 System::GetProcessHandleCount() {
639 typedef LONG (CALLBACK *Fun)(HANDLE, int32, PVOID, ULONG, PULONG);
640
641 // This new version of getting the number of open handles works on win2k.
642 HMODULE h = GetModuleHandle(_T("ntdll.dll"));
643 Fun NtQueryInformationProcess =
644 reinterpret_cast<Fun>(::GetProcAddress(h, "NtQueryInformationProcess"));
645
646 if (!NtQueryInformationProcess) {
647 UTIL_LOG(LEVEL_ERROR, (_T("[NtQueryInformationProcess failed][0x%x]"),
648 HRESULTFromLastError()));
649 return 0;
650 }
651
652 DWORD count = 0;
653 VERIFY(NtQueryInformationProcess(GetCurrentProcess(),
654 kProcessHandleCount,
655 &count,
656 sizeof(count),
657 NULL) >= 0, (L""));
658
659 return count;
660 }
661
662 uint32 System::GetProcessHandleCountOld() {
663 typedef BOOL (CALLBACK * Fun)(HANDLE, PDWORD);
664
665 // GetProcessHandleCount not available on win2k
666 HMODULE handle = GetModuleHandle(_T("kernel32"));
667 Fun f = reinterpret_cast<Fun>(GetProcAddress(handle,
668 "GetProcessHandleCount"));
669
670 if (!f) return 0;
671
672 DWORD count = 0;
673 VERIFY((*f)(GetCurrentProcess(), &count), (L""));
674 return count;
675
676 // DWORD GetGuiResources (HANDLE hProcess, DWORD uiFlags);
677 // Parameters, hProcess
678 // [in] Handle to the process. The handle must have the
679 // PROCESS_QUERY_INFORMATION access right. For more information, see Process
680 // Security and Access Rights.
681 // uiFlags
682 // [in] GUI object type. This parameter can be one of the following values.
683 // Value Meaning
684 // GR_GDIOBJECTS Return the count of GDI objects.
685 // GR_USEROBJECTS Return the count of USER objects.
686 }
687
688 void System::GetGuiObjectCount(uint32 *gdi, uint32 *user) {
689 if (gdi) {
690 *gdi = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
691 }
692 if (user) {
693 *user = GetGuiResources(GetCurrentProcess(), GR_USEROBJECTS);
694 }
695 }
696
697 HRESULT System::GetRebootCheckDummyFileName(const TCHAR* base_file,
698 CString* dummy_file) {
699 ASSERT1(dummy_file);
700
701 if (base_file && *base_file) {
702 ASSERT1(File::Exists(base_file));
703 dummy_file->SetString(base_file);
704 } else {
705 RET_IF_FAILED(GetModuleFileName(NULL, dummy_file));
706 }
707 dummy_file->Append(_T(".needreboot"));
708 return S_OK;
709 }
710
711 // Is the system being rebooted?
712 bool System::IsRebooted(const TCHAR* base_file) {
713 CString dummy_file;
714 if (SUCCEEDED(GetRebootCheckDummyFileName(base_file, &dummy_file))) {
715 if (File::Exists(dummy_file)) {
716 // If the file exists but it is not found in the
717 // PendingFileRenameOperations, (probably becaused that this key is messed
718 // up and thus the system restart fails to delete the file), re-add it
719 if (!File::AreMovesPendingReboot(dummy_file, true)) {
720 File::MoveAfterReboot(dummy_file, NULL);
721 }
722 return false;
723 } else {
724 return true;
725 }
726 }
727 return false;
728 }
729
730 // Mark the system as reboot required
731 HRESULT System::MarkAsRebootRequired(const TCHAR* base_file) {
732 // Create a dummy file if needed
733 CString dummy_file;
734 RET_IF_FAILED(GetRebootCheckDummyFileName(base_file, &dummy_file));
735 if (File::Exists(dummy_file)) {
736 return S_OK;
737 }
738
739 File file;
740 RET_IF_FAILED(file.Open(dummy_file, true, false));
741 RET_IF_FAILED(file.Close());
742
743 // Hide it
744 DWORD file_attr = ::GetFileAttributes(dummy_file);
745 if (file_attr == INVALID_FILE_ATTRIBUTES ||
746 !::SetFileAttributes(dummy_file, file_attr | FILE_ATTRIBUTE_HIDDEN)) {
747 return HRESULTFromLastError();
748 }
749
750 // Mark it as being deleted after reboot
751 return File::MoveAfterReboot(dummy_file, NULL);
752 }
753
754 // Unmark the system as reboot required
755 HRESULT System::UnmarkAsRebootRequired(const TCHAR* base_file) {
756 CString dummy_file;
757 RET_IF_FAILED(GetRebootCheckDummyFileName(base_file, &dummy_file));
758
759 return File::RemoveFromMovesPendingReboot(dummy_file, false);
760 }
761
762 // Restart the computer
763 HRESULT System::RestartComputer() {
764 RET_IF_FAILED(AdjustPrivilege(SE_SHUTDOWN_NAME, true));
765
766 if (!::ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
767 SHTDN_REASON_MINOR_INSTALLATION |
768 SHTDN_REASON_FLAG_PLANNED)) {
769 HRESULT hr = HRESULTFromLastError();
770 UTIL_LOG(LEVEL_ERROR, (_T("[System::RestartComputer - failed to")
771 _T(" ExitWindowsEx][0x%x]"), hr));
772 return hr;
773 }
774
775 return S_OK;
776 }
777
778 // The implementation works on all Windows versions. On NT and XP the screen
779 // saver is actually stored in registry at
780 // HKEY_CURRENT_USER\Control Panel\Desktop\SCRNSAVE.EXE but the
781 // GetPrivateProfileString call is automatically mapped to the registry
782 HRESULT System::GetCurrentScreenSaver(CString* fileName) {
783 if (!fileName) return E_POINTER;
784
785 DWORD nChars = ::GetPrivateProfileString(_T("boot"),
786 _T("SCRNSAVE.EXE"),
787 _T(""),
788 fileName->GetBuffer(MAX_PATH),
789 MAX_PATH,
790 _T("system.ini"));
791 fileName->ReleaseBufferSetLength(nChars);
792
793 return S_OK;
794 }
795
796 HRESULT System::CoCreateInstanceAsAdmin(HWND hwnd,
797 REFCLSID rclsid,
798 REFIID riid,
799 void** ppv) {
800 UTIL_LOG(L6, (_T("[CoCreateInstanceAsAdmin][%d][%s][%s]"),
801 hwnd, GuidToString(rclsid), GuidToString(riid)));
802
803 if (vista_util::IsUserAdmin()) {
804 return ::CoCreateInstance(rclsid, NULL, CLSCTX_LOCAL_SERVER, riid, ppv);
805 }
806
807 if (!SystemInfo::IsRunningOnVistaOrLater()) {
808 return E_ACCESSDENIED;
809 }
810
811 CString moniker_name(_T("Elevation:Administrator!new:"));
812 moniker_name += GuidToString(rclsid);
813 BIND_OPTS3 bo;
814 SetZero(bo);
815 bo.cbStruct = sizeof(bo);
816 bo.hwnd = hwnd;
817 bo.dwClassContext = CLSCTX_LOCAL_SERVER;
818
819 return ::CoGetObject(moniker_name, &bo, riid, ppv);
820 }
821
822 HRESULT System::IsPrivilegeEnabled(const TCHAR* privilege, bool* present) {
823 ASSERT1(privilege);
824 ASSERT1(present);
825
826 *present = false;
827
828 scoped_handle token;
829 if (!::OpenProcessToken(::GetCurrentProcess(),
830 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
831 address(token))) {
832 HRESULT hr = HRESULTFromLastError();
833 UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to ")
834 _T("OpenProcessToken][0x%x]"), hr));
835 return hr;
836 }
837
838 LUID luid = {0};
839 if (!::LookupPrivilegeValue(NULL, privilege, &luid)) {
840 HRESULT hr = HRESULTFromLastError();
841 UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to")
842 _T("LookupPrivilegeValue][0x%x]"), hr));
843 return hr;
844 }
845
846 PRIVILEGE_SET required_privilege = {0};
847 required_privilege.PrivilegeCount = 1;
848 required_privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;
849 required_privilege.Privilege[0].Luid = luid;
850
851 BOOL result = FALSE;
852 if (!::PrivilegeCheck(get(token), &required_privilege, &result)) {
853 HRESULT hr = HRESULTFromLastError();
854 UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to")
855 _T("PrivilegeCheck][0x%x]"), hr));
856 return hr;
857 }
858
859 if (required_privilege.Privilege[0].Attributes &
860 SE_PRIVILEGE_USED_FOR_ACCESS) {
861 *present = true;
862 }
863
864 return S_OK;
865 }
866
867 // Attempts to adjust current process privileges.
868 // Only process running with administrator privileges will succeed.
869 HRESULT System::AdjustPrivilege(const TCHAR* privilege, bool enable) {
870 ASSERT1(privilege);
871
872 scoped_handle token;
873 if (!::OpenProcessToken(::GetCurrentProcess(),
874 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
875 address(token))) {
876 HRESULT hr = HRESULTFromLastError();
877 UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to ")
878 _T("OpenProcessToken][0x%x]"), hr));
879 return hr;
880 }
881
882 LUID luid = {0};
883 if (!::LookupPrivilegeValue(NULL, privilege, &luid)) {
884 HRESULT hr = HRESULTFromLastError();
885 UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to")
886 _T("LookupPrivilegeValue][0x%x]"), hr));
887 return hr;
888 }
889
890 TOKEN_PRIVILEGES privs;
891 privs.PrivilegeCount = 1;
892 privs.Privileges[0].Luid = luid;
893 privs.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
894
895 if (!::AdjustTokenPrivileges(get(token), FALSE, &privs, 0, NULL, 0)) {
896 HRESULT hr = HRESULTFromLastError();
897 UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to ")
898 _T("AdjustTokenPrivileges][0x%x]"), hr));
899 return hr;
900 }
901
902 return S_OK;
903 }
904
905 DWORD System::WTSGetActiveConsoleSessionId() {
906 typedef DWORD (* Fun)();
907
908 HINSTANCE hInst = ::GetModuleHandle(_T("kernel32.dll"));
909 ASSERT1(hInst);
910 Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(
911 hInst,
912 "WTSGetActiveConsoleSessionId"));
913 return !pfn ? kInvalidSessionId : (*pfn)();
914 }
915
916 // Get the session the current process is running under
917 DWORD System::GetCurrentSessionId() {
918 DWORD session_id = kInvalidSessionId;
919 DWORD* session_id_ptr = NULL;
920 DWORD bytes_returned = 0;
921
922 if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
923 WTS_CURRENT_SESSION,
924 WTSSessionId,
925 reinterpret_cast<LPTSTR*>(&session_id_ptr),
926 &bytes_returned)) {
927 ASSERT1(bytes_returned == sizeof(*session_id_ptr));
928 session_id = *session_id_ptr;
929 ::WTSFreeMemory(session_id_ptr);
930 UTIL_LOG(L6, (_T("[System::GetCurrentSessionId]")
931 _T("[session_id from ::WTSQuerySessionInformation][%d]"),
932 session_id));
933 return session_id;
934 }
935
936 // ::WTSQuerySessionInformation can fail if we are not running
937 // in a Terminal Services scenario, in which case, we use
938 // ::ProcessIdToSessionId()
939 if (::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) {
940 UTIL_LOG(L6, (_T("[System::GetCurrentSessionId]")
941 _T("[session_id from ::ProcessIdToSessionId][%d]"),
942 session_id));
943 return session_id;
944 }
945
946 UTIL_LOG(LEVEL_ERROR,
947 (_T("[System::GetCurrentSessionId - both")
948 _T("::WTSQuerySessionInformation and ")
949 _T("::ProcessIdToSessionId failed][0x%x]"),
950 ::GetLastError()));
951
952 return kInvalidSessionId;
953 }
954
955 // Get the best guess as to the currently active session, or kInvalidSessionId
956 // if there is no active session.
957 DWORD System::GetActiveSessionId() {
958 // WTSGetActiveConsoleSessionId retrieves the Terminal Services session
959 // currently attached to the physical console.
960 DWORD active_session_id = WTSGetActiveConsoleSessionId();
961
962 if (IsSessionActive(active_session_id)) {
963 UTIL_LOG(L6, (_T("[System::GetActiveSessionId]")
964 _T("[Active session id from ::WTSGetActiveConsoleSessionId]")
965 _T("[%d]"), active_session_id));
966
967 return active_session_id;
968 }
969
970 // WTSGetActiveConsoleSessionId works for FUS, but it does not work for TS
971 // servers where the current active session is always the console. We then use
972 // a different method as below. We get all the sessions that are present on
973 // the system, to see if we can find an active session.
974 active_session_id = kInvalidSessionId;
975 WTS_SESSION_INFO* session_info = NULL;
976 DWORD num_sessions = 0;
977 if (::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1,
978 &session_info, &num_sessions)) {
979 // Pick the first active session we can find
980 for (DWORD i = 0 ; i < num_sessions; ++i) {
981 if (session_info[i].State == WTSActive) {
982 // There is a user logged on to the WinStation associated with the
983 // session.
984 active_session_id = session_info[i].SessionId;
985 break;
986 }
987 }
988
989 ::WTSFreeMemory(session_info);
990 UTIL_LOG(L6, (_T("[System::GetActiveSessionId]")
991 _T("[Active session id from ::WTSEnumerateSessions][0x%x]"),
992 active_session_id));
993
994 return active_session_id;
995 }
996
997 UTIL_LOG(LEVEL_ERROR,
998 (_T("[System::GetActiveSessionId - ")
999 _T("Both ::WTSGetActiveConsoleSessionId and ::WTSEnumerateSessions ")
1000 _T("failed][0x%x]"),
1001 ::GetLastError()));
1002
1003 return kInvalidSessionId;
1004 }
1005
1006 // Is there a user logged on and active in the specified session?
1007 bool System::IsSessionActive(DWORD session_id) {
1008 if (kInvalidSessionId == session_id) {
1009 return false;
1010 }
1011
1012 WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
1013 WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
1014 DWORD bytes_returned = 0;
1015 if (::WTSQuerySessionInformation(
1016 WTS_CURRENT_SERVER_HANDLE,
1017 session_id,
1018 WTSConnectState,
1019 reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
1020 &bytes_returned)) {
1021 ASSERT1(bytes_returned == sizeof(*ptr_wts_connect_state));
1022 wts_connect_state = *ptr_wts_connect_state;
1023 ::WTSFreeMemory(ptr_wts_connect_state);
1024
1025 UTIL_LOG(L6, (_T("[System::IsSessionActive]")
1026 _T("[wts_connect_state %d]"), wts_connect_state));
1027 return WTSActive == wts_connect_state;
1028 }
1029
1030 UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%x]"),
1031 ::GetLastError()));
1032 return false;
1033 }
1034
1035 // Is the current process running under WinSta0
1036 bool System::IsCurrentProcessInteractive() {
1037 // Use a non-scoped handle, since a handle retrieved via
1038 // ::GetProcessWindowStation() should not be closed.
1039 HWINSTA handle_window_station(::GetProcessWindowStation());
1040 DWORD len = 0;
1041 CString str_window_station;
1042
1043 if (!handle_window_station || handle_window_station == INVALID_HANDLE_VALUE) {
1044 UTIL_LOG(LEVEL_ERROR,
1045 (_T("[System::IsCurrentProcessInteractive - ")
1046 _T("::GetProcessWindowStation() failed (%d)]"),
1047 ::GetLastError()));
1048 return false;
1049 }
1050
1051 if (!::GetUserObjectInformation(handle_window_station,
1052 UOI_NAME,
1053 CStrBuf(str_window_station, MAX_PATH),
1054 MAX_PATH,
1055 &len)) {
1056 UTIL_LOG(LEVEL_ERROR,
1057 (_T("[System::IsCurrentProcessInteractive - ")
1058 _T("::GetUserObjectInfoformation(hWinSta) failed (%d)]"),
1059 ::GetLastError()));
1060 return false;
1061 }
1062
1063 UTIL_LOG(L6, (_T("[System::IsCurrentProcessInteractive]")
1064 _T("[WindowStation name][%s]"),
1065 str_window_station));
1066 return (str_window_station == _T("WinSta0"));
1067 }
1068
1069 // is the current process running under WinSta0 for the currently active session
1070 bool System::IsCurrentProcessActiveAndInteractive() {
1071 return IsSessionActive(GetCurrentSessionId()) &&
1072 IsCurrentProcessInteractive();
1073 }
1074
1075 bool System::IsRunningOnBatteries() {
1076 SYSTEM_POWER_STATUS system_power_status = {0};
1077 if (::GetSystemPowerStatus(&system_power_status)) {
1078 bool has_battery = !(system_power_status.BatteryFlag & 128);
1079 bool ac_status_offline = system_power_status.ACLineStatus == 0;
1080 return ac_status_offline && has_battery;
1081 }
1082 return false;
1083 }
1084
1085 } // namespace omaha
1086
OLDNEW
« no previous file with comments | « base/system.h ('k') | base/system_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698