GuestImpl.cpp revision 0229ec87789aab83ed0595b9ad5151351778e2cf
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson/* $Id$ */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson/** @file
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * VirtualBox COM class implementation
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson/*
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * Copyright (C) 2006-2010 Oracle Corporation
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac *
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * This file is part of VirtualBox Open Source Edition (OSE), as
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * available from http://www.virtualbox.org. This file is free software;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * you can redistribute it and/or modify it under the terms of the GNU
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * General Public License (GPL) as published by the Free Software
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * Foundation, in version 2 as it comes in the "COPYING" file of the
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8cf870d281dc8c242f083d14dfef05f24aa5fceeJnRouvignac */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include "GuestImpl.h"
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include "Global.h"
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include "ConsoleImpl.h"
94e4fd51556092f22a664c3c8080cb4688f09140sin#include "ProgressImpl.h"
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include "VMMDev.h"
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter#include "AutoCaller.h"
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include "Logging.h"
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include <VBox/VMMDev.h>
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#ifdef VBOX_WITH_GUEST_CONTROL
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson# include <VBox/com/array.h>
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift#endif
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include <iprt/cpp/utils.h>
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include <iprt/getopt.h>
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#include <VBox/pgm.h>
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift// defines
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift/////////////////////////////////////////////////////////////////////////////
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift// constructor / destructor
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson/////////////////////////////////////////////////////////////////////////////
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonDEFINE_EMPTY_CTOR_DTOR (Guest)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonHRESULT Guest::FinalConstruct()
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson{
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson return S_OK;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson}
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftvoid Guest::FinalRelease()
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift uninit ();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson// public methods only for internal purposes
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson/////////////////////////////////////////////////////////////////////////////
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson/**
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * Initializes the guest object.
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonHRESULT Guest::init (Console *aParent)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift LogFlowThisFunc(("aParent=%p\n", aParent));
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson ComAssertRet(aParent, E_INVALIDARG);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /* Enclose the state transition NotReady->InInit->Ready */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoInitSpan autoInitSpan(this);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AssertReturn(autoInitSpan.isOk(), E_FAIL);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson unconst(mParent) = aParent;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /* Confirm a successful initialization when it's the case */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson autoInitSpan.setSucceeded();
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson ULONG aMemoryBalloonSize;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (ret == S_OK)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mMemoryBalloonSize = aMemoryBalloonSize;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson else
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mMemoryBalloonSize = 0; /* Default is no ballooning */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson BOOL fPageFusionEnabled;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift ret = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (ret == S_OK)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mfPageFusionEnabled = fPageFusionEnabled;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift else
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mfPageFusionEnabled = false; /* Default is no page fusion*/
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* Clear statistics. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mCurrentGuestStat[i] = 0;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson#ifdef VBOX_WITH_GUEST_CONTROL
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* Init the context ID counter at 1000. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mNextContextID = 1000;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift#endif
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift/**
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * Uninitializes the instance and sets the ready flag to FALSE.
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * Called either from FinalRelease() or by the parent when it gets destroyed.
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftvoid Guest::uninit()
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift LogFlowThisFunc(("\n"));
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift#ifdef VBOX_WITH_GUEST_CONTROL
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* Scope write lock as much as possible. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /*
94e4fd51556092f22a664c3c8080cb4688f09140sin * Cleanup must be done *before* AutoUninitSpan to cancel all
94e4fd51556092f22a664c3c8080cb4688f09140sin * all outstanding waits in API functions (which hold AutoCaller
94e4fd51556092f22a664c3c8080cb4688f09140sin * ref counts).
94e4fd51556092f22a664c3c8080cb4688f09140sin */
94e4fd51556092f22a664c3c8080cb4688f09140sin AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /* Clean up callback data. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CallbackMapIter it;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
e595b7115481489471844679dc84222cf121a754boli destroyCtrlCallbackContext(it);
e595b7115481489471844679dc84222cf121a754boli
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* Clear process map. */
e595b7115481489471844679dc84222cf121a754boli mGuestProcessMap.clear();
e595b7115481489471844679dc84222cf121a754boli }
e595b7115481489471844679dc84222cf121a754boli#endif
e595b7115481489471844679dc84222cf121a754boli
e595b7115481489471844679dc84222cf121a754boli /* Enclose the state transition Ready->InUninit->NotReady */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoUninitSpan autoUninitSpan(this);
e595b7115481489471844679dc84222cf121a754boli if (autoUninitSpan.uninitDone())
e595b7115481489471844679dc84222cf121a754boli return;
e595b7115481489471844679dc84222cf121a754boli
e595b7115481489471844679dc84222cf121a754boli unconst(mParent) = NULL;
e595b7115481489471844679dc84222cf121a754boli}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift// IGuest properties
e595b7115481489471844679dc84222cf121a754boli/////////////////////////////////////////////////////////////////////////////
e595b7115481489471844679dc84222cf121a754boli
e595b7115481489471844679dc84222cf121a754boliSTDMETHODIMP Guest::COMGETTER(OSTypeId) (BSTR *aOSTypeId)
e595b7115481489471844679dc84222cf121a754boli{
e595b7115481489471844679dc84222cf121a754boli CheckComArgOutPointerValid(aOSTypeId);
e595b7115481489471844679dc84222cf121a754boli
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift // redirect the call to IMachine if no additions are installed
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (mData.mAdditionsVersion.isEmpty())
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return mParent->machine()->COMGETTER(OSTypeId)(aOSTypeId);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson mData.mOSTypeId.cloneTo(aOSTypeId);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
e595b7115481489471844679dc84222cf121a754boli}
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftSTDMETHODIMP Guest::COMGETTER(AdditionsRunLevel) (ULONG *aRunLevel)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aRunLevel = mData.mAdditionsRunLevel;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftSTDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CheckComArgOutPointerValid(aAdditionsVersion);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson HRESULT hr = S_OK;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if ( mData.mAdditionsVersion.isEmpty()
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /* Only try alternative way if GA are active! */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift && mData.mAdditionsRunLevel > VBoxGuestAdditionsRunLevel_None)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /*
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * If we got back an empty string from GetAdditionsVersion() we either
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * really don't have the Guest Additions version yet or the guest is running
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * older Guest Additions (< 3.2.0) which don't provide VMMDevReq_ReportGuestInfo2,
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * so get the version + revision from the (hopefully) provided guest properties
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * instead.
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Bstr addVersion;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson LONG64 u64Timestamp;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson Bstr flags;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Version"),
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift addVersion.asOutParam(), &u64Timestamp, flags.asOutParam());
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (hr == S_OK)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Bstr addRevision;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Revision"),
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift addRevision.asOutParam(), &u64Timestamp, flags.asOutParam());
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if ( hr == S_OK
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift && !addVersion.isEmpty()
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift && !addRevision.isEmpty())
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* Some Guest Additions versions had interchanged version + revision values,
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * so check if the version value at least has a dot to identify it and change
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * both values to reflect the right content. */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (!Utf8Str(addVersion).contains("."))
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Bstr addTemp = addVersion;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson addVersion = addRevision;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift addRevision = addTemp;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Bstr additionsVersion = BstrFmt("%ls r%ls",
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift addVersion.raw(), addRevision.raw());
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift additionsVersion.cloneTo(aAdditionsVersion);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /** @todo r=bird: else: Should not return failure! */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift else
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /* If getting the version + revision above fails or they simply aren't there
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * because of *really* old Guest Additions we only can report the interface
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * version to at least have something. */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson mData.mInterfaceVersion.cloneTo(aAdditionsVersion);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /** @todo r=bird: hr is still indicating failure! */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson }
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson else
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson mData.mAdditionsVersion.cloneTo(aAdditionsVersion);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson return hr;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson}
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonSTDMETHODIMP Guest::COMGETTER(SupportsSeamless) (BOOL *aSupportsSeamless)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson{
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson CheckComArgOutPointerValid(aSupportsSeamless);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoCaller autoCaller(this);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (FAILED(autoCaller.rc())) return autoCaller.rc();
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *aSupportsSeamless = mData.mSupportsSeamless;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson return S_OK;
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter}
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suterSTDMETHODIMP Guest::COMGETTER(SupportsGraphics) (BOOL *aSupportsGraphics)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson{
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson CheckComArgOutPointerValid(aSupportsGraphics);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aSupportsGraphics = mData.mSupportsGraphics;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson return S_OK;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson}
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suterBOOL Guest::isPageFusionEnabled()
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter{
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter AutoCaller autoCaller(this);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (FAILED(autoCaller.rc())) return false;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter return mfPageFusionEnabled;
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter}
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonSTDMETHODIMP Guest::COMGETTER(MemoryBalloonSize) (ULONG *aMemoryBalloonSize)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson{
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson CheckComArgOutPointerValid(aMemoryBalloonSize);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoCaller autoCaller(this);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (FAILED(autoCaller.rc())) return autoCaller.rc();
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *aMemoryBalloonSize = mMemoryBalloonSize;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson}
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonSTDMETHODIMP Guest::COMSETTER(MemoryBalloonSize) (ULONG aMemoryBalloonSize)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (FAILED(autoCaller.rc())) return autoCaller.rc();
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter
53247d28ba99538f841a13ea2cde01c3faa3ef36kenneth_suter AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /* We must be 100% sure that IMachine::COMSETTER(MemoryBalloonSize)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * does not call us back in any way! */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (ret == S_OK)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift mMemoryBalloonSize = aMemoryBalloonSize;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson /* forward the information to the VMM device */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift VMMDev *pVMMDev = mParent->getVMMDev();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (pVMMDev)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (pVMMDevPort)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift pVMMDevPort->pfnSetMemoryBalloon(pVMMDevPort, aMemoryBalloonSize);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return ret;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftSTDMETHODIMP Guest::COMGETTER(StatisticsUpdateInterval)(ULONG *aUpdateInterval)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CheckComArgOutPointerValid(aUpdateInterval);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aUpdateInterval = mStatUpdateInterval;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftSTDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval)(ULONG aUpdateInterval)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson mStatUpdateInterval = aUpdateInterval;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* forward the information to the VMM device */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson VMMDev *pVMMDev = mParent->getVMMDev();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (pVMMDev)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson {
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (pVMMDevPort)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift pVMMDevPort->pfnSetStatisticsInterval(pVMMDevPort, aUpdateInterval);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson }
94e4fd51556092f22a664c3c8080cb4688f09140sin
94e4fd51556092f22a664c3c8080cb4688f09140sin return S_OK;
94e4fd51556092f22a664c3c8080cb4688f09140sin}
94e4fd51556092f22a664c3c8080cb4688f09140sin
94e4fd51556092f22a664c3c8080cb4688f09140sinSTDMETHODIMP Guest::InternalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
94e4fd51556092f22a664c3c8080cb4688f09140sin ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemShared,
94e4fd51556092f22a664c3c8080cb4688f09140sin ULONG *aMemCache, ULONG *aPageTotal,
94e4fd51556092f22a664c3c8080cb4688f09140sin ULONG *aMemAllocTotal, ULONG *aMemFreeTotal, ULONG *aMemBalloonTotal, ULONG *aMemSharedTotal)
94e4fd51556092f22a664c3c8080cb4688f09140sin{
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aCpuUser);
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aCpuKernel);
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aCpuIdle);
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aMemTotal);
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aMemFree);
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aMemBalloon);
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aMemShared);
94e4fd51556092f22a664c3c8080cb4688f09140sin CheckComArgOutPointerValid(aMemCache);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CheckComArgOutPointerValid(aPageTotal);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CheckComArgOutPointerValid(aMemAllocTotal);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CheckComArgOutPointerValid(aMemFreeTotal);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CheckComArgOutPointerValid(aMemBalloonTotal);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift CheckComArgOutPointerValid(aMemSharedTotal);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aCpuUser = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER];
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aCpuKernel = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL];
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aCpuIdle = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE];
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemTotal = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemFree = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K); /* page (4K) -> 1KB units */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K); /* page (4K) -> 1KB units */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K); /* page (4K) -> 1KB units */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Console::SafeVMPtr pVM (mParent);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (pVM.isOk())
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal, uSharedTotal;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemFreeTotal = 0;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift int rc = PGMR3QueryVMMMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal, &uSharedTotal);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AssertRC(rc);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (rc == VINF_SUCCESS)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemAllocTotal = (ULONG)(uAllocTotal / _1K); /* bytes -> KB */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemFreeTotal = (ULONG)(uFreeTotal / _1K);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemBalloonTotal = (ULONG)(uBalloonedTotal / _1K);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemSharedTotal = (ULONG)(uSharedTotal / _1K);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* Query the missing per-VM memory statistics. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemShared = 0;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson uint64_t uTotalMem, uPrivateMem, uSharedMem, uZeroMem;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift rc = PGMR3QueryMemoryStats(pVM.raw(), &uTotalMem, &uPrivateMem, &uSharedMem, &uZeroMem);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (rc == VINF_SUCCESS)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aMemShared = (ULONG)(uSharedMem / _1K);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift else
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *aMemFreeTotal = 0;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *aMemShared = 0;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftHRESULT Guest::setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (enmType >= GUESTSTATTYPE_MAX)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return E_INVALIDARG;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson mCurrentGuestStat[enmType] = aVal;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonSTDMETHODIMP Guest::GetAdditionsStatus(ULONG aLevel, BOOL *aActive)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson HRESULT rc = S_OK;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift switch (aLevel)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson case 0: /* System */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *aActive = (mData.mAdditionsRunLevel > VBoxGuestAdditionsRunLevel_None);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift break;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift case 1: /* Userland */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aActive = (mData.mAdditionsRunLevel >= VBoxGuestAdditionsRunLevel_Userland);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift break;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift case 2: /* Desktop */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *aActive = (mData.mAdditionsRunLevel >= VBoxGuestAdditionsRunLevel_Desktop);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift break;
94e4fd51556092f22a664c3c8080cb4688f09140sin
94e4fd51556092f22a664c3c8080cb4688f09140sin default:
94e4fd51556092f22a664c3c8080cb4688f09140sin rc = setError(VBOX_E_NOT_SUPPORTED,
94e4fd51556092f22a664c3c8080cb4688f09140sin tr("Invalid status level defined: %u"), aLevel);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift break;
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return rc;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftSTDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift AutoCaller autoCaller(this);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (FAILED(autoCaller.rc())) return autoCaller.rc();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* forward the information to the VMM device */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift VMMDev *pVMMDev = mParent->getVMMDev();
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (pVMMDev)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson if (pVMMDevPort)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (!aAllowInteractiveLogon)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift pVMMDevPort->pfnSetCredentials(pVMMDevPort,
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Utf8Str(aUserName).c_str(),
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Utf8Str(aPassword).c_str(),
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift Utf8Str(aDomain).c_str(),
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift u32Flags);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return S_OK;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return setError(VBOX_E_VM_ERROR,
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift tr("VMM device is not available (is the VM running?)"));
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift#ifdef VBOX_WITH_GUEST_CONTROL
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift/**
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * Appends environment variables to the environment block. Each var=value pair is separated
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * by NULL (\0) sequence. The whole block will be stored in one blob and disassembled on the
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * guest side later to fit into the HGCM param structure.
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * @returns VBox status code.
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * @todo
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swiftint Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift{
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift int rc = VINF_SUCCESS;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift uint32_t cbLen = strlen(pszEnv);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (*ppvList)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift uint32_t cbNewLen = *pcbList + cbLen + 1; /* Include zero termination. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift char *pvTmp = (char*)RTMemRealloc(*ppvList, cbNewLen);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (NULL == pvTmp)
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift rc = VERR_NO_MEMORY;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift else
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift memcpy(pvTmp + *pcbList, pszEnv, cbLen);
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *ppvList = (void**)pvTmp;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift else
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson char *pcTmp;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (RTStrAPrintf(&pcTmp, "%s", pszEnv) > 0)
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *ppvList = (void**)pcTmp;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift /* Reset counters. */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson *pcEnv = 0;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *pcbList = 0;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift if (RT_SUCCESS(rc))
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift {
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *pcbList += cbLen + 1; /* Include zero termination. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *pcEnv += 1; /* Increase env pairs count. */
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift }
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift return rc;
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift}
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift/**
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * Static callback function for receiving updates on guest control commands
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift * from the guest. Acts as a dispatcher for the actual class instance.
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * @returns VBox status code.
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson * @todo
7185b49f58c4cdb16d035ecc45e38ec9b1cd9bd0matthew_swift *
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson */
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilsonDECLCALLBACK(int) Guest::doGuestCtrlNotification(void *pvExtension,
0218789478dbe859fd4593d9dd37360750a43893neil_a_wilson uint32_t u32Function,
void *pvParms,
uint32_t cbParms)
{
using namespace guestControl;
/*
* No locking, as this is purely a notification which does not make any
* changes to the object state.
*/
#ifdef DEBUG_andy
LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
pvExtension, u32Function, pvParms, cbParms));
#endif
ComObjPtr<Guest> pGuest = reinterpret_cast<Guest *>(pvExtension);
int rc = VINF_SUCCESS;
if (u32Function == GUEST_DISCONNECTED)
{
//LogFlowFunc(("GUEST_DISCONNECTED\n"));
PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
AssertPtr(pCBData);
AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbParms, VERR_INVALID_PARAMETER);
AssertReturn(CALLBACKDATAMAGICCLIENTDISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
rc = pGuest->notifyCtrlClientDisconnected(u32Function, pCBData);
}
else if (u32Function == GUEST_EXEC_SEND_STATUS)
{
//LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n"));
PCALLBACKDATAEXECSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvParms);
AssertPtr(pCBData);
AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER);
AssertReturn(CALLBACKDATAMAGICEXECSTATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
rc = pGuest->notifyCtrlExecStatus(u32Function, pCBData);
}
else if (u32Function == GUEST_EXEC_SEND_OUTPUT)
{
//LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
PCALLBACKDATAEXECOUT pCBData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvParms);
AssertPtr(pCBData);
AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbParms, VERR_INVALID_PARAMETER);
AssertReturn(CALLBACKDATAMAGICEXECOUT == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
rc = pGuest->notifyCtrlExecOut(u32Function, pCBData);
}
else
rc = VERR_NOT_SUPPORTED;
return rc;
}
/* Function for handling the execution start/termination notification. */
int Guest::notifyCtrlExecStatus(uint32_t u32Function,
PCALLBACKDATAEXECSTATUS pData)
{
int vrc = VINF_SUCCESS;
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
AssertPtr(pData);
CallbackMapIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID);
/* Callback can be called several times. */
if (it != mCallbackMap.end())
{
PCALLBACKDATAEXECSTATUS pCBData = (PCALLBACKDATAEXECSTATUS)it->second.pvData;
AssertPtr(pCBData);
pCBData->u32PID = pData->u32PID;
pCBData->u32Status = pData->u32Status;
pCBData->u32Flags = pData->u32Flags;
/** @todo Copy void* buffer contents! */
Utf8Str errMsg;
/* Was progress canceled before? */
BOOL fCanceled;
ComAssert(!it->second.pProgress.isNull());
if ( SUCCEEDED(it->second.pProgress->COMGETTER(Canceled)(&fCanceled))
&& !fCanceled)
{
/* Do progress handling. */
HRESULT hr;
switch (pData->u32Status)
{
case PROC_STS_STARTED:
LogRel(("Guest process (PID %u) started\n", pCBData->u32PID)); /** @todo Add process name */
hr = it->second.pProgress->SetNextOperation(BstrFmt(tr("Waiting for process to exit ...")), 1 /* Weight */);
AssertComRC(hr);
break;
case PROC_STS_TEN: /* Terminated normally. */
LogRel(("Guest process (PID %u) exited normally\n", pCBData->u32PID)); /** @todo Add process name */
hr = it->second.pProgress->notifyComplete(S_OK);
AssertComRC(hr);
LogFlowFunc(("Proccess (context ID=%u, status=%u) terminated successfully\n",
pData->hdr.u32ContextID, pData->u32Status));
break;
case PROC_STS_TEA: /* Terminated abnormally. */
LogRel(("Guest process (PID %u) terminated abnormally with exit code = %u\n",
pCBData->u32PID, pCBData->u32Flags)); /** @todo Add process name */
errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
pCBData->u32Flags);
break;
case PROC_STS_TES: /* Terminated through signal. */
LogRel(("Guest process (PID %u) terminated through signal with exit code = %u\n",
pCBData->u32PID, pCBData->u32Flags)); /** @todo Add process name */
errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
pCBData->u32Flags);
break;
case PROC_STS_TOK:
LogRel(("Guest process (PID %u) timed out and was killed\n", pCBData->u32PID)); /** @todo Add process name */
errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
break;
case PROC_STS_TOA:
LogRel(("Guest process (PID %u) timed out and could not be killed\n", pCBData->u32PID)); /** @todo Add process name */
errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
break;
case PROC_STS_DWN:
LogRel(("Guest process (PID %u) exited because system is shutting down\n", pCBData->u32PID)); /** @todo Add process name */
errMsg = Utf8StrFmt(Guest::tr("Process exited because system is shutting down"));
break;
case PROC_STS_ERROR:
LogRel(("Guest process (PID %u) could not be started because of rc=%Rrc\n",
pCBData->u32PID, pCBData->u32Flags)); /** @todo Add process name */
errMsg = Utf8StrFmt(Guest::tr("Process execution failed with rc=%Rrc"), pCBData->u32Flags);
break;
default:
vrc = VERR_INVALID_PARAMETER;
break;
}
/* Handle process map. */
/** @todo What happens on/deal with PID reuse? */
/** @todo How to deal with multiple updates at once? */
if (pCBData->u32PID > 0)
{
GuestProcessMapIter it_proc = getProcessByPID(pCBData->u32PID);
if (it_proc == mGuestProcessMap.end())
{
/* Not found, add to map. */
GuestProcess newProcess;
newProcess.mStatus = pCBData->u32Status;
newProcess.mExitCode = pCBData->u32Flags; /* Contains exit code. */
newProcess.mFlags = 0;
mGuestProcessMap[pCBData->u32PID] = newProcess;
}
else /* Update map. */
{
it_proc->second.mStatus = pCBData->u32Status;
it_proc->second.mExitCode = pCBData->u32Flags; /* Contains exit code. */
it_proc->second.mFlags = 0;
}
}
}
else
errMsg = Utf8StrFmt(Guest::tr("Process execution canceled"));
if (!it->second.pProgress->getCompleted())
{
if ( errMsg.length()
|| fCanceled) /* If canceled we have to report E_FAIL! */
{
HRESULT hr2 = it->second.pProgress->notifyComplete(VBOX_E_IPRT_ERROR,
COM_IIDOF(IGuest),
Guest::getStaticComponentName(),
"%s", errMsg.c_str());
AssertComRC(hr2);
LogFlowFunc(("Process (context ID=%u, status=%u) reported error: %s\n",
pData->hdr.u32ContextID, pData->u32Status, errMsg.c_str()));
}
}
}
else
LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
LogFlowFunc(("Returned with rc=%Rrc\n", vrc));
return vrc;
}
/* Function for handling the execution output notification. */
int Guest::notifyCtrlExecOut(uint32_t u32Function,
PCALLBACKDATAEXECOUT pData)
{
int rc = VINF_SUCCESS;
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
AssertPtr(pData);
CallbackMapIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID);
if (it != mCallbackMap.end())
{
PCALLBACKDATAEXECOUT pCBData = (CALLBACKDATAEXECOUT*)it->second.pvData;
AssertPtr(pCBData);
pCBData->u32PID = pData->u32PID;
pCBData->u32HandleId = pData->u32HandleId;
pCBData->u32Flags = pData->u32Flags;
/* Make sure we really got something! */
if ( pData->cbData
&& pData->pvData)
{
/* Allocate data buffer and copy it */
pCBData->pvData = RTMemAlloc(pData->cbData);
pCBData->cbData = pData->cbData;
AssertReturn(pCBData->pvData, VERR_NO_MEMORY);
memcpy(pCBData->pvData, pData->pvData, pData->cbData);
}
else
{
pCBData->pvData = NULL;
pCBData->cbData = 0;
}
/* Was progress canceled before? */
BOOL fCanceled;
ComAssert(!it->second.pProgress.isNull());
if (SUCCEEDED(it->second.pProgress->COMGETTER(Canceled)(&fCanceled)) && fCanceled)
{
it->second.pProgress->notifyComplete(VBOX_E_IPRT_ERROR,
COM_IIDOF(IGuest),
Guest::getStaticComponentName(),
Guest::tr("The output operation was canceled"));
}
else
it->second.pProgress->notifyComplete(S_OK);
}
else
LogFlowFunc(("Unexpected callback (magic=%u, context ID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
return rc;
}
int Guest::notifyCtrlClientDisconnected(uint32_t u32Function,
PCALLBACKDATACLIENTDISCONNECTED pData)
{
int rc = VINF_SUCCESS;
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
CallbackMapIter it = getCtrlCallbackContextByID(pData->hdr.u32ContextID);
if (it != mCallbackMap.end())
{
LogFlowFunc(("Client with context ID=%u disconnected\n", it->first));
destroyCtrlCallbackContext(it);
}
return rc;
}
Guest::CallbackMapIter Guest::getCtrlCallbackContextByID(uint32_t u32ContextID)
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
return mCallbackMap.find(u32ContextID);
}
Guest::GuestProcessMapIter Guest::getProcessByPID(uint32_t u32PID)
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
return mGuestProcessMap.find(u32PID);
}
/* No locking here; */
void Guest::destroyCtrlCallbackContext(Guest::CallbackMapIter it)
{
LogFlowFunc(("Destroying callback with CID=%u ...\n", it->first));
if (it->second.pvData)
{
RTMemFree(it->second.pvData);
it->second.pvData = NULL;
it->second.cbData = 0;
}
/* Notify outstanding waits for progress ... */
if ( it->second.pProgress
&& !it->second.pProgress.isNull())
{
LogFlowFunc(("Handling progress for CID=%u ...\n", it->first));
/*
* Assume we didn't complete to make sure we clean up even if the
* following call fails.
*/
BOOL fCompleted = FALSE;
it->second.pProgress->COMGETTER(Completed)(&fCompleted);
if (!fCompleted)
{
LogFlowFunc(("Progress of CID=%u *not* completed, cancelling ...\n", it->first));
/* Only cancel if not canceled before! */
BOOL fCanceled;
if (SUCCEEDED(it->second.pProgress->COMGETTER(Canceled)(&fCanceled)) && !fCanceled)
it->second.pProgress->Cancel();
/*
* To get waitForCompletion completed (unblocked) we have to notify it if necessary (only
* cancle won't work!). This could happen if the client thread (e.g. VBoxService, thread of a spawned process)
* is disconnecting without having the chance to sending a status message before, so we
* have to abort here to make sure the host never hangs/gets stuck while waiting for the
* progress object to become signalled.
*/
it->second.pProgress->notifyComplete(VBOX_E_IPRT_ERROR,
COM_IIDOF(IGuest),
Guest::getStaticComponentName(),
Guest::tr("The operation was canceled because client is shutting down"));
}
/*
* Do *not* NULL pProgress here, because waiting function like executeProcess()
* will still rely on this object for checking whether they have to give up!
*/
}
}
/* Adds a callback with a user provided data block and an optional progress object
* to the callback map. A callback is identified by a unique context ID which is used
* to identify a callback from the guest side. */
uint32_t Guest::addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void *pvData, uint32_t cbData, Progress *pProgress)
{
AssertPtr(pProgress);
/** @todo Put this stuff into a constructor! */
CallbackContext context;
context.mType = enmType;
context.pvData = pvData;
context.cbData = cbData;
context.pProgress = pProgress;
/* Create a new context ID and assign it. */
CallbackMapIter it;
uint32_t uNewContext = 0;
do
{
/* Create a new context ID ... */
uNewContext = ASMAtomicIncU32(&mNextContextID);
if (uNewContext == UINT32_MAX)
ASMAtomicUoWriteU32(&mNextContextID, 1000);
/* Is the context ID already used? */
it = getCtrlCallbackContextByID(uNewContext);
} while(it != mCallbackMap.end());
uint32_t nCallbacks = 0;
if ( it == mCallbackMap.end()
&& uNewContext > 0)
{
/* We apparently got an unused context ID, let's use it! */
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
mCallbackMap[uNewContext] = context;
nCallbacks = mCallbackMap.size();
}
else
{
/* Should never happen ... */
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
nCallbacks = mCallbackMap.size();
}
AssertReleaseMsg(uNewContext, ("No free context ID found! uNewContext=%u, nCallbacks=%u", uNewContext, nCallbacks));
}
#if 0
if (nCallbacks > 256) /* Don't let the container size get too big! */
{
Guest::CallbackListIter it = mCallbackList.begin();
destroyCtrlCallbackContext(it);
{
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
mCallbackList.erase(it);
}
}
#endif
return uNewContext;
}
#endif /* VBOX_WITH_GUEST_CONTROL */
STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags,
ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
IN_BSTR aUserName, IN_BSTR aPassword,
ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress)
{
/** @todo r=bird: Eventually we should clean up all the timeout parameters
* in the API and have the same way of specifying infinite waits! */
#ifndef VBOX_WITH_GUEST_CONTROL
ReturnComNotImplemented();
#else /* VBOX_WITH_GUEST_CONTROL */
using namespace guestControl;
CheckComArgStrNotEmptyOrNull(aCommand);
CheckComArgOutPointerValid(aPID);
CheckComArgOutPointerValid(aProgress);
/* Do not allow anonymous executions (with system rights). */
if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
return setError(E_INVALIDARG, tr("No user name specified"));
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
if (aFlags != 0) /* Flags are not supported at the moment. */
return E_INVALIDARG;
HRESULT rc = S_OK;
try
{
/*
* Create progress object. Note that this is a multi operation
* object to perform the following steps:
* - Operation 1 (0): Create/start process.
* - Operation 2 (1): Wait for process to exit.
* If this progress completed successfully (S_OK), the process
* started and exited normally. In any other case an error/exception
* occured.
*/
ComObjPtr <Progress> progress;
rc = progress.createObject();
if (SUCCEEDED(rc))
{
rc = progress->init(static_cast<IGuest*>(this),
BstrFmt(tr("Executing process")),
TRUE,
2, /* Number of operations. */
BstrFmt(tr("Starting process ..."))); /* Description of first stage. */
}
if (FAILED(rc)) return rc;
/*
* Prepare process execution.
*/
int vrc = VINF_SUCCESS;
Utf8Str Utf8Command(aCommand);
/* Adjust timeout */
if (aTimeoutMS == 0)
aTimeoutMS = UINT32_MAX;
/* Prepare arguments. */
char **papszArgv = NULL;
uint32_t uNumArgs = 0;
if (aArguments > 0)
{
com::SafeArray<IN_BSTR> args(ComSafeArrayInArg(aArguments));
uNumArgs = args.size();
papszArgv = (char**)RTMemAlloc(sizeof(char*) * (uNumArgs + 1));
AssertReturn(papszArgv, E_OUTOFMEMORY);
for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++)
vrc = RTUtf16ToUtf8(args[i], &papszArgv[i]);
papszArgv[uNumArgs] = NULL;
}
Utf8Str Utf8UserName(aUserName);
Utf8Str Utf8Password(aPassword);
if (RT_SUCCESS(vrc))
{
uint32_t uContextID = 0;
char *pszArgs = NULL;
if (uNumArgs > 0)
vrc = RTGetOptArgvToString(&pszArgs, papszArgv, 0);
if (RT_SUCCESS(vrc))
{
uint32_t cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
/* Prepare environment. */
void *pvEnv = NULL;
uint32_t uNumEnv = 0;
uint32_t cbEnv = 0;
if (aEnvironment > 0)
{
com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
for (unsigned i = 0; i < env.size(); i++)
{
vrc = prepareExecuteEnv(Utf8Str(env[i]).c_str(), &pvEnv, &cbEnv, &uNumEnv);
if (RT_FAILURE(vrc))
break;
}
}
LogRel(("Executing guest process \"%s\" as user \"%s\" ...\n",
Utf8Command.c_str(), Utf8UserName.c_str()));
if (RT_SUCCESS(vrc))
{
PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
AssertReturn(pData, VBOX_E_IPRT_ERROR);
RT_ZERO(*pData);
uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START,
pData, sizeof(CALLBACKDATAEXECSTATUS), progress);
Assert(uContextID > 0);
VBOXHGCMSVCPARM paParms[15];
int i = 0;
paParms[i++].setUInt32(uContextID);
paParms[i++].setPointer((void*)Utf8Command.c_str(), (uint32_t)Utf8Command.length() + 1);
paParms[i++].setUInt32(aFlags);
paParms[i++].setUInt32(uNumArgs);
paParms[i++].setPointer((void*)pszArgs, cbArgs);
paParms[i++].setUInt32(uNumEnv);
paParms[i++].setUInt32(cbEnv);
paParms[i++].setPointer((void*)pvEnv, cbEnv);
paParms[i++].setPointer((void*)Utf8UserName.c_str(), (uint32_t)Utf8UserName.length() + 1);
paParms[i++].setPointer((void*)Utf8Password.c_str(), (uint32_t)Utf8Password.length() + 1);
paParms[i++].setUInt32(aTimeoutMS);
VMMDev *vmmDev;
{
/* Make sure mParent is valid, so set the read lock while using.
* Do not keep this lock while doing the actual call, because in the meanwhile
* another thread could request a write lock which would be a bad idea ... */
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
/* Forward the information to the VMM device. */
AssertPtr(mParent);
vmmDev = mParent->getVMMDev();
}
if (vmmDev)
{
LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
i, paParms);
}
else
vrc = VERR_INVALID_VM_HANDLE;
RTMemFree(pvEnv);
}
RTStrFree(pszArgs);
}
if (RT_SUCCESS(vrc))
{
LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS));
/*
* Wait for the HGCM low level callback until the process
* has been started (or something went wrong). This is necessary to
* get the PID.
*/
CallbackMapIter it = getCtrlCallbackContextByID(uContextID);
BOOL fCanceled = FALSE;
if (it != mCallbackMap.end())
{
ComAssert(!it->second.pProgress.isNull());
/*
* Wait for the first stage (=0) to complete (that is starting the process).
*/
PCALLBACKDATAEXECSTATUS pData = NULL;
rc = it->second.pProgress->WaitForOperationCompletion(0, aTimeoutMS);
if (SUCCEEDED(rc))
{
/* Was the operation canceled by one of the parties? */
rc = it->second.pProgress->COMGETTER(Canceled)(&fCanceled);
if (FAILED(rc)) throw rc;
if (!fCanceled)
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
pData = (PCALLBACKDATAEXECSTATUS)it->second.pvData;
Assert(it->second.cbData == sizeof(CALLBACKDATAEXECSTATUS));
AssertPtr(pData);
/* Did we get some status? */
switch (pData->u32Status)
{
case PROC_STS_STARTED:
/* Process is (still) running; get PID. */
*aPID = pData->u32PID;
break;
/* In any other case the process either already
* terminated or something else went wrong, so no PID ... */
case PROC_STS_TEN: /* Terminated normally. */
case PROC_STS_TEA: /* Terminated abnormally. */
case PROC_STS_TES: /* Terminated through signal. */
case PROC_STS_TOK:
case PROC_STS_TOA:
case PROC_STS_DWN:
/*
* Process (already) ended, but we want to get the
* PID anyway to retrieve the output in a later call.
*/
*aPID = pData->u32PID;
break;
case PROC_STS_ERROR:
vrc = pData->u32Flags; /* u32Flags member contains IPRT error code. */
break;
case PROC_STS_UNDEFINED:
vrc = VERR_TIMEOUT; /* Operation did not complete within time. */
break;
default:
vrc = VERR_INVALID_PARAMETER; /* Unknown status, should never happen! */
break;
}
}
else /* Operation was canceled. */
vrc = VERR_CANCELLED;
}
else /* Operation did not complete within time. */
vrc = VERR_TIMEOUT;
/*
* Do *not* remove the callback yet - we might wait with the IProgress object on something
* else (like end of process) ...
*/
if (RT_FAILURE(vrc))
{
if (vrc == VERR_FILE_NOT_FOUND) /* This is the most likely error. */
rc = setError(VBOX_E_IPRT_ERROR,
tr("The file '%s' was not found on guest"), Utf8Command.c_str());
else if (vrc == VERR_PATH_NOT_FOUND)
rc = setError(VBOX_E_IPRT_ERROR,
tr("The path to file '%s' was not found on guest"), Utf8Command.c_str());
else if (vrc == VERR_BAD_EXE_FORMAT)
rc = setError(VBOX_E_IPRT_ERROR,
tr("The file '%s' is not an executable format on guest"), Utf8Command.c_str());
else if (vrc == VERR_AUTHENTICATION_FAILURE)
rc = setError(VBOX_E_IPRT_ERROR,
tr("The specified user '%s' was not able to logon on guest"), Utf8UserName.c_str());
else if (vrc == VERR_TIMEOUT)
rc = setError(VBOX_E_IPRT_ERROR,
tr("The guest did not respond within time (%ums)"), aTimeoutMS);
else if (vrc == VERR_CANCELLED)
rc = setError(VBOX_E_IPRT_ERROR,
tr("The execution operation was canceled"));
else if (vrc == VERR_PERMISSION_DENIED)
rc = setError(VBOX_E_IPRT_ERROR,
tr("Invalid user/password credentials"));
else
{
if (pData && pData->u32Status == PROC_STS_ERROR)
rc = setError(VBOX_E_IPRT_ERROR,
tr("Process could not be started: %Rrc"), pData->u32Flags);
else
rc = setError(E_UNEXPECTED,
tr("The service call failed with error %Rrc"), vrc);
}
}
else /* Execution went fine. */
{
/* Return the progress to the caller. */
progress.queryInterfaceTo(aProgress);
}
}
else /* Callback context not found; should never happen! */
AssertMsg(it != mCallbackMap.end(), ("Callback context with ID %u not found!", uContextID));
}
else /* HGCM related error codes .*/
{
if (vrc == VERR_INVALID_VM_HANDLE)
rc = setError(VBOX_E_VM_ERROR,
tr("VMM device is not available (is the VM running?)"));
else if (vrc == VERR_TIMEOUT)
rc = setError(VBOX_E_VM_ERROR,
tr("The guest execution service is not ready"));
else if (vrc == VERR_HGCM_SERVICE_NOT_FOUND)
rc = setError(VBOX_E_VM_ERROR,
tr("The guest execution service is not available"));
else /* HGCM call went wrong. */
rc = setError(E_UNEXPECTED,
tr("The HGCM call failed with error %Rrc"), vrc);
}
for (unsigned i = 0; i < uNumArgs; i++)
RTMemFree(papszArgv[i]);
RTMemFree(papszArgv);
}
if (RT_FAILURE(vrc))
LogRel(("Executing guest process \"%s\" as user \"%s\" failed with %Rrc\n",
Utf8Command.c_str(), Utf8UserName.c_str(), vrc));
}
catch (std::bad_alloc &)
{
rc = E_OUTOFMEMORY;
}
return rc;
#endif /* VBOX_WITH_GUEST_CONTROL */
}
STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
{
/** @todo r=bird: Eventually we should clean up all the timeout parameters
* in the API and have the same way of specifying infinite waits! */
#ifndef VBOX_WITH_GUEST_CONTROL
ReturnComNotImplemented();
#else /* VBOX_WITH_GUEST_CONTROL */
using namespace guestControl;
CheckComArgExpr(aPID, aPID > 0);
if (aSize < 0)
return setError(E_INVALIDARG, tr("The size argument (%lld) is negative"), aSize);
if (aFlags != 0) /* Flags are not supported at the moment. */
return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
HRESULT rc = S_OK;
try
{
/*
* Create progress object.
* This progress object, compared to the one in executeProgress() above,
* is only local and is used to determine whether the operation finished
* or got canceled.
*/
ComObjPtr <Progress> progress;
rc = progress.createObject();
if (SUCCEEDED(rc))
{
rc = progress->init(static_cast<IGuest*>(this),
BstrFmt(tr("Getting output of process")),
TRUE);
}
if (FAILED(rc)) return rc;
/* Adjust timeout */
if (aTimeoutMS == 0)
aTimeoutMS = UINT32_MAX;
/* Search for existing PID. */
PCALLBACKDATAEXECOUT pData = (CALLBACKDATAEXECOUT*)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT));
AssertReturn(pData, VBOX_E_IPRT_ERROR);
RT_ZERO(*pData);
uint32_t uContextID = addCtrlCallbackContext(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT,
pData, sizeof(CALLBACKDATAEXECOUT), progress);
Assert(uContextID > 0);
size_t cbData = (size_t)RT_MIN(aSize, _64K);
com::SafeArray<BYTE> outputData(cbData);
VBOXHGCMSVCPARM paParms[5];
int i = 0;
paParms[i++].setUInt32(uContextID);
paParms[i++].setUInt32(aPID);
paParms[i++].setUInt32(aFlags); /** @todo Should represent stdout and/or stderr. */
int vrc = VINF_SUCCESS;
{
VMMDev *vmmDev;
{
/* Make sure mParent is valid, so set the read lock while using.
* Do not keep this lock while doing the actual call, because in the meanwhile
* another thread could request a write lock which would be a bad idea ... */
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
/* Forward the information to the VMM device. */
AssertPtr(mParent);
vmmDev = mParent->getVMMDev();
}
if (vmmDev)
{
LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
vrc = vmmDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_GET_OUTPUT,
i, paParms);
}
}
if (RT_SUCCESS(vrc))
{
LogFlowFunc(("Waiting for HGCM callback (timeout=%ldms) ...\n", aTimeoutMS));
/*
* Wait for the HGCM low level callback until the process
* has been started (or something went wrong). This is necessary to
* get the PID.
*/
CallbackMapIter it = getCtrlCallbackContextByID(uContextID);
BOOL fCanceled = FALSE;
if (it != mCallbackMap.end())
{
ComAssert(!it->second.pProgress.isNull());
/* Wait until operation completed. */
rc = it->second.pProgress->WaitForCompletion(aTimeoutMS);
if (FAILED(rc)) throw rc;
/* Was the operation canceled by one of the parties? */
rc = it->second.pProgress->COMGETTER(Canceled)(&fCanceled);
if (FAILED(rc)) throw rc;
if (!fCanceled)
{
BOOL fCompleted;
if ( SUCCEEDED(it->second.pProgress->COMGETTER(Completed)(&fCompleted))
&& fCompleted)
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
/* Did we get some output? */
pData = (PCALLBACKDATAEXECOUT)it->second.pvData;
Assert(it->second.cbData == sizeof(CALLBACKDATAEXECOUT));
AssertPtr(pData);
if (pData->cbData)
{
/* Do we need to resize the array? */
if (pData->cbData > cbData)
outputData.resize(pData->cbData);
/* Fill output in supplied out buffer. */
memcpy(outputData.raw(), pData->pvData, pData->cbData);
outputData.resize(pData->cbData); /* Shrink to fit actual buffer size. */
}
else
vrc = VERR_NO_DATA; /* This is not an error we want to report to COM. */
}
else /* If callback not called within time ... well, that's a timeout! */
vrc = VERR_TIMEOUT;
}
else /* Operation was canceled. */
{
vrc = VERR_CANCELLED;
}
if (RT_FAILURE(vrc))
{
if (vrc == VERR_NO_DATA)
{
/* This is not an error we want to report to COM. */
rc = S_OK;
}
else if (vrc == VERR_TIMEOUT)
{
rc = setError(VBOX_E_IPRT_ERROR,
tr("The guest did not output within time (%ums)"), aTimeoutMS);
}
else if (vrc == VERR_CANCELLED)
{
rc = setError(VBOX_E_IPRT_ERROR,
tr("The output operation was canceled"));
}
else
{
rc = setError(E_UNEXPECTED,
tr("The service call failed with error %Rrc"), vrc);
}
}
{
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
/*
* Destroy locally used progress object.
*/
destroyCtrlCallbackContext(it);
}
/* Remove callback context (not used anymore). */
mCallbackMap.erase(it);
}
else /* PID lookup failed. */
rc = setError(VBOX_E_IPRT_ERROR,
tr("Process (PID %u) not found!"), aPID);
}
else /* HGCM operation failed. */
rc = setError(E_UNEXPECTED,
tr("The HGCM call failed with error %Rrc"), vrc);
/* Cleanup. */
progress->uninit();
progress.setNull();
/* If something failed (or there simply was no data, indicated by VERR_NO_DATA,
* we return an empty array so that the frontend knows when to give up. */
if (RT_FAILURE(vrc) || FAILED(rc))
outputData.resize(0);
outputData.detachTo(ComSafeArrayOutArg(aData));
}
catch (std::bad_alloc &)
{
rc = E_OUTOFMEMORY;
}
return rc;
#endif
}
STDMETHODIMP Guest::GetProcessStatus(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ULONG *aStatus)
{
#ifndef VBOX_WITH_GUEST_CONTROL
ReturnComNotImplemented();
#else /* VBOX_WITH_GUEST_CONTROL */
using namespace guestControl;
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
HRESULT rc = S_OK;
try
{
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
GuestProcessMapIterConst it = getProcessByPID(aPID);
if (it != mGuestProcessMap.end())
{
*aExitCode = it->second.mExitCode;
*aFlags = it->second.mFlags;
*aStatus = it->second.mStatus;
}
else
rc = setError(VBOX_E_IPRT_ERROR,
tr("Process (PID %u) not found!"), aPID);
}
catch (std::bad_alloc &)
{
rc = E_OUTOFMEMORY;
}
return rc;
#endif
}
// public methods only for internal purposes
/////////////////////////////////////////////////////////////////////////////
/**
* Sets the general Guest Additions information like
* API (interface) version and OS type. Gets called by
* vmmdevUpdateGuestInfo.
*
* @param aInterfaceVersion
* @param aOsType
*/
void Guest::setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType)
{
AutoCaller autoCaller(this);
AssertComRCReturnVoid (autoCaller.rc());
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
/*
* Note: The Guest Additions API (interface) version is deprecated
* and will not be used anymore! We might need it to at least report
* something as version number if *really* ancient Guest Additions are
* installed (without the guest version + revision properties having set).
*/
mData.mInterfaceVersion = aInterfaceVersion;
/*
* Older Additions rely on the Additions API version whether they
* are assumed to be active or not. Since newer Additions do report
* the Additions version *before* calling this function (by calling
* VMMDevReportGuestInfo2, VMMDevReportGuestStatus, VMMDevReportGuestInfo,
* in that order) we can tell apart old and new Additions here. Old
* Additions never would set VMMDevReportGuestInfo2 (which set mData.mAdditionsVersion)
* so they just rely on the aInterfaceVersion string (which gets set by
* VMMDevReportGuestInfo).
*
* So only mark the Additions as being active (run level = system) when we
* don't have the Additions version set.
*/
if (mData.mAdditionsVersion.isEmpty())
{
mData.mAdditionsRunLevel = aInterfaceVersion.isEmpty()
? VBoxGuestAdditionsRunLevel_None
: VBoxGuestAdditionsRunLevel_System;
}
/*
* Older Additions didn't have this finer grained capability bit,
* so enable it by default. Newer Additions will not enable this here
* and use the setSupportedFeatures function instead.
*/
mData.mSupportsGraphics = mData.mAdditionsRunLevel > VBoxGuestAdditionsRunLevel_None;
/*
* Note! There is a race going on between setting mAdditionsRunLevel and
* mSupportsGraphics here and disabling/enabling it later according to
* its real status when using new(er) Guest Additions.
*/
mData.mOSTypeId = Global::OSTypeId (aOsType);
}
/**
* Sets the Guest Additions version information details.
* Gets called by vmmdevUpdateGuestInfo2.
*
* @param aAdditionsVersion
* @param aVersionName
*/
void Guest::setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision)
{
AutoCaller autoCaller(this);
AssertComRCReturnVoid (autoCaller.rc());
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
if (!aVersionName.isEmpty())
/*
* aVersionName could be "x.y.z_BETA1_FOOBAR", so append revision manually to
* become "x.y.z_BETA1_FOOBARr12345".
*/
mData.mAdditionsVersion = BstrFmt("%ls r%ls", aVersionName.raw(), aRevision.raw());
else /* aAdditionsVersion is in x.y.zr12345 format. */
mData.mAdditionsVersion = aAdditionsVersion;
}
/**
* Sets the status of a certain Guest Additions facility.
* Gets called by vmmdevUpdateGuestStatus.
*
* @param Facility
* @param Status
* @param ulFlags
*/
void Guest::setAdditionsStatus(VBoxGuestStatusFacility Facility, VBoxGuestStatusCurrent Status, ULONG ulFlags)
{
AutoCaller autoCaller(this);
AssertComRCReturnVoid (autoCaller.rc());
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
uint32_t uCurFacility = Facility + (Status == VBoxGuestStatusCurrent_Active ? 0 : -1);
/* First check for disabled status. */
if ( Facility < VBoxGuestStatusFacility_VBoxGuestDriver
|| ( Facility == VBoxGuestStatusFacility_All
&& ( Status == VBoxGuestStatusCurrent_Inactive
|| Status == VBoxGuestStatusCurrent_Disabled
)
)
)
{
mData.mAdditionsRunLevel = VBoxGuestAdditionsRunLevel_None;
}
else if (uCurFacility >= VBoxGuestStatusFacility_VBoxTray)
{
mData.mAdditionsRunLevel = VBoxGuestAdditionsRunLevel_Desktop;
}
else if (uCurFacility >= VBoxGuestStatusFacility_VBoxService)
{
mData.mAdditionsRunLevel = VBoxGuestAdditionsRunLevel_Userland;
}
else if (uCurFacility >= VBoxGuestStatusFacility_VBoxGuestDriver)
{
mData.mAdditionsRunLevel = VBoxGuestAdditionsRunLevel_System;
}
else /* Should never happen! */
AssertMsgFailed(("Invalid facility status/run level detected! uCurFacility=%ld\n", uCurFacility));
}
/**
* Sets the supported features (and whether they are active or not).
*
* @param fCaps Guest capability bit mask (VMMDEV_GUEST_SUPPORTS_XXX).
* @param fActive No idea what this is supposed to be, it's always 0 and
* not references by this method.
*/
void Guest::setSupportedFeatures(uint32_t fCaps, uint32_t fActive)
{
AutoCaller autoCaller(this);
AssertComRCReturnVoid (autoCaller.rc());
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
mData.mSupportsSeamless = (fCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS);
/** @todo Add VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING */
mData.mSupportsGraphics = (fCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS);
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */