| Index: base/registry_monitor_manager.cc
|
| diff --git a/base/registry_monitor_manager.cc b/base/registry_monitor_manager.cc
|
| deleted file mode 100644
|
| index e57d7dee2fc69530799a18fe1fb22fa9fab796db..0000000000000000000000000000000000000000
|
| --- a/base/registry_monitor_manager.cc
|
| +++ /dev/null
|
| @@ -1,586 +0,0 @@
|
| -// Copyright 2008-2009 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -//
|
| -// RegistryMonitor creates a KeyWatcher for every unique registry key that
|
| -// contains a value registered by MonitorValue. Each KeyWatcher is responsible
|
| -// for monitoring one or more values in a single registry key but not its
|
| -// subkeys. RegistryMonitor manages a thread which waits on event objects.
|
| -// The events are signaled when the corresponding monitored key changes.
|
| -
|
| -#include "omaha/base/registry_monitor_manager.h"
|
| -#include <atlbase.h>
|
| -#include <utility>
|
| -#include <vector>
|
| -#include "omaha/base/debug.h"
|
| -#include "omaha/base/error.h"
|
| -#include "omaha/base/logging.h"
|
| -#include "omaha/base/reg_key.h"
|
| -#include "omaha/base/scoped_any.h"
|
| -#include "omaha/base/synchronized.h"
|
| -#include "omaha/base/thread.h"
|
| -
|
| -namespace omaha {
|
| -
|
| -namespace detail {
|
| -
|
| -// converts a registry change type value to a string for logging purposes.
|
| -CString RegistryChangeTypeToString(RegistryChangeType registry_change_type) {
|
| - switch (registry_change_type) {
|
| - case REGISTRY_CHANGE_TYPE_CREATE:
|
| - return _T("create");
|
| - case REGISTRY_CHANGE_TYPE_UPDATE:
|
| - return _T("update");
|
| - case REGISTRY_CHANGE_TYPE_DELETE:
|
| - return _T("delete");
|
| - default:
|
| - ASSERT1(false);
|
| - return _T("unknown");
|
| - }
|
| -};
|
| -
|
| -// Holds a pair of root key and sub key, as monitoring must be unique for
|
| -// each pair.
|
| -class KeyId {
|
| - public:
|
| - KeyId(HKEY parent_key, const CString& key_name)
|
| - : parent_key_(parent_key), key_name_(key_name) {}
|
| -
|
| - HKEY parent_key() const { return parent_key_; }
|
| - CString key_name() const { return key_name_; }
|
| -
|
| - static bool IsEqual(const KeyId& id1, const KeyId& id2) {
|
| - return id1.parent_key_ == id2.parent_key_ &&
|
| - id1.key_name_ == id2.key_name_;
|
| - }
|
| - private:
|
| - HKEY parent_key_;
|
| - CString key_name_;
|
| -};
|
| -
|
| -class KeyWatcher;
|
| -
|
| -// ValueWatcher represents a single monitored registry value.
|
| -// It is used by KeyWatcher to determine which registry value has changed when
|
| -// it detects a change in its key.
|
| -class ValueWatcher {
|
| - public:
|
| - ValueWatcher(KeyWatcher* key_watcher,
|
| - const CString& value_name,
|
| - int value_type,
|
| - RegistryValueChangeCallback callback,
|
| - void* user_data);
|
| - ~ValueWatcher();
|
| -
|
| - // Returns true if the initial value has changed.
|
| - bool HasChanged();
|
| -
|
| - // Calls the callback function to do the notification of the change.
|
| - void DoCallback();
|
| -
|
| - private:
|
| - CString GetCurrentValueString();
|
| - DWORD GetCurrentValueDword();
|
| -
|
| - CString last_known_value_string_;
|
| - DWORD last_known_value_dword_;
|
| - bool value_is_valid_;
|
| - RegistryChangeType change_type_;
|
| - CString value_name_;
|
| - int value_type_;
|
| - KeyWatcher* key_watcher_;
|
| - RegistryValueChangeCallback callback_;
|
| - void* callback_param_;
|
| -};
|
| -
|
| -
|
| -// KeyWatcher is responsible for monitoring changes to a single key in the
|
| -// Windows registry. RegistryMonitor keeps a container of KeyWatcher objects,
|
| -// one object for each key that contains a value to be monitored.
|
| -class KeyWatcher {
|
| - public:
|
| - explicit KeyWatcher(const KeyId& key_id);
|
| -
|
| - ~KeyWatcher();
|
| -
|
| - // Adds a new registry value to monitor.
|
| - HRESULT AddValue(const CString& value_name,
|
| - int value_type,
|
| - RegistryValueChangeCallback callback,
|
| - void* user_data);
|
| -
|
| - // Registers the key watcher with the OS and gets ready to receive events.
|
| - HRESULT StartWatching();
|
| -
|
| - // Returns true if the underlying registry handle corresponds to a valid key.
|
| - bool IsKeyValid();
|
| -
|
| - HANDLE notification_event() const { return get(notification_event_); }
|
| -
|
| - RegKey& key() { return key_; }
|
| -
|
| - CString key_name() const { return key_id_.key_name(); }
|
| -
|
| - void set_callback(RegistryKeyChangeCallback callback, void* callback_param) {
|
| - callback_ = callback;
|
| - callback_param_ = callback_param;
|
| - }
|
| -
|
| - // Callback called when the notification event is signaled by the OS
|
| - // as a result of a change in the monitored key.
|
| - void HandleEvent(HANDLE handle);
|
| -
|
| - private:
|
| - // Ensures the key to monitor is always open.
|
| - HRESULT EnsureOpen();
|
| -
|
| - std::vector<ValueWatcher*> values_;
|
| - RegKey key_;
|
| - const KeyId key_id_;
|
| - scoped_event notification_event_;
|
| -
|
| - RegistryKeyChangeCallback callback_;
|
| - void* callback_param_;
|
| -
|
| - DISALLOW_EVIL_CONSTRUCTORS(KeyWatcher);
|
| -};
|
| -
|
| -class RegistryMonitorImpl : public Runnable {
|
| - public:
|
| - RegistryMonitorImpl();
|
| - ~RegistryMonitorImpl();
|
| -
|
| - HRESULT MonitorKey(HKEY root_key,
|
| - const CString& sub_key,
|
| - RegistryKeyChangeCallback callback,
|
| - void* user_data);
|
| -
|
| - HRESULT MonitorValue(HKEY root_key,
|
| - const CString& sub_key,
|
| - const CString& value_name,
|
| - int value_type,
|
| - RegistryValueChangeCallback callback,
|
| - void* user_data);
|
| -
|
| - HRESULT Initialize();
|
| -
|
| - HRESULT StartMonitoring();
|
| -
|
| - private:
|
| -
|
| - // Runnable.
|
| - virtual void Run();
|
| -
|
| - typedef std::pair<KeyId, KeyWatcher*> Watcher;
|
| - std::vector<Watcher> watchers_;
|
| -
|
| - Thread thread_;
|
| - scoped_ptr<Gate> start_monitoring_gate_;
|
| - scoped_event stop_monitoring_;
|
| - DISALLOW_EVIL_CONSTRUCTORS(RegistryMonitorImpl);
|
| -};
|
| -
|
| -
|
| -ValueWatcher::ValueWatcher(KeyWatcher* key_watcher,
|
| - const CString &value_name,
|
| - int value_type,
|
| - RegistryValueChangeCallback callback,
|
| - void* user_data)
|
| - : key_watcher_(key_watcher),
|
| - value_is_valid_(false),
|
| - change_type_(REGISTRY_CHANGE_TYPE_CREATE),
|
| - callback_(callback),
|
| - callback_param_(user_data),
|
| - value_name_(value_name),
|
| - value_type_(value_type),
|
| - last_known_value_dword_(0) {
|
| - ASSERT1(key_watcher);
|
| - ASSERT1(callback);
|
| - if (value_type_ == REG_SZ) {
|
| - last_known_value_string_ = GetCurrentValueString();
|
| - } else if (value_type_ == REG_DWORD) {
|
| - last_known_value_dword_ = GetCurrentValueDword();
|
| - } else {
|
| - ASSERT(false, (_T("value type not supported")));
|
| - }
|
| -}
|
| -
|
| -ValueWatcher::~ValueWatcher() {
|
| -}
|
| -
|
| -bool ValueWatcher::HasChanged() {
|
| - UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
|
| - _T("[key name '%s'][value '%s'][valid %d]"),
|
| - key_watcher_->key_name(), value_name_, value_is_valid_));
|
| -
|
| - const bool value_was_valid = value_is_valid_;
|
| -
|
| - bool has_changed = false;
|
| - if (value_type_ == REG_SZ) {
|
| - CString new_value = GetCurrentValueString();
|
| - has_changed = last_known_value_string_ != new_value;
|
| -
|
| - UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %s][new value %s]"),
|
| - last_known_value_string_, new_value));
|
| -
|
| - last_known_value_string_ = new_value;
|
| - } else if (value_type_ == REG_DWORD) {
|
| - DWORD new_value = GetCurrentValueDword();
|
| - has_changed = last_known_value_dword_ != new_value;
|
| -
|
| - UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %d][new value %d]"),
|
| - last_known_value_dword_, new_value));
|
| -
|
| - last_known_value_dword_ = new_value;
|
| - } else {
|
| - ASSERT(false, (_T("value type not supported")));
|
| - }
|
| -
|
| - // Detect the type of the change based on previous and current value state.
|
| - if (value_was_valid && value_is_valid_) {
|
| - change_type_ = REGISTRY_CHANGE_TYPE_UPDATE;
|
| - } else if (value_was_valid && !value_is_valid_) {
|
| - change_type_ = REGISTRY_CHANGE_TYPE_DELETE;
|
| - } else if (!value_was_valid && value_is_valid_) {
|
| - change_type_ = REGISTRY_CHANGE_TYPE_CREATE;
|
| - } else {
|
| - ASSERT1(!value_was_valid && !value_is_valid_);
|
| - }
|
| -
|
| - if (has_changed) {
|
| - UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
|
| - _T("[key name '%s'][value '%s' has changed][%s]"),
|
| - key_watcher_->key_name(), value_name_,
|
| - RegistryChangeTypeToString(change_type_)));
|
| - } else {
|
| - UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
|
| - _T("[key name '%s'][value '%s' is the same]"),
|
| - key_watcher_->key_name(), value_name_));
|
| - }
|
| -
|
| - return has_changed;
|
| -}
|
| -
|
| -CString ValueWatcher::GetCurrentValueString() {
|
| - CString value_data;
|
| - RegKey& key = key_watcher_->key();
|
| - ASSERT1(key.Key());
|
| - value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));
|
| - return value_is_valid_ ? value_data : CString();
|
| -}
|
| -
|
| -DWORD ValueWatcher::GetCurrentValueDword() {
|
| - DWORD value_data = 0;
|
| - RegKey& key = key_watcher_->key();
|
| - ASSERT1(key.Key());
|
| - value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));
|
| - return value_is_valid_ ? value_data : static_cast<DWORD>(-1);
|
| -}
|
| -
|
| -void ValueWatcher::DoCallback() {
|
| - ASSERT1(callback_ != NULL);
|
| -
|
| - const void* value = NULL;
|
| - if (value_type_ == REG_SZ) {
|
| - value = static_cast<const TCHAR*>(last_known_value_string_);
|
| - } else if (value_type_ == REG_DWORD) {
|
| - value = reinterpret_cast<void*>(last_known_value_dword_);
|
| - }
|
| -
|
| - callback_(key_watcher_->key_name(), value_name_, change_type_,
|
| - value, callback_param_);
|
| -
|
| - // If value was not valid, for example, the key was deleted or renamed, and
|
| - // it is valid after callback, update last known with the current value.
|
| - if (!value_is_valid_) {
|
| - if (value_type_ == REG_SZ) {
|
| - CString new_value = GetCurrentValueString();
|
| - if (value_is_valid_) {
|
| - last_known_value_string_ = new_value;
|
| - }
|
| - } else if (value_type_ == REG_DWORD) {
|
| - DWORD new_value = GetCurrentValueDword();
|
| - if (value_is_valid_) {
|
| - last_known_value_dword_ = new_value;
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -KeyWatcher::KeyWatcher(const KeyId& key_id)
|
| - : key_id_(key_id),
|
| - notification_event_(::CreateEvent(NULL, false, false, NULL)),
|
| - callback_(NULL),
|
| - callback_param_(NULL) {
|
| -}
|
| -
|
| -KeyWatcher::~KeyWatcher() {
|
| - for (size_t i = 0; i != values_.size(); ++i) {
|
| - delete values_[i];
|
| - }
|
| -}
|
| -
|
| -HRESULT KeyWatcher::StartWatching() {
|
| - // By this time the key could be deleted or renamed. Check if the handle
|
| - // is still valid and reopen the key if needed.
|
| - HRESULT hr = EnsureOpen();
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - ASSERT1(key_.Key());
|
| - const DWORD kNotifyFilter = REG_NOTIFY_CHANGE_NAME |
|
| - REG_NOTIFY_CHANGE_ATTRIBUTES |
|
| - REG_NOTIFY_CHANGE_LAST_SET |
|
| - REG_NOTIFY_CHANGE_SECURITY;
|
| - LONG result = ::RegNotifyChangeKeyValue(key_.Key(), false, kNotifyFilter,
|
| - get(notification_event_), true);
|
| - UTIL_LOG(L3, (_T("[KeyWatcher::StartWatching][key '%s' %s]"),
|
| - key_id_.key_name(),
|
| - result == ERROR_SUCCESS ? _T("ok") : _T("failed")));
|
| - return HRESULT_FROM_WIN32(result);
|
| -}
|
| -
|
| -HRESULT KeyWatcher::AddValue(const CString& value_name,
|
| - int value_type,
|
| - RegistryValueChangeCallback callback,
|
| - void* user_data) {
|
| - ASSERT1(callback);
|
| - HRESULT hr = EnsureOpen();
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - values_.push_back(
|
| - new ValueWatcher(this, value_name, value_type, callback, user_data));
|
| - return S_OK;
|
| -}
|
| -
|
| -void KeyWatcher::HandleEvent(HANDLE handle) {
|
| - UTIL_LOG(L3, (_T("[KeyWatcher::HandleEvent][key '%s']"), key_id_.key_name()));
|
| -
|
| - ASSERT1(handle);
|
| - ASSERT1(handle == get(notification_event_));
|
| - UNREFERENCED_PARAMETER(handle);
|
| -
|
| - // Although not documented, it seems the OS pulses the event so the event
|
| - // is never signaled at this point.
|
| - ASSERT1(::WaitForSingleObject(handle, 0) == WAIT_TIMEOUT);
|
| -
|
| - // Notify the key has changed.
|
| - if (callback_) {
|
| - callback_(key_name(), callback_param_);
|
| - }
|
| -
|
| - // Notify the values have changed.
|
| - for (size_t i = 0; i != values_.size(); ++i) {
|
| - ValueWatcher* value = values_[i];
|
| - if (value != NULL) {
|
| - if (value->HasChanged()) {
|
| - value->DoCallback();
|
| - }
|
| - }
|
| - }
|
| -
|
| - VERIFY1(SUCCEEDED(StartWatching()));
|
| -}
|
| -
|
| -HRESULT KeyWatcher::EnsureOpen() {
|
| - // Close the key if it is not valid for whatever reasons, such as it was
|
| - // deleted and recreated back.
|
| - if (!IsKeyValid()) {
|
| - UTIL_LOG(L3, (_T("[key '%s' is not valid]"), key_id_.key_name()));
|
| - VERIFY1(SUCCEEDED(key_.Close()));
|
| - }
|
| -
|
| - // Open the key if not already open or create the key if needed.
|
| - HRESULT hr = S_OK;
|
| - if (!key_.Key()) {
|
| - hr = key_.Create(key_id_.parent_key(), key_id_.key_name());
|
| - if (SUCCEEDED(hr)) {
|
| - UTIL_LOG(L3, (_T("[key '%s' has been created]"), key_id_.key_name()));
|
| - }
|
| - }
|
| - return hr;
|
| -}
|
| -
|
| -bool KeyWatcher::IsKeyValid() {
|
| - if (!key_.Key()) {
|
| - return false;
|
| - }
|
| - LONG ret = RegQueryInfoKey(key_.Key(),
|
| - NULL, NULL, NULL, NULL, NULL,
|
| - NULL, NULL, NULL, NULL, NULL, NULL);
|
| - return ret == ERROR_SUCCESS;
|
| -}
|
| -
|
| -RegistryMonitorImpl::RegistryMonitorImpl() {
|
| -}
|
| -
|
| -RegistryMonitorImpl::~RegistryMonitorImpl() {
|
| - if (stop_monitoring_) {
|
| - VERIFY1(::SetEvent(get(stop_monitoring_)));
|
| - }
|
| - VERIFY1(thread_.WaitTillExit(INFINITE));
|
| -
|
| - for (size_t i = 0; i != watchers_.size(); ++i) {
|
| - ASSERT1(watchers_[i].second);
|
| - delete watchers_[i].second;
|
| - }
|
| -}
|
| -
|
| -HRESULT RegistryMonitorImpl::Initialize() {
|
| - reset(stop_monitoring_, ::CreateEvent(NULL, true, false, NULL));
|
| - if (!stop_monitoring_) {
|
| - return HRESULTFromLastError();
|
| - }
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT RegistryMonitorImpl::MonitorKey(HKEY root_key,
|
| - const CString& sub_key,
|
| - RegistryKeyChangeCallback callback,
|
| - void* user_data) {
|
| - ASSERT1(callback);
|
| - ASSERT1(!thread_.Running());
|
| -
|
| - KeyId key_id(root_key, sub_key);
|
| - for (size_t i = 0; i != watchers_.size(); ++i) {
|
| - if (KeyId::IsEqual(watchers_[i].first, key_id)) {
|
| - watchers_[i].second->set_callback(callback, user_data);
|
| - return S_OK;
|
| - }
|
| - }
|
| - scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));
|
| - key_watcher->set_callback(callback, user_data);
|
| - Watcher watcher(key_id, key_watcher.release());
|
| - watchers_.push_back(watcher);
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT RegistryMonitorImpl::MonitorValue(
|
| - HKEY root_key, const CString& sub_key, const CString& value_name,
|
| - int value_type, RegistryValueChangeCallback callback, void* user_data) {
|
| - ASSERT1(callback);
|
| - ASSERT1(!thread_.Running());
|
| -
|
| - // Reuse an existing key watcher if there is a value already registered
|
| - // for monitoring under the respective registry key.
|
| - KeyId key_id(root_key, sub_key);
|
| - for (size_t i = 0; i != watchers_.size(); ++i) {
|
| - if (KeyId::IsEqual(watchers_[i].first, key_id)) {
|
| - return watchers_[i].second->AddValue(value_name, value_type,
|
| - callback, user_data);
|
| - }
|
| - }
|
| - scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));
|
| - HRESULT hr = key_watcher->AddValue(value_name, value_type,
|
| - callback, user_data);
|
| - if (FAILED(hr)) {
|
| - UTIL_LOG(LE, (_T("[RegistryMonitorImpl::RegisterValue failed]")
|
| - _T("[key %s][value %s][0x%x]"), sub_key, value_name, hr));
|
| - return hr;
|
| - }
|
| - Watcher watcher(key_id, key_watcher.release());
|
| - watchers_.push_back(watcher);
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT RegistryMonitorImpl::StartMonitoring() {
|
| - // Starts the thread and waits on the gate for the thread to open after
|
| - // it has registered all watchers for notifications and it is ready to
|
| - // handle notification events. The gate is only needed to synchronize the
|
| - // caller and the monitoring threads.
|
| - start_monitoring_gate_.reset(new Gate);
|
| - if (!thread_.Start(this)) {
|
| - return E_FAIL;
|
| - }
|
| - bool wait_result = start_monitoring_gate_->Wait(INFINITE);
|
| - start_monitoring_gate_.reset();
|
| - ASSERT1(wait_result);
|
| - return wait_result ? S_OK : HRESULTFromLastError();
|
| -}
|
| -
|
| -void RegistryMonitorImpl::Run() {
|
| - UTIL_LOG(L3, (_T("[started monitoring registry]")));
|
| -
|
| - const size_t kNumNotificationHandles = watchers_.size();
|
| - const size_t kNumHandles = kNumNotificationHandles + 1;
|
| - const size_t kStopMonitoringHandleIndex = kNumNotificationHandles;
|
| -
|
| - scoped_array<HANDLE> handles(new HANDLE[kNumHandles]);
|
| - for (size_t i = 0; i != watchers_.size(); ++i) {
|
| - handles[i] = watchers_[i].second->notification_event();
|
| - VERIFY1(SUCCEEDED(watchers_[i].second->StartWatching()));
|
| - }
|
| - handles[kStopMonitoringHandleIndex] = get(stop_monitoring_);
|
| -
|
| - // Open the gate and allow the RegistryMonitor::StartMonitoring call to
|
| - // to return to the caller.
|
| - ASSERT1(start_monitoring_gate_.get());
|
| - VERIFY1(start_monitoring_gate_->Open());
|
| -
|
| - for (;;) {
|
| - DWORD result = ::WaitForMultipleObjects(kNumHandles,
|
| - handles.get(),
|
| - false,
|
| - INFINITE);
|
| - COMPILE_ASSERT(0 == WAIT_OBJECT_0, invalid_wait_object_0);
|
| - ASSERT1(result < kNumHandles);
|
| - if (result < kNumHandles) {
|
| - if (result == kStopMonitoringHandleIndex) {
|
| - break;
|
| - } else {
|
| - size_t i = result - WAIT_OBJECT_0;
|
| - watchers_[i].second->HandleEvent(handles[i]);
|
| - }
|
| - }
|
| - }
|
| - UTIL_LOG(L3, (_T("[stopped monitoring registry]")));
|
| -}
|
| -
|
| -} // namespace detail
|
| -
|
| -RegistryMonitor::RegistryMonitor()
|
| - : impl_(new detail::RegistryMonitorImpl) {
|
| -}
|
| -
|
| -RegistryMonitor::~RegistryMonitor() {
|
| -}
|
| -
|
| -HRESULT RegistryMonitor::MonitorKey(HKEY root_key,
|
| - const CString& sub_key,
|
| - RegistryKeyChangeCallback callback,
|
| - void* user_data) {
|
| - return impl_->MonitorKey(root_key, sub_key, callback, user_data);
|
| -}
|
| -
|
| -HRESULT RegistryMonitor::MonitorValue(HKEY root_key,
|
| - const CString& sub_key,
|
| - const CString& value_name,
|
| - int value_type,
|
| - RegistryValueChangeCallback callback,
|
| - void* user_data) {
|
| - return impl_->MonitorValue(root_key, sub_key, value_name, value_type,
|
| - callback, user_data);
|
| -}
|
| -
|
| -HRESULT RegistryMonitor::Initialize() {
|
| - return impl_->Initialize();
|
| -}
|
| -
|
| -HRESULT RegistryMonitor::StartMonitoring() {
|
| - return impl_->StartMonitoring();
|
| -}
|
| -
|
| -} // namespace omaha
|
| -
|
|
|