| Index: goopdate/app_command.cc
|
| diff --git a/goopdate/app_command.cc b/goopdate/app_command.cc
|
| deleted file mode 100644
|
| index 9757e1e5e34c4d4150945cce0373bc88f7dc2ed6..0000000000000000000000000000000000000000
|
| --- a/goopdate/app_command.cc
|
| +++ /dev/null
|
| @@ -1,454 +0,0 @@
|
| -// Copyright 2011 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/goopdate/app_command.h"
|
| -
|
| -#include "base/scoped_ptr.h"
|
| -#include "omaha/base/constants.h"
|
| -#include "omaha/base/debug.h"
|
| -#include "omaha/base/error.h"
|
| -#include "omaha/base/exception_barrier.h"
|
| -#include "omaha/base/reg_key.h"
|
| -#include "omaha/base/scoped_ptr_address.h"
|
| -#include "omaha/base/system.h"
|
| -#include "omaha/base/utils.h"
|
| -#include "omaha/common/config_manager.h"
|
| -#include "omaha/common/const_cmd_line.h"
|
| -#include "omaha/common/const_goopdate.h"
|
| -#include "omaha/common/ping.h"
|
| -#include "omaha/common/ping_event.h"
|
| -
|
| -namespace omaha {
|
| -
|
| -namespace {
|
| -
|
| -// Sends a single ping event to the Omaha server, synchronously.
|
| -void SendPing(const CString& app_guid,
|
| - bool is_machine,
|
| - const CString& session_id,
|
| - PingEvent::Types type,
|
| - PingEvent::Results result,
|
| - int error_code,
|
| - int extra_code) {
|
| - PingEventPtr ping_event(new PingEvent(type, result, error_code, extra_code));
|
| -
|
| - Ping ping(is_machine, session_id, kCmdLineInstallSource_OneClick);
|
| - std::vector<CString> apps;
|
| - apps.push_back(app_guid);
|
| - ping.LoadAppDataFromRegistry(apps);
|
| - ping.BuildAppsPing(ping_event);
|
| - ping.Send(true); // true == is_fire_and_forget
|
| -}
|
| -
|
| -// Waits on a process to exit, sends a ping based on the outcome.
|
| -// This is a COM object so that, during its lifetime, the process will not exit.
|
| -// The instance is AddRef'd in the instantiating thread and Release'd by the
|
| -// thread procedure when all work is completed.
|
| -class ATL_NO_VTABLE CompletePingSender
|
| - : public CComObjectRootEx<CComMultiThreadModel>,
|
| - public IUnknown {
|
| - public:
|
| - // Starts a wait on a process, belonging to the specified app and having the
|
| - // given reporting ID. Will send a ping when the process exits.
|
| - static void Start(const CString& app_guid,
|
| - bool is_machine,
|
| - const CString& session_id,
|
| - int reporting_id,
|
| - HANDLE process);
|
| -
|
| - BEGIN_COM_MAP(CompletePingSender)
|
| - END_COM_MAP()
|
| -
|
| - protected:
|
| - CompletePingSender();
|
| - virtual ~CompletePingSender();
|
| -
|
| - private:
|
| - static HRESULT Create(const CString& app_guid,
|
| - bool is_machine,
|
| - const CString& session_id,
|
| - int reporting_id,
|
| - HANDLE process,
|
| - CompletePingSender** sender);
|
| -
|
| - // Sends an EVENT_APP_COMMAND_COMPLETE ping with data from member
|
| - // variables and parameters.
|
| - void SendCompletePing(PingEvent::Results result, int error_code);
|
| -
|
| - // Waits for the process to exit, returning S_OK and the exit_code or the
|
| - // underlying error code if the wait fails.
|
| - HRESULT WaitForProcessExit(DWORD* exit_code);
|
| -
|
| - // Waits until the process exits or timeout occurs, then sends a ping with
|
| - // the result. parameter is the CompletePingSender instance.
|
| - static DWORD WINAPI WaitFunction(void* parameter);
|
| -
|
| - CString app_guid_;
|
| - bool is_machine_;
|
| - CString session_id_;
|
| - int reporting_id_;
|
| - scoped_process process_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(CompletePingSender);
|
| -}; // class CompletePingSender
|
| -
|
| -CompletePingSender::CompletePingSender() {
|
| -}
|
| -
|
| -HRESULT CompletePingSender::Create(const CString& app_guid,
|
| - bool is_machine,
|
| - const CString& session_id,
|
| - int reporting_id,
|
| - HANDLE process,
|
| - CompletePingSender** sender) {
|
| - ASSERT1(process && sender);
|
| -
|
| - scoped_process process_handle(process);
|
| - process = NULL;
|
| -
|
| - typedef CComObject<CompletePingSender> ComObjectCompletePingSender;
|
| -
|
| - scoped_ptr<ComObjectCompletePingSender> new_object;
|
| - HRESULT hr = ComObjectCompletePingSender::CreateInstance(address(new_object));
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - new_object->app_guid_ = app_guid;
|
| - new_object->is_machine_ = is_machine;
|
| - new_object->session_id_ = session_id;
|
| - new_object->reporting_id_ = reporting_id;
|
| - reset(new_object->process_, release(process_handle));
|
| -
|
| - new_object->AddRef();
|
| - *sender = new_object.release();
|
| - return S_OK;
|
| -}
|
| -
|
| -CompletePingSender::~CompletePingSender() {
|
| -}
|
| -
|
| -void CompletePingSender::Start(const CString& app_guid,
|
| - bool is_machine,
|
| - const CString& session_id,
|
| - int reporting_id,
|
| - HANDLE process) {
|
| - ASSERT1(process);
|
| -
|
| - scoped_process process_handle(process);
|
| - process = NULL;
|
| -
|
| - CComPtr<CompletePingSender> sender;
|
| - HRESULT hr = CompletePingSender::Create(app_guid,
|
| - is_machine,
|
| - session_id,
|
| - reporting_id,
|
| - release(process_handle),
|
| - &sender);
|
| - if (FAILED(hr)) {
|
| - CORE_LOG(LE, (_T("[failed to create CompletePingSender]"),
|
| - _T("[0x%08x]"), hr));
|
| - return;
|
| - }
|
| -
|
| - void* context =
|
| - reinterpret_cast<void *>(static_cast<CompletePingSender*>(sender));
|
| -
|
| - scoped_handle thread(::CreateThread(NULL, 0, WaitFunction, context, 0, NULL));
|
| -
|
| - if (thread) {
|
| - // In case of success, the thread is responsible for calling Release.
|
| - sender.Detach();
|
| - } else {
|
| - hr = HRESULTFromLastError();
|
| - CORE_LOG(LE, (_T("[failed to start wait thread for app command ")
|
| - _T("process exit]") _T("[0x%08x]"), hr));
|
| - sender->SendCompletePing(PingEvent::EVENT_RESULT_ERROR, hr);
|
| - }
|
| -}
|
| -
|
| -void CompletePingSender::SendCompletePing(PingEvent::Results result,
|
| - int error_code) {
|
| - SendPing(app_guid_,
|
| - is_machine_,
|
| - session_id_,
|
| - PingEvent::EVENT_APP_COMMAND_COMPLETE,
|
| - result,
|
| - error_code,
|
| - reporting_id_);
|
| -}
|
| -
|
| -HRESULT CompletePingSender::WaitForProcessExit(DWORD* exit_code) {
|
| - ASSERT1(exit_code);
|
| - if (!exit_code) {
|
| - return E_INVALIDARG;
|
| - }
|
| -
|
| - DWORD wait_result = ::WaitForSingleObject(get(process_), INFINITE);
|
| -
|
| - if (wait_result == WAIT_TIMEOUT) {
|
| - return GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT;
|
| - } else if (wait_result == WAIT_FAILED) {
|
| - return HRESULTFromLastError();
|
| - }
|
| -
|
| - ASSERT1(wait_result == WAIT_OBJECT_0);
|
| -
|
| - if (wait_result != WAIT_OBJECT_0) {
|
| - return E_UNEXPECTED;
|
| - }
|
| -
|
| - if (!::GetExitCodeProcess(get(process_), exit_code)) {
|
| - return HRESULTFromLastError();
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -DWORD WINAPI CompletePingSender::WaitFunction(void* parameter) {
|
| - scoped_co_init init_com_apt(COINIT_MULTITHREADED);
|
| - HRESULT hr = init_com_apt.hresult();
|
| - if (FAILED(hr)) {
|
| - CORE_LOG(LE, (_T("[init_com_apt failed][0x%x]"), hr));
|
| - return 0;
|
| - }
|
| -
|
| - CComPtr<CompletePingSender> instance(
|
| - reinterpret_cast<CompletePingSender*>(parameter));
|
| - DWORD exit_code = 0;
|
| - hr = instance->WaitForProcessExit(&exit_code);
|
| -
|
| - PingEvent::Results result = PingEvent::EVENT_RESULT_SUCCESS;
|
| - int error_code = 0;
|
| -
|
| - if (FAILED(hr)) {
|
| - result = PingEvent::EVENT_RESULT_ERROR;
|
| - error_code = hr;
|
| - } else {
|
| - switch (exit_code) {
|
| - case ERROR_SUCCESS_REBOOT_REQUIRED:
|
| - result = PingEvent::EVENT_RESULT_SUCCESS_REBOOT;
|
| - break;
|
| - case ERROR_SUCCESS:
|
| - result = PingEvent::EVENT_RESULT_SUCCESS;
|
| - break;
|
| - default:
|
| - result = PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER;
|
| - error_code = exit_code;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - instance->SendCompletePing(result, error_code);
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -// Attempts to read the command line from the given registry key and value.
|
| -// Logs a message in case of failure.
|
| -HRESULT ReadCommandLine(const CString& key_name,
|
| - const CString& value_name,
|
| - CString* command_line) {
|
| - HRESULT hr = RegKey::GetValue(key_name, value_name, command_line);
|
| - if (FAILED(hr)) {
|
| - CORE_LOG(LE, (_T("[failed to read command line]")
|
| - _T("[key %s][value %s][0x%08x]"), key_name, value_name, hr));
|
| - }
|
| -
|
| - return hr;
|
| -}
|
| -
|
| -// Checks if the specified value exists in the registry under the specified key.
|
| -// If so, attempts to read the value's DWORD contents into 'paramter'. Succeeds
|
| -// iff the value is absent or a DWORD value is successfully read.
|
| -HRESULT ReadCommandParameter(const CString& key_name,
|
| - const CString& value_name,
|
| - DWORD* parameter) {
|
| - if (!RegKey::HasValue(key_name, value_name)) {
|
| - return S_OK;
|
| - }
|
| -
|
| - HRESULT hr = RegKey::GetValue(key_name, value_name, parameter);
|
| - if (FAILED(hr)) {
|
| - CORE_LOG(LE, (_T("[failed to read command parameter]")
|
| - _T("[key %s][value %s][0x%08x]"), key_name, value_name, hr));
|
| - }
|
| -
|
| - return hr;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -AppCommand::AppCommand(const CString& app_guid,
|
| - bool is_machine,
|
| - const CString& cmd_id,
|
| - const CString& cmd_line,
|
| - bool sends_pings,
|
| - const CString& session_id,
|
| - bool is_web_accessible,
|
| - DWORD reporting_id)
|
| - : app_guid_(app_guid),
|
| - is_machine_(is_machine),
|
| - cmd_id_(cmd_id),
|
| - session_id_(session_id),
|
| - cmd_line_(cmd_line),
|
| - sends_pings_(sends_pings),
|
| - reporting_id_(reporting_id),
|
| - is_web_accessible_(is_web_accessible) {
|
| -}
|
| -
|
| -HRESULT AppCommand::Load(const CString& app_guid,
|
| - bool is_machine,
|
| - const CString& cmd_id,
|
| - const CString& session_id,
|
| - AppCommand** app_command) {
|
| - ASSERT1(app_command);
|
| -
|
| - CString cmd_line;
|
| - DWORD sends_pings = 0;
|
| - DWORD is_web_accessible = 0;
|
| - DWORD reporting_id = 0;
|
| -
|
| - ConfigManager* config_manager = ConfigManager::Instance();
|
| - CString clients_key_name = config_manager->registry_clients(is_machine);
|
| -
|
| - CString app_key_name(AppendRegKeyPath(clients_key_name, app_guid));
|
| - CString command_key_name(
|
| - AppendRegKeyPath(app_key_name, kCommandsRegKeyName, cmd_id));
|
| -
|
| - // Prefer the new layout, otherwise look for the legacy layout. See comments
|
| - // in app_command.h for description of each.
|
| - if (!RegKey::HasKey(command_key_name)) {
|
| - if (!RegKey::HasValue(app_key_name, cmd_id)) {
|
| - return GOOPDATE_E_CORE_MISSING_CMD;
|
| - }
|
| -
|
| - // Legacy command layout.
|
| - HRESULT hr = ReadCommandLine(app_key_name, cmd_id, &cmd_line);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - } else {
|
| - // New command layout.
|
| - HRESULT hr = ReadCommandLine(command_key_name, kRegValueCommandLine,
|
| - &cmd_line);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = ReadCommandParameter(command_key_name, kRegValueSendsPings,
|
| - &sends_pings);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = ReadCommandParameter(command_key_name, kRegValueWebAccessible,
|
| - &is_web_accessible);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - hr = ReadCommandParameter(command_key_name, kRegValueReportingId,
|
| - &reporting_id);
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - *app_command = new AppCommand(app_guid,
|
| - is_machine,
|
| - cmd_id,
|
| - cmd_line,
|
| - sends_pings != 0,
|
| - session_id,
|
| - is_web_accessible != 0,
|
| - reporting_id);
|
| - return S_OK;
|
| -}
|
| -
|
| -HRESULT AppCommand::Execute(HANDLE* process) const {
|
| - ASSERT1(process);
|
| - if (!process) {
|
| - return E_INVALIDARG;
|
| - }
|
| -
|
| - *process = NULL;
|
| -
|
| - CString cmd_line(cmd_line_);
|
| -
|
| - PROCESS_INFORMATION pi = {0};
|
| - HRESULT hr = System::StartProcess(NULL, cmd_line.GetBuffer(), &pi);
|
| -
|
| - if (sends_pings_) {
|
| - PingEvent::Results result = SUCCEEDED(hr) ?
|
| - PingEvent::EVENT_RESULT_SUCCESS : PingEvent::EVENT_RESULT_ERROR;
|
| -
|
| - SendPing(app_guid_,
|
| - is_machine_,
|
| - session_id_,
|
| - PingEvent::EVENT_APP_COMMAND_BEGIN,
|
| - result,
|
| - hr,
|
| - reporting_id_);
|
| - }
|
| -
|
| - if (FAILED(hr)) {
|
| - CORE_LOG(LE, (_T("[failed to launch cmd][%s][0x%08x]"), cmd_line_, hr));
|
| - return hr;
|
| - }
|
| -
|
| - ASSERT1(pi.hProcess);
|
| - VERIFY1(::CloseHandle(pi.hThread));
|
| -
|
| - *process = pi.hProcess;
|
| -
|
| - if (sends_pings_) {
|
| - StartBackgroundThread(pi.hProcess);
|
| - }
|
| -
|
| - return S_OK;
|
| -}
|
| -
|
| -// Starts a background thread with a duplicate of the process handle.
|
| -// We need to duplicate the handle because the original handle will be returned
|
| -// to the client.
|
| -void AppCommand::StartBackgroundThread(HANDLE command_process) const {
|
| - HANDLE duplicate_process = NULL;
|
| -
|
| - // This is a pseudo handle that need not be closed.
|
| - HANDLE this_process_handle = ::GetCurrentProcess();
|
| -
|
| - if (::DuplicateHandle(this_process_handle, command_process,
|
| - this_process_handle, &duplicate_process,
|
| - NULL, false, DUPLICATE_SAME_ACCESS)) {
|
| - CompletePingSender::Start(app_guid_,
|
| - is_machine_,
|
| - session_id_,
|
| - reporting_id_,
|
| - duplicate_process);
|
| - } else {
|
| - CORE_LOG(LE, (_T("[failed call to DuplicateHandle][0x%08x]"),
|
| - HRESULTFromLastError()));
|
| - SendPing(app_guid_,
|
| - is_machine_,
|
| - session_id_,
|
| - PingEvent::EVENT_APP_COMMAND_COMPLETE,
|
| - PingEvent::EVENT_RESULT_ERROR,
|
| - HRESULTFromLastError(),
|
| - reporting_id_);
|
| - }
|
| -}
|
| -
|
| -} // namespace omaha
|
|
|