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

Side by Side Diff: base/registry_monitor_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 | « base/registry_monitor_manager.h ('k') | base/registry_monitor_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 2008-2009 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 // RegistryMonitor creates a KeyWatcher for every unique registry key that
17 // contains a value registered by MonitorValue. Each KeyWatcher is responsible
18 // for monitoring one or more values in a single registry key but not its
19 // subkeys. RegistryMonitor manages a thread which waits on event objects.
20 // The events are signaled when the corresponding monitored key changes.
21
22 #include "omaha/base/registry_monitor_manager.h"
23 #include <atlbase.h>
24 #include <utility>
25 #include <vector>
26 #include "omaha/base/debug.h"
27 #include "omaha/base/error.h"
28 #include "omaha/base/logging.h"
29 #include "omaha/base/reg_key.h"
30 #include "omaha/base/scoped_any.h"
31 #include "omaha/base/synchronized.h"
32 #include "omaha/base/thread.h"
33
34 namespace omaha {
35
36 namespace detail {
37
38 // converts a registry change type value to a string for logging purposes.
39 CString RegistryChangeTypeToString(RegistryChangeType registry_change_type) {
40 switch (registry_change_type) {
41 case REGISTRY_CHANGE_TYPE_CREATE:
42 return _T("create");
43 case REGISTRY_CHANGE_TYPE_UPDATE:
44 return _T("update");
45 case REGISTRY_CHANGE_TYPE_DELETE:
46 return _T("delete");
47 default:
48 ASSERT1(false);
49 return _T("unknown");
50 }
51 };
52
53 // Holds a pair of root key and sub key, as monitoring must be unique for
54 // each pair.
55 class KeyId {
56 public:
57 KeyId(HKEY parent_key, const CString& key_name)
58 : parent_key_(parent_key), key_name_(key_name) {}
59
60 HKEY parent_key() const { return parent_key_; }
61 CString key_name() const { return key_name_; }
62
63 static bool IsEqual(const KeyId& id1, const KeyId& id2) {
64 return id1.parent_key_ == id2.parent_key_ &&
65 id1.key_name_ == id2.key_name_;
66 }
67 private:
68 HKEY parent_key_;
69 CString key_name_;
70 };
71
72 class KeyWatcher;
73
74 // ValueWatcher represents a single monitored registry value.
75 // It is used by KeyWatcher to determine which registry value has changed when
76 // it detects a change in its key.
77 class ValueWatcher {
78 public:
79 ValueWatcher(KeyWatcher* key_watcher,
80 const CString& value_name,
81 int value_type,
82 RegistryValueChangeCallback callback,
83 void* user_data);
84 ~ValueWatcher();
85
86 // Returns true if the initial value has changed.
87 bool HasChanged();
88
89 // Calls the callback function to do the notification of the change.
90 void DoCallback();
91
92 private:
93 CString GetCurrentValueString();
94 DWORD GetCurrentValueDword();
95
96 CString last_known_value_string_;
97 DWORD last_known_value_dword_;
98 bool value_is_valid_;
99 RegistryChangeType change_type_;
100 CString value_name_;
101 int value_type_;
102 KeyWatcher* key_watcher_;
103 RegistryValueChangeCallback callback_;
104 void* callback_param_;
105 };
106
107
108 // KeyWatcher is responsible for monitoring changes to a single key in the
109 // Windows registry. RegistryMonitor keeps a container of KeyWatcher objects,
110 // one object for each key that contains a value to be monitored.
111 class KeyWatcher {
112 public:
113 explicit KeyWatcher(const KeyId& key_id);
114
115 ~KeyWatcher();
116
117 // Adds a new registry value to monitor.
118 HRESULT AddValue(const CString& value_name,
119 int value_type,
120 RegistryValueChangeCallback callback,
121 void* user_data);
122
123 // Registers the key watcher with the OS and gets ready to receive events.
124 HRESULT StartWatching();
125
126 // Returns true if the underlying registry handle corresponds to a valid key.
127 bool IsKeyValid();
128
129 HANDLE notification_event() const { return get(notification_event_); }
130
131 RegKey& key() { return key_; }
132
133 CString key_name() const { return key_id_.key_name(); }
134
135 void set_callback(RegistryKeyChangeCallback callback, void* callback_param) {
136 callback_ = callback;
137 callback_param_ = callback_param;
138 }
139
140 // Callback called when the notification event is signaled by the OS
141 // as a result of a change in the monitored key.
142 void HandleEvent(HANDLE handle);
143
144 private:
145 // Ensures the key to monitor is always open.
146 HRESULT EnsureOpen();
147
148 std::vector<ValueWatcher*> values_;
149 RegKey key_;
150 const KeyId key_id_;
151 scoped_event notification_event_;
152
153 RegistryKeyChangeCallback callback_;
154 void* callback_param_;
155
156 DISALLOW_EVIL_CONSTRUCTORS(KeyWatcher);
157 };
158
159 class RegistryMonitorImpl : public Runnable {
160 public:
161 RegistryMonitorImpl();
162 ~RegistryMonitorImpl();
163
164 HRESULT MonitorKey(HKEY root_key,
165 const CString& sub_key,
166 RegistryKeyChangeCallback callback,
167 void* user_data);
168
169 HRESULT MonitorValue(HKEY root_key,
170 const CString& sub_key,
171 const CString& value_name,
172 int value_type,
173 RegistryValueChangeCallback callback,
174 void* user_data);
175
176 HRESULT Initialize();
177
178 HRESULT StartMonitoring();
179
180 private:
181
182 // Runnable.
183 virtual void Run();
184
185 typedef std::pair<KeyId, KeyWatcher*> Watcher;
186 std::vector<Watcher> watchers_;
187
188 Thread thread_;
189 scoped_ptr<Gate> start_monitoring_gate_;
190 scoped_event stop_monitoring_;
191 DISALLOW_EVIL_CONSTRUCTORS(RegistryMonitorImpl);
192 };
193
194
195 ValueWatcher::ValueWatcher(KeyWatcher* key_watcher,
196 const CString &value_name,
197 int value_type,
198 RegistryValueChangeCallback callback,
199 void* user_data)
200 : key_watcher_(key_watcher),
201 value_is_valid_(false),
202 change_type_(REGISTRY_CHANGE_TYPE_CREATE),
203 callback_(callback),
204 callback_param_(user_data),
205 value_name_(value_name),
206 value_type_(value_type),
207 last_known_value_dword_(0) {
208 ASSERT1(key_watcher);
209 ASSERT1(callback);
210 if (value_type_ == REG_SZ) {
211 last_known_value_string_ = GetCurrentValueString();
212 } else if (value_type_ == REG_DWORD) {
213 last_known_value_dword_ = GetCurrentValueDword();
214 } else {
215 ASSERT(false, (_T("value type not supported")));
216 }
217 }
218
219 ValueWatcher::~ValueWatcher() {
220 }
221
222 bool ValueWatcher::HasChanged() {
223 UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
224 _T("[key name '%s'][value '%s'][valid %d]"),
225 key_watcher_->key_name(), value_name_, value_is_valid_));
226
227 const bool value_was_valid = value_is_valid_;
228
229 bool has_changed = false;
230 if (value_type_ == REG_SZ) {
231 CString new_value = GetCurrentValueString();
232 has_changed = last_known_value_string_ != new_value;
233
234 UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %s][new value %s]"),
235 last_known_value_string_, new_value));
236
237 last_known_value_string_ = new_value;
238 } else if (value_type_ == REG_DWORD) {
239 DWORD new_value = GetCurrentValueDword();
240 has_changed = last_known_value_dword_ != new_value;
241
242 UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %d][new value %d]"),
243 last_known_value_dword_, new_value));
244
245 last_known_value_dword_ = new_value;
246 } else {
247 ASSERT(false, (_T("value type not supported")));
248 }
249
250 // Detect the type of the change based on previous and current value state.
251 if (value_was_valid && value_is_valid_) {
252 change_type_ = REGISTRY_CHANGE_TYPE_UPDATE;
253 } else if (value_was_valid && !value_is_valid_) {
254 change_type_ = REGISTRY_CHANGE_TYPE_DELETE;
255 } else if (!value_was_valid && value_is_valid_) {
256 change_type_ = REGISTRY_CHANGE_TYPE_CREATE;
257 } else {
258 ASSERT1(!value_was_valid && !value_is_valid_);
259 }
260
261 if (has_changed) {
262 UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
263 _T("[key name '%s'][value '%s' has changed][%s]"),
264 key_watcher_->key_name(), value_name_,
265 RegistryChangeTypeToString(change_type_)));
266 } else {
267 UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
268 _T("[key name '%s'][value '%s' is the same]"),
269 key_watcher_->key_name(), value_name_));
270 }
271
272 return has_changed;
273 }
274
275 CString ValueWatcher::GetCurrentValueString() {
276 CString value_data;
277 RegKey& key = key_watcher_->key();
278 ASSERT1(key.Key());
279 value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));
280 return value_is_valid_ ? value_data : CString();
281 }
282
283 DWORD ValueWatcher::GetCurrentValueDword() {
284 DWORD value_data = 0;
285 RegKey& key = key_watcher_->key();
286 ASSERT1(key.Key());
287 value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));
288 return value_is_valid_ ? value_data : static_cast<DWORD>(-1);
289 }
290
291 void ValueWatcher::DoCallback() {
292 ASSERT1(callback_ != NULL);
293
294 const void* value = NULL;
295 if (value_type_ == REG_SZ) {
296 value = static_cast<const TCHAR*>(last_known_value_string_);
297 } else if (value_type_ == REG_DWORD) {
298 value = reinterpret_cast<void*>(last_known_value_dword_);
299 }
300
301 callback_(key_watcher_->key_name(), value_name_, change_type_,
302 value, callback_param_);
303
304 // If value was not valid, for example, the key was deleted or renamed, and
305 // it is valid after callback, update last known with the current value.
306 if (!value_is_valid_) {
307 if (value_type_ == REG_SZ) {
308 CString new_value = GetCurrentValueString();
309 if (value_is_valid_) {
310 last_known_value_string_ = new_value;
311 }
312 } else if (value_type_ == REG_DWORD) {
313 DWORD new_value = GetCurrentValueDword();
314 if (value_is_valid_) {
315 last_known_value_dword_ = new_value;
316 }
317 }
318 }
319 }
320
321 KeyWatcher::KeyWatcher(const KeyId& key_id)
322 : key_id_(key_id),
323 notification_event_(::CreateEvent(NULL, false, false, NULL)),
324 callback_(NULL),
325 callback_param_(NULL) {
326 }
327
328 KeyWatcher::~KeyWatcher() {
329 for (size_t i = 0; i != values_.size(); ++i) {
330 delete values_[i];
331 }
332 }
333
334 HRESULT KeyWatcher::StartWatching() {
335 // By this time the key could be deleted or renamed. Check if the handle
336 // is still valid and reopen the key if needed.
337 HRESULT hr = EnsureOpen();
338 if (FAILED(hr)) {
339 return hr;
340 }
341 ASSERT1(key_.Key());
342 const DWORD kNotifyFilter = REG_NOTIFY_CHANGE_NAME |
343 REG_NOTIFY_CHANGE_ATTRIBUTES |
344 REG_NOTIFY_CHANGE_LAST_SET |
345 REG_NOTIFY_CHANGE_SECURITY;
346 LONG result = ::RegNotifyChangeKeyValue(key_.Key(), false, kNotifyFilter,
347 get(notification_event_), true);
348 UTIL_LOG(L3, (_T("[KeyWatcher::StartWatching][key '%s' %s]"),
349 key_id_.key_name(),
350 result == ERROR_SUCCESS ? _T("ok") : _T("failed")));
351 return HRESULT_FROM_WIN32(result);
352 }
353
354 HRESULT KeyWatcher::AddValue(const CString& value_name,
355 int value_type,
356 RegistryValueChangeCallback callback,
357 void* user_data) {
358 ASSERT1(callback);
359 HRESULT hr = EnsureOpen();
360 if (FAILED(hr)) {
361 return hr;
362 }
363 values_.push_back(
364 new ValueWatcher(this, value_name, value_type, callback, user_data));
365 return S_OK;
366 }
367
368 void KeyWatcher::HandleEvent(HANDLE handle) {
369 UTIL_LOG(L3, (_T("[KeyWatcher::HandleEvent][key '%s']"), key_id_.key_name()));
370
371 ASSERT1(handle);
372 ASSERT1(handle == get(notification_event_));
373 UNREFERENCED_PARAMETER(handle);
374
375 // Although not documented, it seems the OS pulses the event so the event
376 // is never signaled at this point.
377 ASSERT1(::WaitForSingleObject(handle, 0) == WAIT_TIMEOUT);
378
379 // Notify the key has changed.
380 if (callback_) {
381 callback_(key_name(), callback_param_);
382 }
383
384 // Notify the values have changed.
385 for (size_t i = 0; i != values_.size(); ++i) {
386 ValueWatcher* value = values_[i];
387 if (value != NULL) {
388 if (value->HasChanged()) {
389 value->DoCallback();
390 }
391 }
392 }
393
394 VERIFY1(SUCCEEDED(StartWatching()));
395 }
396
397 HRESULT KeyWatcher::EnsureOpen() {
398 // Close the key if it is not valid for whatever reasons, such as it was
399 // deleted and recreated back.
400 if (!IsKeyValid()) {
401 UTIL_LOG(L3, (_T("[key '%s' is not valid]"), key_id_.key_name()));
402 VERIFY1(SUCCEEDED(key_.Close()));
403 }
404
405 // Open the key if not already open or create the key if needed.
406 HRESULT hr = S_OK;
407 if (!key_.Key()) {
408 hr = key_.Create(key_id_.parent_key(), key_id_.key_name());
409 if (SUCCEEDED(hr)) {
410 UTIL_LOG(L3, (_T("[key '%s' has been created]"), key_id_.key_name()));
411 }
412 }
413 return hr;
414 }
415
416 bool KeyWatcher::IsKeyValid() {
417 if (!key_.Key()) {
418 return false;
419 }
420 LONG ret = RegQueryInfoKey(key_.Key(),
421 NULL, NULL, NULL, NULL, NULL,
422 NULL, NULL, NULL, NULL, NULL, NULL);
423 return ret == ERROR_SUCCESS;
424 }
425
426 RegistryMonitorImpl::RegistryMonitorImpl() {
427 }
428
429 RegistryMonitorImpl::~RegistryMonitorImpl() {
430 if (stop_monitoring_) {
431 VERIFY1(::SetEvent(get(stop_monitoring_)));
432 }
433 VERIFY1(thread_.WaitTillExit(INFINITE));
434
435 for (size_t i = 0; i != watchers_.size(); ++i) {
436 ASSERT1(watchers_[i].second);
437 delete watchers_[i].second;
438 }
439 }
440
441 HRESULT RegistryMonitorImpl::Initialize() {
442 reset(stop_monitoring_, ::CreateEvent(NULL, true, false, NULL));
443 if (!stop_monitoring_) {
444 return HRESULTFromLastError();
445 }
446 return S_OK;
447 }
448
449 HRESULT RegistryMonitorImpl::MonitorKey(HKEY root_key,
450 const CString& sub_key,
451 RegistryKeyChangeCallback callback,
452 void* user_data) {
453 ASSERT1(callback);
454 ASSERT1(!thread_.Running());
455
456 KeyId key_id(root_key, sub_key);
457 for (size_t i = 0; i != watchers_.size(); ++i) {
458 if (KeyId::IsEqual(watchers_[i].first, key_id)) {
459 watchers_[i].second->set_callback(callback, user_data);
460 return S_OK;
461 }
462 }
463 scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));
464 key_watcher->set_callback(callback, user_data);
465 Watcher watcher(key_id, key_watcher.release());
466 watchers_.push_back(watcher);
467 return S_OK;
468 }
469
470 HRESULT RegistryMonitorImpl::MonitorValue(
471 HKEY root_key, const CString& sub_key, const CString& value_name,
472 int value_type, RegistryValueChangeCallback callback, void* user_data) {
473 ASSERT1(callback);
474 ASSERT1(!thread_.Running());
475
476 // Reuse an existing key watcher if there is a value already registered
477 // for monitoring under the respective registry key.
478 KeyId key_id(root_key, sub_key);
479 for (size_t i = 0; i != watchers_.size(); ++i) {
480 if (KeyId::IsEqual(watchers_[i].first, key_id)) {
481 return watchers_[i].second->AddValue(value_name, value_type,
482 callback, user_data);
483 }
484 }
485 scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));
486 HRESULT hr = key_watcher->AddValue(value_name, value_type,
487 callback, user_data);
488 if (FAILED(hr)) {
489 UTIL_LOG(LE, (_T("[RegistryMonitorImpl::RegisterValue failed]")
490 _T("[key %s][value %s][0x%x]"), sub_key, value_name, hr));
491 return hr;
492 }
493 Watcher watcher(key_id, key_watcher.release());
494 watchers_.push_back(watcher);
495 return S_OK;
496 }
497
498 HRESULT RegistryMonitorImpl::StartMonitoring() {
499 // Starts the thread and waits on the gate for the thread to open after
500 // it has registered all watchers for notifications and it is ready to
501 // handle notification events. The gate is only needed to synchronize the
502 // caller and the monitoring threads.
503 start_monitoring_gate_.reset(new Gate);
504 if (!thread_.Start(this)) {
505 return E_FAIL;
506 }
507 bool wait_result = start_monitoring_gate_->Wait(INFINITE);
508 start_monitoring_gate_.reset();
509 ASSERT1(wait_result);
510 return wait_result ? S_OK : HRESULTFromLastError();
511 }
512
513 void RegistryMonitorImpl::Run() {
514 UTIL_LOG(L3, (_T("[started monitoring registry]")));
515
516 const size_t kNumNotificationHandles = watchers_.size();
517 const size_t kNumHandles = kNumNotificationHandles + 1;
518 const size_t kStopMonitoringHandleIndex = kNumNotificationHandles;
519
520 scoped_array<HANDLE> handles(new HANDLE[kNumHandles]);
521 for (size_t i = 0; i != watchers_.size(); ++i) {
522 handles[i] = watchers_[i].second->notification_event();
523 VERIFY1(SUCCEEDED(watchers_[i].second->StartWatching()));
524 }
525 handles[kStopMonitoringHandleIndex] = get(stop_monitoring_);
526
527 // Open the gate and allow the RegistryMonitor::StartMonitoring call to
528 // to return to the caller.
529 ASSERT1(start_monitoring_gate_.get());
530 VERIFY1(start_monitoring_gate_->Open());
531
532 for (;;) {
533 DWORD result = ::WaitForMultipleObjects(kNumHandles,
534 handles.get(),
535 false,
536 INFINITE);
537 COMPILE_ASSERT(0 == WAIT_OBJECT_0, invalid_wait_object_0);
538 ASSERT1(result < kNumHandles);
539 if (result < kNumHandles) {
540 if (result == kStopMonitoringHandleIndex) {
541 break;
542 } else {
543 size_t i = result - WAIT_OBJECT_0;
544 watchers_[i].second->HandleEvent(handles[i]);
545 }
546 }
547 }
548 UTIL_LOG(L3, (_T("[stopped monitoring registry]")));
549 }
550
551 } // namespace detail
552
553 RegistryMonitor::RegistryMonitor()
554 : impl_(new detail::RegistryMonitorImpl) {
555 }
556
557 RegistryMonitor::~RegistryMonitor() {
558 }
559
560 HRESULT RegistryMonitor::MonitorKey(HKEY root_key,
561 const CString& sub_key,
562 RegistryKeyChangeCallback callback,
563 void* user_data) {
564 return impl_->MonitorKey(root_key, sub_key, callback, user_data);
565 }
566
567 HRESULT RegistryMonitor::MonitorValue(HKEY root_key,
568 const CString& sub_key,
569 const CString& value_name,
570 int value_type,
571 RegistryValueChangeCallback callback,
572 void* user_data) {
573 return impl_->MonitorValue(root_key, sub_key, value_name, value_type,
574 callback, user_data);
575 }
576
577 HRESULT RegistryMonitor::Initialize() {
578 return impl_->Initialize();
579 }
580
581 HRESULT RegistryMonitor::StartMonitoring() {
582 return impl_->StartMonitoring();
583 }
584
585 } // namespace omaha
586
OLDNEW
« no previous file with comments | « base/registry_monitor_manager.h ('k') | base/registry_monitor_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698