blob: b4e1d00f2224310c201c6f6879fe99eb12d19b3d [file] [log] [blame]
// Copyright 2007-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.
// ========================================================================
//
#include "omaha/worker/worker_com_wrapper.h"
#include <atlbase.h>
#include <atlstr.h>
#include <atlsecurity.h>
#include "omaha/common/error.h"
#include "omaha/common/exception_barrier.h"
#include "omaha/common/scope_guard.h"
#include "omaha/goopdate/google_update.h"
#include "omaha/worker/com_wrapper_shutdown_handler.h"
#include "omaha/worker/worker.h"
namespace omaha {
HRESULT OnDemandCOMClass::FinalConstruct() {
CORE_LOG(L2, (_T("[OnDemandCOMClass::FinalConstruct]")));
GoogleUpdate* google_update = static_cast<GoogleUpdate*>(_pAtlModule);
worker_ = google_update->worker();
ASSERT1(worker_);
HRESULT hr = worker_->InitializeThreadPool();
if (FAILED(hr)) {
return hr;
}
// For update checks on machine applications where the user is not an
// administrator, the COM server will shutdown automatically after it returns
// from a COM method invocation. Two reasons for this policy:
// * Only update checks on a machine app can be done as a non-admin user. To
// call Update requires an elevated instance of the COM server. So this COM
// server is useless after the UpdateCheck call.
// * Listening on the shutdown handler requires admin privileges.
bool shutdown_after_invocation = worker_->is_machine() && !::IsUserAnAdmin();
worker_->set_shutdown_callback(new WorkerComWrapperShutdownCallBack(
shutdown_after_invocation));
return shutdown_after_invocation ?
S_OK :
worker_->InitializeShutDownHandler(worker_->shutdown_callback());
}
void OnDemandCOMClass::FinalRelease() {
CORE_LOG(L2, (_T("[OnDemandCOMClass::FinalRelease]")));
worker_ = NULL;
}
void OnDemandCOMClass::AddRefIgnoreShutdownEvent() const {
CORE_LOG(L2, (_T("[OnDemandCOMClass::AddRefIgnoreShutdownEvent]")));
ASSERT1(worker_);
WorkerComWrapperShutdownCallBack* callback = worker_->shutdown_callback();
ASSERT1(callback);
callback->AddRefIgnoreShutdown();
}
void OnDemandCOMClass::ResetStateOnError() const {
CORE_LOG(L2, (_T("[OnDemandCOMClass::ResetStateOnError]")));
ASSERT1(worker_);
WorkerComWrapperShutdownCallBack* callback = worker_->shutdown_callback();
ASSERT1(callback);
callback->ReleaseIgnoreShutdown();
}
HRESULT OnDemandCOMClass::DoOnDemand(bool is_update_check_only,
const WCHAR* guid,
IJobObserver* observer) {
CORE_LOG(L2, (_T("[OnDemandCOMClass::DoOnDemand][%d][%s][%d]"),
is_update_check_only, guid, observer));
// The exception barrier is needed, because any exceptions that are thrown
// in this method will get caught by the COM run time. We compile with
// exceptions off, and do not expect to throw any exceptions. This barrier
// will treat an exception in this method as a unhandled exception.
ExceptionBarrier barrier;
ASSERT1(guid);
ASSERT1(observer);
if (!guid || StringToGuid(guid) == GUID_NULL || !observer) {
return E_INVALIDARG;
}
AddRefIgnoreShutdownEvent();
// Ensure that the reset method is called in all error cases.
ScopeGuard guard = MakeObjGuard(*this, &OnDemandCOMClass::ResetStateOnError);
HRESULT hr = worker_->DoOnDemand(guid,
CString(),
observer,
is_update_check_only);
if (FAILED(hr)) {
OPT_LOG(LE, (_T("[DoOnDemand failed][0x%08x]"), hr));
return hr;
}
// Dismiss the scope guard, since the DoOnDemand succeeded and the worker job
// thread is now responsible for the cleanup.
guard.Dismiss();
return S_OK;
}
STDMETHODIMP OnDemandCOMClass::Update(const WCHAR* guid,
IJobObserver* observer) {
return DoOnDemand(false, guid, observer);
}
STDMETHODIMP OnDemandCOMClass::CheckForUpdate(const WCHAR* guid,
IJobObserver* observer) {
return DoOnDemand(true, guid, observer);
}
} // namespace omaha