VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestImpl.cpp@ 70772

Last change on this file since 70772 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.9 KB
RevLine 
[9360]1/* $Id: GuestImpl.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
[1]2/** @file
[51476]3 * VirtualBox COM class implementation: Guest features.
[1]4 */
5
6/*
[69500]7 * Copyright (C) 2006-2017 Oracle Corporation
[1]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
[5999]12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
[1]16 */
17
[67914]18#define LOG_GROUP LOG_GROUP_MAIN_GUEST
19#include "LoggingNew.h"
20
[1]21#include "GuestImpl.h"
[55644]22#ifdef VBOX_WITH_GUEST_CONTROL
23# include "GuestSessionImpl.h"
24#endif
[9360]25#include "Global.h"
[1]26#include "ConsoleImpl.h"
[28132]27#include "ProgressImpl.h"
[39450]28#ifdef VBOX_WITH_DRAG_AND_DROP
[51476]29# include "GuestDnDPrivate.h"
[39450]30#endif
[1]31#include "VMMDev.h"
32
[25860]33#include "AutoCaller.h"
[40084]34#include "Performance.h"
[47294]35#include "VBoxEvents.h"
[1]36
[21219]37#include <VBox/VMMDev.h>
[25346]38#include <iprt/cpp/utils.h>
[43908]39#include <iprt/ctype.h>
40#include <iprt/stream.h>
[40084]41#include <iprt/timer.h>
[35346]42#include <VBox/vmm/pgm.h>
[39882]43#include <VBox/version.h>
[1]44
45// defines
46/////////////////////////////////////////////////////////////////////////////
47
48// constructor / destructor
49/////////////////////////////////////////////////////////////////////////////
50
[42817]51DEFINE_EMPTY_CTOR_DTOR(Guest)
[2567]52
[1]53HRESULT Guest::FinalConstruct()
54{
[35638]55 return BaseFinalConstruct();
[1]56}
57
58void Guest::FinalRelease()
59{
[42817]60 uninit();
[35638]61 BaseFinalRelease();
[1]62}
63
64// public methods only for internal purposes
65/////////////////////////////////////////////////////////////////////////////
66
67/**
68 * Initializes the guest object.
69 */
[33492]70HRESULT Guest::init(Console *aParent)
[1]71{
[21878]72 LogFlowThisFunc(("aParent=%p\n", aParent));
[1]73
[26235]74 ComAssertRet(aParent, E_INVALIDARG);
[1]75
[2567]76 /* Enclose the state transition NotReady->InInit->Ready */
[21878]77 AutoInitSpan autoInitSpan(this);
78 AssertReturn(autoInitSpan.isOk(), E_FAIL);
[1]79
[21878]80 unconst(mParent) = aParent;
[1]81
[2567]82 /* Confirm a successful initialization when it's the case */
83 autoInitSpan.setSucceeded();
84
[4529]85 ULONG aMemoryBalloonSize;
[51612]86 HRESULT hr = mParent->i_machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
[45415]87 if (hr == S_OK) /** @todo r=andy SUCCEEDED? */
[4529]88 mMemoryBalloonSize = aMemoryBalloonSize;
89 else
[45415]90 mMemoryBalloonSize = 0; /* Default is no ballooning */
[4321]91
[29589]92 BOOL fPageFusionEnabled;
[51612]93 hr = mParent->i_machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
[45415]94 if (hr == S_OK) /** @todo r=andy SUCCEEDED? */
[29589]95 mfPageFusionEnabled = fPageFusionEnabled;
96 else
[45415]97 mfPageFusionEnabled = false; /* Default is no page fusion*/
[29589]98
[45415]99 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
[40084]100 mCollectVMMStats = false;
[27896]101
102 /* Clear statistics. */
[43908]103 mNetStatRx = mNetStatTx = 0;
104 mNetStatLastTs = RTTimeNanoTS();
[27896]105 for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++)
106 mCurrentGuestStat[i] = 0;
[43908]107 mVmValidStats = pm::VMSTATMASK_NONE;
[56470]108 RT_ZERO(mCurrentGuestCpuUserStat);
109 RT_ZERO(mCurrentGuestCpuKernelStat);
110 RT_ZERO(mCurrentGuestCpuIdleStat);
[27896]111
[40084]112 mMagic = GUEST_MAGIC;
[42817]113 int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */,
[52082]114 &Guest::i_staticUpdateStats, this);
[45415]115 AssertMsgRC(vrc, ("Failed to create guest statistics update timer (%Rrc)\n", vrc));
[40084]116
[47469]117 hr = unconst(mEventSource).createObject();
118 if (SUCCEEDED(hr))
[50544]119 hr = mEventSource->init();
[45415]120
[56470]121 mCpus = 1;
122
[51476]123#ifdef VBOX_WITH_DRAG_AND_DROP
[42867]124 try
125 {
[51476]126 GuestDnD::createInstance(this /* pGuest */);
127 hr = unconst(mDnDSource).createObject();
128 if (SUCCEEDED(hr))
129 hr = mDnDSource->init(this /* pGuest */);
130 if (SUCCEEDED(hr))
131 {
132 hr = unconst(mDnDTarget).createObject();
133 if (SUCCEEDED(hr))
134 hr = mDnDTarget->init(this /* pGuest */);
135 }
136
[55180]137 LogFlowFunc(("Drag and drop initializied with hr=%Rhrc\n", hr));
[42867]138 }
[51476]139 catch (std::bad_alloc &)
[42867]140 {
[45415]141 hr = E_OUTOFMEMORY;
[42867]142 }
[51476]143#endif
[39450]144
[51476]145 LogFlowFunc(("hr=%Rhrc\n", hr));
[45415]146 return hr;
[1]147}
148
149/**
[30758]150 * Uninitializes the instance and sets the ready flag to FALSE.
151 * Called either from FinalRelease() or by the parent when it gets destroyed.
[1]152 */
153void Guest::uninit()
154{
[21878]155 LogFlowThisFunc(("\n"));
[1]156
[40020]157 /* Enclose the state transition Ready->InUninit->NotReady */
158 AutoUninitSpan autoUninitSpan(this);
159 if (autoUninitSpan.uninitDone())
160 return;
161
[40084]162 /* Destroy stat update timer */
[42817]163 int vrc = RTTimerLRDestroy(mStatTimer);
164 AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc));
[40084]165 mStatTimer = NULL;
166 mMagic = 0;
167
[42867]168#ifdef VBOX_WITH_GUEST_CONTROL
[42897]169 LogFlowThisFunc(("Closing sessions (%RU64 total)\n",
170 mData.mGuestSessions.size()));
[42867]171 GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
172 while (itSessions != mData.mGuestSessions.end())
173 {
[51476]174# ifdef DEBUG
[42897]175 ULONG cRefs = itSessions->second->AddRef();
[49389]176 LogFlowThisFunc(("sessionID=%RU32, cRefs=%RU32\n", itSessions->first, cRefs > 1 ? cRefs - 1 : 0));
[42897]177 itSessions->second->Release();
[51476]178# endif
[42897]179 itSessions->second->uninit();
[56030]180 ++itSessions;
[42867]181 }
182 mData.mGuestSessions.clear();
183#endif
184
[39450]185#ifdef VBOX_WITH_DRAG_AND_DROP
[51476]186 GuestDnD::destroyInstance();
187 unconst(mDnDSource).setNull();
188 unconst(mDnDTarget).setNull();
[39450]189#endif
190
[45415]191 unconst(mEventSource).setNull();
[27607]192 unconst(mParent) = NULL;
[42897]193
194 LogFlowFuncLeave();
[1]195}
196
[40084]197/* static */
[52082]198DECLCALLBACK(void) Guest::i_staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick)
[40084]199{
[42817]200 AssertReturnVoid(pvUser != NULL);
201 Guest *guest = static_cast<Guest *>(pvUser);
[40084]202 Assert(guest->mMagic == GUEST_MAGIC);
203 if (guest->mMagic == GUEST_MAGIC)
[52082]204 guest->i_updateStats(iTick);
[40084]205
[42817]206 NOREF(hTimerLR);
[40084]207}
208
[43908]209/* static */
[57425]210DECLCALLBACK(int) Guest::i_staticEnumStatsCallback(const char *pszName, STAMTYPE enmType, void *pvSample,
211 STAMUNIT enmUnit, STAMVISIBILITY enmVisiblity,
212 const char *pszDesc, void *pvUser)
[43908]213{
[63244]214 RT_NOREF(enmVisiblity, pszDesc);
[46456]215 AssertLogRelMsgReturn(enmType == STAMTYPE_COUNTER, ("Unexpected sample type %d ('%s')\n", enmType, pszName), VINF_SUCCESS);
216 AssertLogRelMsgReturn(enmUnit == STAMUNIT_BYTES, ("Unexpected sample unit %d ('%s')\n", enmUnit, pszName), VINF_SUCCESS);
[43908]217
[46456]218 /* Get the base name w/ slash. */
219 const char *pszLastSlash = strrchr(pszName, '/');
220 AssertLogRelMsgReturn(pszLastSlash, ("Unexpected sample '%s'\n", pszName), VINF_SUCCESS);
221
222 /* Receive or transmit? */
223 bool fRx;
224 if (!strcmp(pszLastSlash, "/BytesReceived"))
225 fRx = true;
226 else if (!strcmp(pszLastSlash, "/BytesTransmitted"))
227 fRx = false;
[43908]228 else
[46456]229 AssertLogRelMsgFailedReturn(("Unexpected sample '%s'\n", pszName), VINF_SUCCESS);
[43908]230
[46456]231#if 0 /* not used for anything, so don't bother parsing it. */
232 /* Find start of instance number. ASSUMES '/Public/Net/Name<Instance digits>/Bytes...' */
233 do
234 --pszLastSlash;
235 while (pszLastSlash > pszName && RT_C_IS_DIGIT(*pszLastSlash));
236 pszLastSlash++;
237
238 uint8_t uInstance;
239 int rc = RTStrToUInt8Ex(pszLastSlash, NULL, 10, &uInstance);
240 AssertLogRelMsgReturn(RT_SUCCESS(rc) && rc != VWRN_NUMBER_TOO_BIG && rc != VWRN_NEGATIVE_UNSIGNED,
241 ("%Rrc '%s'\n", rc, pszName), VINF_SUCCESS)
242#endif
243
244 /* Add the bytes to our counters. */
245 PSTAMCOUNTER pCnt = (PSTAMCOUNTER)pvSample;
246 Guest *pGuest = (Guest *)pvUser;
247 uint64_t cb = pCnt->c;
248#if 0
249 LogFlowFunc(("%s i=%u d=%s %llu bytes\n", pszName, uInstance, fRx ? "RX" : "TX", cb));
250#else
251 LogFlowFunc(("%s d=%s %llu bytes\n", pszName, fRx ? "RX" : "TX", cb));
252#endif
253 if (fRx)
254 pGuest->mNetStatRx += cb;
255 else
256 pGuest->mNetStatTx += cb;
257
[43908]258 return VINF_SUCCESS;
259}
260
[52082]261void Guest::i_updateStats(uint64_t iTick)
[40084]262{
[63244]263 RT_NOREF(iTick);
264
[44347]265 uint64_t cbFreeTotal = 0;
266 uint64_t cbAllocTotal = 0;
267 uint64_t cbBalloonedTotal = 0;
268 uint64_t cbSharedTotal = 0;
269 uint64_t cbSharedMem = 0;
270 ULONG uNetStatRx = 0;
271 ULONG uNetStatTx = 0;
272 ULONG aGuestStats[GUESTSTATTYPE_MAX];
273 RT_ZERO(aGuestStats);
[40084]274
275 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
276
[43908]277 ULONG validStats = mVmValidStats;
[40084]278 /* Check if we have anything to report */
279 if (validStats)
280 {
[43908]281 mVmValidStats = pm::VMSTATMASK_NONE;
[40084]282 memcpy(aGuestStats, mCurrentGuestStat, sizeof(aGuestStats));
283 }
284 alock.release();
[44347]285
[40084]286 /*
287 * Calling SessionMachine may take time as the object resides in VBoxSVC
288 * process. This is why we took a snapshot of currently collected stats
289 * and released the lock.
290 */
[45674]291 Console::SafeVMPtrQuiet ptrVM(mParent);
[44347]292 if (ptrVM.isOk())
[40084]293 {
294 int rc;
295
296 /*
297 * There is no point in collecting VM shared memory if other memory
[44903]298 * statistics are not available yet. Or is there?
[40084]299 */
300 if (validStats)
301 {
302 /* Query the missing per-VM memory statistics. */
[44347]303 uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbZeroMemIgn;
304 rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn);
[40084]305 if (rc == VINF_SUCCESS)
[43908]306 validStats |= pm::VMSTATMASK_GUEST_MEMSHARED;
[40084]307 }
308
309 if (mCollectVMMStats)
310 {
[44347]311 rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal);
[40084]312 AssertRC(rc);
313 if (rc == VINF_SUCCESS)
[44903]314 validStats |= pm::VMSTATMASK_VMM_ALLOC | pm::VMSTATMASK_VMM_FREE
315 | pm::VMSTATMASK_VMM_BALOON | pm::VMSTATMASK_VMM_SHARED;
[40084]316 }
317
[43908]318 uint64_t uRxPrev = mNetStatRx;
319 uint64_t uTxPrev = mNetStatTx;
320 mNetStatRx = mNetStatTx = 0;
[52082]321 rc = STAMR3Enum(ptrVM.rawUVM(), "/Public/Net/*/Bytes*", i_staticEnumStatsCallback, this);
[44903]322 AssertRC(rc);
323
[43908]324 uint64_t uTsNow = RTTimeNanoTS();
[44903]325 uint64_t cNsPassed = uTsNow - mNetStatLastTs;
326 if (cNsPassed >= 1000)
327 {
328 mNetStatLastTs = uTsNow;
329
330 uNetStatRx = (ULONG)((mNetStatRx - uRxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */
331 uNetStatTx = (ULONG)((mNetStatTx - uTxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */
332 validStats |= pm::VMSTATMASK_NET_RX | pm::VMSTATMASK_NET_TX;
333 LogFlowThisFunc(("Net Rx=%llu Tx=%llu Ts=%llu Delta=%llu\n", mNetStatRx, mNetStatTx, uTsNow, cNsPassed));
334 }
335 else
336 {
337 /* Can happen on resume or if we're using a non-monotonic clock
338 source for the timer and the time is adjusted. */
339 mNetStatRx = uRxPrev;
340 mNetStatTx = uTxPrev;
341 LogThisFunc(("Net Ts=%llu cNsPassed=%llu - too small interval\n", uTsNow, cNsPassed));
342 }
[40084]343 }
344
[51612]345 mParent->i_reportVmStatistics(validStats,
346 aGuestStats[GUESTSTATTYPE_CPUUSER],
347 aGuestStats[GUESTSTATTYPE_CPUKERNEL],
348 aGuestStats[GUESTSTATTYPE_CPUIDLE],
349 /* Convert the units for RAM usage stats: page (4K) -> 1KB units */
350 mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K),
351 mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K),
352 mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K),
353 (ULONG)(cbSharedMem / _1K), /* bytes -> KB */
354 mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K),
355 mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K),
356 (ULONG)(cbAllocTotal / _1K), /* bytes -> KB */
357 (ULONG)(cbFreeTotal / _1K),
358 (ULONG)(cbBalloonedTotal / _1K),
359 (ULONG)(cbSharedTotal / _1K),
360 uNetStatRx,
361 uNetStatTx);
[40084]362}
363
[1]364// IGuest properties
365/////////////////////////////////////////////////////////////////////////////
366
[52082]367HRESULT Guest::getOSTypeId(com::Utf8Str &aOSTypeId)
[1]368{
[52082]369 HRESULT hrc = S_OK;
370 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
371 if (!mData.mInterfaceVersion.isEmpty())
372 aOSTypeId = mData.mOSTypeId;
373 else
[39882]374 {
[52082]375 /* Redirect the call to IMachine if no additions are installed. */
376 ComPtr<IMachine> ptrMachine(mParent->i_machine());
377 alock.release();
378 BSTR bstr;
379 hrc = ptrMachine->COMGETTER(OSTypeId)(&bstr);
380 aOSTypeId = bstr;
[39882]381 }
382 return hrc;
[1]383}
384
[52082]385HRESULT Guest::getAdditionsRunLevel(AdditionsRunLevelType_T *aAdditionsRunLevel)
[1]386{
[25310]387 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[2567]388
[52082]389 *aAdditionsRunLevel = mData.mAdditionsRunLevel;
[2567]390
[1]391 return S_OK;
392}
393
[52082]394HRESULT Guest::getAdditionsVersion(com::Utf8Str &aAdditionsVersion)
[1]395{
[52082]396 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
397 HRESULT hrc = S_OK;
[1]398
[52082]399 /*
400 * Return the ReportGuestInfo2 version info if available.
401 */
402 if ( !mData.mAdditionsVersionNew.isEmpty()
403 || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
404 aAdditionsVersion = mData.mAdditionsVersionNew;
405 else
[39882]406 {
[31436]407 /*
[52082]408 * If we're running older guest additions (< 3.2.0) try get it from
409 * the guest properties. Detected switched around Version and
410 * Revision in early 3.1.x releases (see r57115).
[31436]411 */
[52082]412 ComPtr<IMachine> ptrMachine = mParent->i_machine();
413 alock.release(); /* No need to hold this during the IPC fun. */
414
415 Bstr bstr;
416 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam());
417 if ( SUCCEEDED(hrc)
418 && !bstr.isEmpty())
419 {
420 Utf8Str str(bstr);
421 if (str.count('.') == 0)
422 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam());
423 str = bstr;
424 if (str.count('.') != 2)
425 hrc = E_FAIL;
426 }
427
428 if (SUCCEEDED(hrc))
429 aAdditionsVersion = bstr;
[39882]430 else
[31436]431 {
[52082]432 /* Returning 1.4 is better than nothing. */
433 alock.acquire();
434 aAdditionsVersion = mData.mInterfaceVersion;
435 hrc = S_OK;
[31436]436 }
[39882]437 }
438 return hrc;
439}
440
[52082]441HRESULT Guest::getAdditionsRevision(ULONG *aAdditionsRevision)
[39882]442{
[52082]443 HRESULT hrc = S_OK;
444 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[39882]445
[52082]446 /*
447 * Return the ReportGuestInfo2 version info if available.
448 */
449 if ( !mData.mAdditionsVersionNew.isEmpty()
450 || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
451 *aAdditionsRevision = mData.mAdditionsRevision;
452 else
[39882]453 {
454 /*
[52082]455 * If we're running older guest additions (< 3.2.0) try get it from
456 * the guest properties. Detected switched around Version and
457 * Revision in early 3.1.x releases (see r57115).
[39882]458 */
[52082]459 ComPtr<IMachine> ptrMachine = mParent->i_machine();
460 alock.release(); /* No need to hold this during the IPC fun. */
461
462 Bstr bstr;
463 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam());
464 if (SUCCEEDED(hrc))
[31436]465 {
[52082]466 Utf8Str str(bstr);
467 uint32_t uRevision;
468 int vrc = RTStrToUInt32Full(str.c_str(), 0, &uRevision);
469 if (vrc != VINF_SUCCESS && str.count('.') == 2)
[39882]470 {
[52082]471 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam());
472 if (SUCCEEDED(hrc))
[39898]473 {
[52082]474 str = bstr;
475 vrc = RTStrToUInt32Full(str.c_str(), 0, &uRevision);
[39898]476 }
[39882]477 }
[52082]478 if (vrc == VINF_SUCCESS)
479 *aAdditionsRevision = uRevision;
480 else
481 hrc = VBOX_E_IPRT_ERROR;
[31436]482 }
[52082]483 if (FAILED(hrc))
484 {
485 /* Return 0 if we don't know. */
486 *aAdditionsRevision = 0;
487 hrc = S_OK;
488 }
[31436]489 }
[39882]490 return hrc;
[1]491}
492
[52082]493HRESULT Guest::getDnDSource(ComPtr<IGuestDnDSource> &aDnDSource)
[51476]494{
495#ifndef VBOX_WITH_DRAG_AND_DROP
[63418]496 RT_NOREF(aDnDSource);
[51476]497 ReturnComNotImplemented();
498#else
499 LogFlowThisFuncEnter();
500
501 /* No need to lock - lifetime constant. */
[52082]502 HRESULT hr = mDnDSource.queryInterfaceTo(aDnDSource.asOutParam());
[51476]503
504 LogFlowFuncLeaveRC(hr);
505 return hr;
506#endif /* VBOX_WITH_DRAG_AND_DROP */
507}
508
[52082]509HRESULT Guest::getDnDTarget(ComPtr<IGuestDnDTarget> &aDnDTarget)
[51476]510{
511#ifndef VBOX_WITH_DRAG_AND_DROP
[63418]512 RT_NOREF(aDnDTarget);
[51476]513 ReturnComNotImplemented();
514#else
515 LogFlowThisFuncEnter();
516
517 /* No need to lock - lifetime constant. */
[52082]518 HRESULT hr = mDnDTarget.queryInterfaceTo(aDnDTarget.asOutParam());
[51476]519
520 LogFlowFuncLeaveRC(hr);
521 return hr;
522#endif /* VBOX_WITH_DRAG_AND_DROP */
523}
524
[52082]525HRESULT Guest::getEventSource(ComPtr<IEventSource> &aEventSource)
[45426]526{
527 LogFlowThisFuncEnter();
528
[51476]529 /* No need to lock - lifetime constant. */
[52082]530 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
[45426]531
532 LogFlowFuncLeaveRC(S_OK);
533 return S_OK;
534}
535
[52082]536HRESULT Guest::getFacilities(std::vector<ComPtr<IAdditionsFacility> > &aFacilities)
[35967]537{
538 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
539
[52082]540 aFacilities.resize(mData.mFacilityMap.size());
541 size_t i = 0;
542 for (FacilityMapIter it = mData.mFacilityMap.begin(); it != mData.mFacilityMap.end(); ++it, ++i)
543 it->second.queryInterfaceTo(aFacilities[i].asOutParam());
[35967]544
545 return S_OK;
546}
547
[52082]548HRESULT Guest::getSessions(std::vector<ComPtr<IGuestSession> > &aSessions)
[42084]549{
[55644]550#ifdef VBOX_WITH_GUEST_CONTROL
[42084]551 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
552
[52082]553 aSessions.resize(mData.mGuestSessions.size());
554 size_t i = 0;
555 for (GuestSessions::iterator it = mData.mGuestSessions.begin(); it != mData.mGuestSessions.end(); ++it, ++i)
556 it->second.queryInterfaceTo(aSessions[i].asOutParam());
[42084]557
558 return S_OK;
[55644]559#else
560 ReturnComNotImplemented();
561#endif
[42084]562}
563
[52082]564BOOL Guest::i_isPageFusionEnabled()
[29589]565{
566 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
567
[31692]568 return mfPageFusionEnabled;
[29589]569}
570
[52082]571HRESULT Guest::getMemoryBalloonSize(ULONG *aMemoryBalloonSize)
[4314]572{
[25310]573 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
[4314]574
575 *aMemoryBalloonSize = mMemoryBalloonSize;
576
577 return S_OK;
578}
579
[52082]580HRESULT Guest::setMemoryBalloonSize(ULONG aMemoryBalloonSize)
[4314]581{
[25310]582 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[4318]583
[28529]584 /* We must be 100% sure that IMachine::COMSETTER(MemoryBalloonSize)
585 * does not call us back in any way! */
[51612]586 HRESULT ret = mParent->i_machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
[4513]587 if (ret == S_OK)
588 {
589 mMemoryBalloonSize = aMemoryBalloonSize;
[32851]590 /* forward the information to the VMM device */
[51612]591 VMMDev *pVMMDev = mParent->i_getVMMDev();
[32827]592 /* MUST release all locks before calling VMM device as its critsect
593 * has higher lock order than anything in Main. */
594 alock.release();
[29997]595 if (pVMMDev)
596 {
597 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
[30002]598 if (pVMMDevPort)
599 pVMMDevPort->pfnSetMemoryBalloon(pVMMDevPort, aMemoryBalloonSize);
[29997]600 }
[4513]601 }
[4318]602
[4513]603 return ret;
[4314]604}
605
[52082]606HRESULT Guest::getStatisticsUpdateInterval(ULONG *aStatisticsUpdateInterval)
[26295]607{
608 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
609
[52082]610 *aStatisticsUpdateInterval = mStatUpdateInterval;
[26295]611 return S_OK;
612}
613
[52082]614HRESULT Guest::setStatisticsUpdateInterval(ULONG aStatisticsUpdateInterval)
[26295]615{
616 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
617
[40084]618 if (mStatUpdateInterval)
[52082]619 if (aStatisticsUpdateInterval == 0)
[40084]620 RTTimerLRStop(mStatTimer);
621 else
[52082]622 RTTimerLRChangeInterval(mStatTimer, aStatisticsUpdateInterval);
[40084]623 else
[52082]624 if (aStatisticsUpdateInterval != 0)
[40084]625 {
[52082]626 RTTimerLRChangeInterval(mStatTimer, aStatisticsUpdateInterval);
[40084]627 RTTimerLRStart(mStatTimer, 0);
628 }
[52082]629 mStatUpdateInterval = aStatisticsUpdateInterval;
[32851]630 /* forward the information to the VMM device */
[51612]631 VMMDev *pVMMDev = mParent->i_getVMMDev();
[32827]632 /* MUST release all locks before calling VMM device as its critsect
633 * has higher lock order than anything in Main. */
634 alock.release();
[29997]635 if (pVMMDev)
636 {
637 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
[30002]638 if (pVMMDevPort)
[52082]639 pVMMDevPort->pfnSetStatisticsInterval(pVMMDevPort, aStatisticsUpdateInterval);
[29997]640 }
[26295]641
[27822]642 return S_OK;
[26295]643}
644
[52082]645
646HRESULT Guest::internalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
647 ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon,
648 ULONG *aMemShared, ULONG *aMemCache, ULONG *aPageTotal,
649 ULONG *aMemAllocTotal, ULONG *aMemFreeTotal,
650 ULONG *aMemBalloonTotal, ULONG *aMemSharedTotal)
[27885]651{
[27896]652 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
653
[29225]654 *aCpuUser = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER];
655 *aCpuKernel = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL];
656 *aCpuIdle = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE];
657 *aMemTotal = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
658 *aMemFree = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K); /* page (4K) -> 1KB units */
[28481]659 *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K); /* page (4K) -> 1KB units */
[29225]660 *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K); /* page (4K) -> 1KB units */
661 *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
[27896]662
[44347]663 /* Play safe or smth? */
664 *aMemAllocTotal = 0;
665 *aMemFreeTotal = 0;
666 *aMemBalloonTotal = 0;
667 *aMemSharedTotal = 0;
668 *aMemShared = 0;
669
[32827]670 /* MUST release all locks before calling any PGM statistics queries,
671 * as they are executed by EMT and that might deadlock us by VMM device
672 * activity which waits for the Guest object lock. */
673 alock.release();
[44347]674 Console::SafeVMPtr ptrVM(mParent);
675 if (!ptrVM.isOk())
[36128]676 return E_FAIL;
[28004]677
[44347]678 uint64_t cbFreeTotal, cbAllocTotal, cbBalloonedTotal, cbSharedTotal;
679 int rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal);
680 AssertRCReturn(rc, E_FAIL);
681
682 *aMemAllocTotal = (ULONG)(cbAllocTotal / _1K); /* bytes -> KB */
683 *aMemFreeTotal = (ULONG)(cbFreeTotal / _1K);
684 *aMemBalloonTotal = (ULONG)(cbBalloonedTotal / _1K);
685 *aMemSharedTotal = (ULONG)(cbSharedTotal / _1K);
686
687 /* Query the missing per-VM memory statistics. */
688 uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbSharedMem, cbZeroMemIgn;
689 rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn);
690 AssertRCReturn(rc, E_FAIL);
691 *aMemShared = (ULONG)(cbSharedMem / _1K);
692
[27885]693 return S_OK;
694}
695
[52082]696HRESULT Guest::i_setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal)
[27896]697{
[40084]698 static ULONG indexToPerfMask[] =
699 {
[43908]700 pm::VMSTATMASK_GUEST_CPUUSER,
701 pm::VMSTATMASK_GUEST_CPUKERNEL,
702 pm::VMSTATMASK_GUEST_CPUIDLE,
703 pm::VMSTATMASK_GUEST_MEMTOTAL,
704 pm::VMSTATMASK_GUEST_MEMFREE,
705 pm::VMSTATMASK_GUEST_MEMBALLOON,
706 pm::VMSTATMASK_GUEST_MEMCACHE,
707 pm::VMSTATMASK_GUEST_PAGETOTAL,
708 pm::VMSTATMASK_NONE
[40084]709 };
[27896]710 AutoCaller autoCaller(this);
711 if (FAILED(autoCaller.rc())) return autoCaller.rc();
[27885]712
[27896]713 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
714
[27930]715 if (enmType >= GUESTSTATTYPE_MAX)
[27896]716 return E_INVALIDARG;
717
[56470]718 if (aCpuId < VMM_MAX_CPU_COUNT)
719 {
720 ULONG *paCpuStats;
721 switch (enmType)
722 {
723 case GUESTSTATTYPE_CPUUSER: paCpuStats = mCurrentGuestCpuUserStat; break;
724 case GUESTSTATTYPE_CPUKERNEL: paCpuStats = mCurrentGuestCpuKernelStat; break;
725 case GUESTSTATTYPE_CPUIDLE: paCpuStats = mCurrentGuestCpuIdleStat; break;
726 default: paCpuStats = NULL; break;
727 }
728 if (paCpuStats)
729 {
730 paCpuStats[aCpuId] = aVal;
731 aVal = 0;
732 for (uint32_t i = 0; i < mCpus && i < VMM_MAX_CPU_COUNT; i++)
733 aVal += paCpuStats[i];
734 aVal /= mCpus;
735 }
736 }
737
[27896]738 mCurrentGuestStat[enmType] = aVal;
[43908]739 mVmValidStats |= indexToPerfMask[enmType];
[27896]740 return S_OK;
741}
742
[35887]743/**
744 * Returns the status of a specified Guest Additions facility.
745 *
[65120]746 * @return COM status code
747 * @param aFacility Facility to get the status from.
[35887]748 * @param aTimestamp Timestamp of last facility status update in ms (optional).
[65120]749 * @param aStatus Current status of the specified facility.
[35887]750 */
[52082]751HRESULT Guest::getFacilityStatus(AdditionsFacilityType_T aFacility, LONG64 *aTimestamp, AdditionsFacilityStatus_T *aStatus)
[35887]752{
753 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
754
755 /* Not checking for aTimestamp is intentional; it's optional. */
[52082]756 FacilityMapIterConst it = mData.mFacilityMap.find(aFacility);
[35887]757 if (it != mData.mFacilityMap.end())
758 {
[35967]759 AdditionsFacility *pFacility = it->second;
760 ComAssert(pFacility);
[50370]761 *aStatus = pFacility->i_getStatus();
[35887]762 if (aTimestamp)
[50370]763 *aTimestamp = pFacility->i_getLastUpdated();
[35887]764 }
765 else
766 {
767 /*
768 * Do not fail here -- could be that the facility never has been brought up (yet) but
769 * the host wants to have its status anyway. So just tell we don't know at this point.
770 */
771 *aStatus = AdditionsFacilityStatus_Unknown;
772 if (aTimestamp)
773 *aTimestamp = RTTimeMilliTS();
774 }
775 return S_OK;
776}
777
[52082]778HRESULT Guest::getAdditionsStatus(AdditionsRunLevelType_T aLevel, BOOL *aActive)
[32020]779{
780 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
781
782 HRESULT rc = S_OK;
783 switch (aLevel)
784 {
[32086]785 case AdditionsRunLevelType_System:
786 *aActive = (mData.mAdditionsRunLevel > AdditionsRunLevelType_None);
[32020]787 break;
788
[32086]789 case AdditionsRunLevelType_Userland:
790 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Userland);
[32020]791 break;
792
[32086]793 case AdditionsRunLevelType_Desktop:
794 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Desktop);
[32020]795 break;
796
797 default:
798 rc = setError(VBOX_E_NOT_SUPPORTED,
799 tr("Invalid status level defined: %u"), aLevel);
800 break;
801 }
802
803 return rc;
804}
[52082]805HRESULT Guest::setCredentials(const com::Utf8Str &aUserName, const com::Utf8Str &aPassword,
806 const com::Utf8Str &aDomain, BOOL aAllowInteractiveLogon)
[1]807{
[51342]808 /* Check for magic domain names which are used to pass encryption keys to the disk. */
809 if (Utf8Str(aDomain) == "@@disk")
[52082]810 return mParent->i_setDiskEncryptionKeys(aPassword);
[51342]811 else if (Utf8Str(aDomain) == "@@mem")
[1]812 {
[51342]813 /** @todo */
[51476]814 return E_NOTIMPL;
[51342]815 }
816 else
817 {
818 /* forward the information to the VMM device */
[51612]819 VMMDev *pVMMDev = mParent->i_getVMMDev();
[51342]820 if (pVMMDev)
[30002]821 {
[51342]822 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
823 if (pVMMDevPort)
824 {
825 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
826 if (!aAllowInteractiveLogon)
827 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
[51476]828
[51342]829 pVMMDevPort->pfnSetCredentials(pVMMDevPort,
[52082]830 aUserName.c_str(),
831 aPassword.c_str(),
832 aDomain.c_str(),
[51342]833 u32Flags);
834 return S_OK;
835 }
[30002]836 }
[1]837 }
[2567]838
[26186]839 return setError(VBOX_E_VM_ERROR,
840 tr("VMM device is not available (is the VM running?)"));
[1]841}
842
843// public methods only for internal purposes
844/////////////////////////////////////////////////////////////////////////////
845
[30758]846/**
847 * Sets the general Guest Additions information like
[31364]848 * API (interface) version and OS type. Gets called by
849 * vmmdevUpdateGuestInfo.
[30758]850 *
[31241]851 * @param aInterfaceVersion
[30758]852 * @param aOsType
853 */
[67793]854void Guest::i_setAdditionsInfo(const com::Utf8Str &aInterfaceVersion, VBOXOSTYPE aOsType)
[1]855{
[39890]856 RTTIMESPEC TimeSpecTS;
857 RTTimeNow(&TimeSpecTS);
858
[21878]859 AutoCaller autoCaller(this);
[33492]860 AssertComRCReturnVoid(autoCaller.rc());
[2567]861
[25310]862 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[2567]863
[39890]864
[30758]865 /*
[31241]866 * Note: The Guest Additions API (interface) version is deprecated
[31436]867 * and will not be used anymore! We might need it to at least report
868 * something as version number if *really* ancient Guest Additions are
869 * installed (without the guest version + revision properties having set).
[30758]870 */
[31436]871 mData.mInterfaceVersion = aInterfaceVersion;
[31241]872
[30758]873 /*
874 * Older Additions rely on the Additions API version whether they
[31364]875 * are assumed to be active or not. Since newer Additions do report
876 * the Additions version *before* calling this function (by calling
877 * VMMDevReportGuestInfo2, VMMDevReportGuestStatus, VMMDevReportGuestInfo,
878 * in that order) we can tell apart old and new Additions here. Old
879 * Additions never would set VMMDevReportGuestInfo2 (which set mData.mAdditionsVersion)
880 * so they just rely on the aInterfaceVersion string (which gets set by
881 * VMMDevReportGuestInfo).
882 *
[32020]883 * So only mark the Additions as being active (run level = system) when we
884 * don't have the Additions version set.
[30758]885 */
[39882]886 if (mData.mAdditionsVersionNew.isEmpty())
[32020]887 {
[32138]888 if (aInterfaceVersion.isEmpty())
889 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
890 else
[35977]891 {
[32138]892 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
[35977]893
894 /*
895 * To keep it compatible with the old Guest Additions behavior we need to set the
896 * "graphics" (feature) facility to active as soon as we got the Guest Additions
897 * interface version.
898 */
[52082]899 i_facilityUpdate(VBoxGuestFacilityType_Graphics, VBoxGuestFacilityStatus_Active, 0 /*fFlags*/, &TimeSpecTS);
[35977]900 }
[32020]901 }
902
[30758]903 /*
904 * Older Additions didn't have this finer grained capability bit,
[35907]905 * so enable it by default. Newer Additions will not enable this here
[31436]906 * and use the setSupportedFeatures function instead.
[30758]907 */
[39890]908 /** @todo r=bird: I don't get the above comment nor the code below...
909 * One talks about capability bits, the one always does something to a facility.
910 * Then there is the comment below it all, which is placed like it addresses the
911 * mOSTypeId, but talks about something which doesn't remotely like mOSTypeId...
912 *
913 * Andy, could you please try clarify and make the comments shorter and more
914 * coherent! Also, explain why this is important and what depends on it.
915 *
916 * PS. There is the VMMDEV_GUEST_SUPPORTS_GRAPHICS capability* report... It
917 * should come in pretty quickly after this update, normally.
918 */
[52082]919 i_facilityUpdate(VBoxGuestFacilityType_Graphics,
920 i_facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver)
921 ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
922 0 /*fFlags*/, &TimeSpecTS); /** @todo the timestamp isn't gonna be right here on saved state restore. */
[9360]923
[30758]924 /*
[32020]925 * Note! There is a race going on between setting mAdditionsRunLevel and
[30758]926 * mSupportsGraphics here and disabling/enabling it later according to
927 * its real status when using new(er) Guest Additions.
928 */
[55613]929 mData.mOSType = aOsType;
[39248]930 mData.mOSTypeId = Global::OSTypeId(aOsType);
[1]931}
[3582]932
[30758]933/**
[31241]934 * Sets the Guest Additions version information details.
935 *
[39882]936 * Gets called by vmmdevUpdateGuestInfo2 and vmmdevUpdateGuestInfo (to clear the
937 * state).
938 *
939 * @param a_uFullVersion VBoxGuestInfo2::additionsMajor,
940 * VBoxGuestInfo2::additionsMinor and
941 * VBoxGuestInfo2::additionsBuild combined into
942 * one value by VBOX_FULL_VERSION_MAKE.
943 *
944 * When this is 0, it's vmmdevUpdateGuestInfo
945 * calling to reset the state.
946 *
947 * @param a_pszName Build type tag and/or publisher tag, empty
948 * string if neiter of those are present.
949 * @param a_uRevision See VBoxGuestInfo2::additionsRevision.
950 * @param a_fFeatures See VBoxGuestInfo2::additionsFeatures.
[31241]951 */
[52082]952void Guest::i_setAdditionsInfo2(uint32_t a_uFullVersion, const char *a_pszName, uint32_t a_uRevision, uint32_t a_fFeatures)
[31241]953{
954 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
955
[39882]956 if (a_uFullVersion)
957 {
[52085]958 mData.mAdditionsVersionNew = Utf8StrFmt(*a_pszName ? "%u.%u.%u_%s" : "%u.%u.%u",
959 VBOX_FULL_VERSION_GET_MAJOR(a_uFullVersion),
960 VBOX_FULL_VERSION_GET_MINOR(a_uFullVersion),
961 VBOX_FULL_VERSION_GET_BUILD(a_uFullVersion),
962 a_pszName);
[39882]963 mData.mAdditionsVersionFull = a_uFullVersion;
964 mData.mAdditionsRevision = a_uRevision;
965 mData.mAdditionsFeatures = a_fFeatures;
966 }
967 else
968 {
969 Assert(!a_fFeatures && !a_uRevision && !*a_pszName);
970 mData.mAdditionsVersionNew.setNull();
971 mData.mAdditionsVersionFull = 0;
972 mData.mAdditionsRevision = 0;
973 mData.mAdditionsFeatures = 0;
974 }
[31241]975}
976
[52082]977bool Guest::i_facilityIsActive(VBoxGuestFacilityType enmFacility)
[35907]978{
[35970]979 Assert(enmFacility < INT32_MAX);
[35967]980 FacilityMapIterConst it = mData.mFacilityMap.find((AdditionsFacilityType_T)enmFacility);
981 if (it != mData.mFacilityMap.end())
982 {
983 AdditionsFacility *pFac = it->second;
[50370]984 return (pFac->i_getStatus() == AdditionsFacilityStatus_Active);
[35967]985 }
986 return false;
[35907]987}
988
[52082]989void Guest::i_facilityUpdate(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus,
990 uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS)
[35907]991{
[39890]992 AssertReturnVoid( a_enmFacility < VBoxGuestFacilityType_All
993 && a_enmFacility > VBoxGuestFacilityType_Unknown);
[35907]994
[39890]995 FacilityMapIter it = mData.mFacilityMap.find((AdditionsFacilityType_T)a_enmFacility);
[35967]996 if (it != mData.mFacilityMap.end())
997 {
998 AdditionsFacility *pFac = it->second;
[50370]999 pFac->i_update((AdditionsFacilityStatus_T)a_enmStatus, a_fFlags, a_pTimeSpecTS);
[35967]1000 }
1001 else
1002 {
[39890]1003 if (mData.mFacilityMap.size() > 64)
1004 {
1005 /* The easy way out for now. We could automatically destroy
1006 inactive facilities like VMMDev does if we like... */
1007 AssertFailedReturnVoid();
1008 }
1009
1010 ComObjPtr<AdditionsFacility> ptrFac;
1011 ptrFac.createObject();
1012 AssertReturnVoid(!ptrFac.isNull());
1013
1014 HRESULT hrc = ptrFac->init(this, (AdditionsFacilityType_T)a_enmFacility, (AdditionsFacilityStatus_T)a_enmStatus,
1015 a_fFlags, a_pTimeSpecTS);
1016 if (SUCCEEDED(hrc))
1017 mData.mFacilityMap.insert(std::make_pair((AdditionsFacilityType_T)a_enmFacility, ptrFac));
[35967]1018 }
[35907]1019}
1020
[31241]1021/**
[47294]1022 * Issued by the guest when a guest user changed its state.
1023 *
1024 * @return IPRT status code.
1025 * @param aUser Guest user name.
1026 * @param aDomain Domain of guest user account. Optional.
1027 * @param enmState New state to indicate.
[55644]1028 * @param pbDetails Pointer to state details. Optional.
[47294]1029 * @param cbDetails Size (in bytes) of state details. Pass 0 if not used.
1030 */
[52082]1031void Guest::i_onUserStateChange(Bstr aUser, Bstr aDomain, VBoxGuestUserState enmState,
[55644]1032 const uint8_t *pbDetails, uint32_t cbDetails)
[47294]1033{
[63244]1034 RT_NOREF(pbDetails, cbDetails);
[47294]1035 LogFlowThisFunc(("\n"));
1036
1037 AutoCaller autoCaller(this);
1038 AssertComRCReturnVoid(autoCaller.rc());
1039
1040 Bstr strDetails; /** @todo Implement state details here. */
1041
1042 fireGuestUserStateChangedEvent(mEventSource, aUser.raw(), aDomain.raw(),
1043 (GuestUserState_T)enmState, strDetails.raw());
1044 LogFlowFuncLeave();
1045}
1046
1047/**
[30758]1048 * Sets the status of a certain Guest Additions facility.
1049 *
[39890]1050 * Gets called by vmmdevUpdateGuestStatus, which just passes the report along.
1051 *
1052 * @param a_enmFacility The facility.
1053 * @param a_enmStatus The status.
1054 * @param a_fFlags Flags assoicated with the update. Currently
1055 * reserved and should be ignored.
1056 * @param a_pTimeSpecTS Pointer to the timestamp of this report.
1057 * @sa PDMIVMMDEVCONNECTOR::pfnUpdateGuestStatus, vmmdevUpdateGuestStatus
1058 * @thread The emulation thread.
[30758]1059 */
[52082]1060void Guest::i_setAdditionsStatus(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus,
1061 uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS)
[3582]1062{
[39890]1063 Assert( a_enmFacility > VBoxGuestFacilityType_Unknown
1064 && a_enmFacility <= VBoxGuestFacilityType_All); /* Paranoia, VMMDev checks for this. */
1065
[21878]1066 AutoCaller autoCaller(this);
[33492]1067 AssertComRCReturnVoid(autoCaller.rc());
[3582]1068
[25310]1069 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[3582]1070
[35887]1071 /*
[39890]1072 * Set a specific facility status.
[35887]1073 */
[39890]1074 if (a_enmFacility == VBoxGuestFacilityType_All)
1075 for (FacilityMapIter it = mData.mFacilityMap.begin(); it != mData.mFacilityMap.end(); ++it)
[52082]1076 i_facilityUpdate((VBoxGuestFacilityType)it->first, a_enmStatus, a_fFlags, a_pTimeSpecTS);
[39890]1077 else /* Update one facility only. */
[52082]1078 i_facilityUpdate(a_enmFacility, a_enmStatus, a_fFlags, a_pTimeSpecTS);
[32020]1079
[39890]1080 /*
1081 * Recalc the runlevel.
1082 */
[52082]1083 if (i_facilityIsActive(VBoxGuestFacilityType_VBoxTrayClient))
[32086]1084 mData.mAdditionsRunLevel = AdditionsRunLevelType_Desktop;
[52082]1085 else if (i_facilityIsActive(VBoxGuestFacilityType_VBoxService))
[32086]1086 mData.mAdditionsRunLevel = AdditionsRunLevelType_Userland;
[52082]1087 else if (i_facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver))
[32086]1088 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
[39890]1089 else
1090 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
[3582]1091}
[7409]1092
[30758]1093/**
1094 * Sets the supported features (and whether they are active or not).
1095 *
[65120]1096 * @param aCaps Guest capability bit mask (VMMDEV_GUEST_SUPPORTS_XXX).
[30758]1097 */
[52082]1098void Guest::i_setSupportedFeatures(uint32_t aCaps)
[7409]1099{
[21878]1100 AutoCaller autoCaller(this);
[33492]1101 AssertComRCReturnVoid(autoCaller.rc());
[7409]1102
[25310]1103 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
[7409]1104
[39890]1105 /** @todo A nit: The timestamp is wrong on saved state restore. Would be better
1106 * to move the graphics and seamless capability -> facility translation to
1107 * VMMDev so this could be saved. */
1108 RTTIMESPEC TimeSpecTS;
1109 RTTimeNow(&TimeSpecTS);
1110
[52082]1111 i_facilityUpdate(VBoxGuestFacilityType_Seamless,
1112 aCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
1113 0 /*fFlags*/, &TimeSpecTS);
[30758]1114 /** @todo Add VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING */
[7409]1115}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use