OLD | NEW |
| (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 | |
OLD | NEW |