VirtualBox

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

Last change on this file since 44179 was 43908, checked in by vboxsync, 12 years ago

Main/Metrics: VM network rate metrics (#6345)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.9 KB
Line 
1/* $Id: GuestImpl.cpp 43908 2012-11-19 05:36:43Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Guest
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
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
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.
16 */
17
18#include "GuestImpl.h"
19#include "GuestSessionImpl.h"
20
21#include "Global.h"
22#include "ConsoleImpl.h"
23#include "ProgressImpl.h"
24#ifdef VBOX_WITH_DRAG_AND_DROP
25# include "GuestDnDImpl.h"
26#endif
27#include "VMMDev.h"
28
29#include "AutoCaller.h"
30#include "Logging.h"
31#include "Performance.h"
32
33#include <VBox/VMMDev.h>
34#include <iprt/cpp/utils.h>
35#include <iprt/ctype.h>
36#include <iprt/stream.h>
37#include <iprt/timer.h>
38#include <VBox/vmm/pgm.h>
39#include <VBox/version.h>
40
41// defines
42/////////////////////////////////////////////////////////////////////////////
43
44// constructor / destructor
45/////////////////////////////////////////////////////////////////////////////
46
47DEFINE_EMPTY_CTOR_DTOR(Guest)
48
49HRESULT Guest::FinalConstruct()
50{
51 return BaseFinalConstruct();
52}
53
54void Guest::FinalRelease()
55{
56 uninit();
57 BaseFinalRelease();
58}
59
60// public methods only for internal purposes
61/////////////////////////////////////////////////////////////////////////////
62
63/**
64 * Initializes the guest object.
65 */
66HRESULT Guest::init(Console *aParent)
67{
68 LogFlowThisFunc(("aParent=%p\n", aParent));
69
70 ComAssertRet(aParent, E_INVALIDARG);
71
72 /* Enclose the state transition NotReady->InInit->Ready */
73 AutoInitSpan autoInitSpan(this);
74 AssertReturn(autoInitSpan.isOk(), E_FAIL);
75
76 unconst(mParent) = aParent;
77
78 /* Confirm a successful initialization when it's the case */
79 autoInitSpan.setSucceeded();
80
81 ULONG aMemoryBalloonSize;
82 HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
83 if (ret == S_OK)
84 mMemoryBalloonSize = aMemoryBalloonSize;
85 else
86 mMemoryBalloonSize = 0; /* Default is no ballooning */
87
88 BOOL fPageFusionEnabled;
89 ret = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
90 if (ret == S_OK)
91 mfPageFusionEnabled = fPageFusionEnabled;
92 else
93 mfPageFusionEnabled = false; /* Default is no page fusion*/
94
95 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
96 mCollectVMMStats = false;
97
98 /* Clear statistics. */
99 mNetStatRx = mNetStatTx = 0;
100 mNetStatLastTs = RTTimeNanoTS();
101 for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++)
102 mCurrentGuestStat[i] = 0;
103 mVmValidStats = pm::VMSTATMASK_NONE;
104
105 mMagic = GUEST_MAGIC;
106 int vrc = RTTimerLRCreate(&mStatTimer, 1000 /* ms */,
107 &Guest::staticUpdateStats, this);
108 AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc));
109
110 try
111 {
112#ifdef VBOX_WITH_DRAG_AND_DROP
113 m_pGuestDnD = new GuestDnD(this);
114 AssertPtr(m_pGuestDnD);
115#endif
116 }
117 catch(std::bad_alloc &)
118 {
119 return E_OUTOFMEMORY;
120 }
121
122 return S_OK;
123}
124
125/**
126 * Uninitializes the instance and sets the ready flag to FALSE.
127 * Called either from FinalRelease() or by the parent when it gets destroyed.
128 */
129void Guest::uninit()
130{
131 LogFlowThisFunc(("\n"));
132
133 /* Enclose the state transition Ready->InUninit->NotReady */
134 AutoUninitSpan autoUninitSpan(this);
135 if (autoUninitSpan.uninitDone())
136 return;
137
138 /* Destroy stat update timer */
139 int vrc = RTTimerLRDestroy(mStatTimer);
140 AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc));
141 mStatTimer = NULL;
142 mMagic = 0;
143
144#ifdef VBOX_WITH_GUEST_CONTROL
145 LogFlowThisFunc(("Closing sessions (%RU64 total)\n",
146 mData.mGuestSessions.size()));
147 GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
148 while (itSessions != mData.mGuestSessions.end())
149 {
150#ifdef DEBUG
151 ULONG cRefs = itSessions->second->AddRef();
152 LogFlowThisFunc(("pSession=%p, cRefs=%RU32\n", (GuestSession *)itSessions->second, cRefs > 0 ? cRefs - 1 : 0));
153 itSessions->second->Release();
154#endif
155 itSessions->second->uninit();
156 itSessions++;
157 }
158 mData.mGuestSessions.clear();
159#endif
160
161#ifdef VBOX_WITH_DRAG_AND_DROP
162 if (m_pGuestDnD)
163 {
164 delete m_pGuestDnD;
165 m_pGuestDnD = NULL;
166 }
167#endif
168
169 unconst(mParent) = NULL;
170
171 LogFlowFuncLeave();
172}
173
174/* static */
175void Guest::staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick)
176{
177 AssertReturnVoid(pvUser != NULL);
178 Guest *guest = static_cast<Guest *>(pvUser);
179 Assert(guest->mMagic == GUEST_MAGIC);
180 if (guest->mMagic == GUEST_MAGIC)
181 guest->updateStats(iTick);
182
183 NOREF(hTimerLR);
184}
185
186/* static */
187int Guest::staticEnumStatsCallback(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit,
188 STAMVISIBILITY enmVisiblity, const char *pszDesc, void *pvUser)
189{
190 PSTAMCOUNTER pCnt = (PSTAMCOUNTER)pvSample;
191 char *pszEnd = strrchr((char*)pszName, '/');
192 if (pszEnd)
193 {
194 bool fRx;
195 uint8_t uInstance = 0;
196
197 switch (pszEnd[1])
198 {
199 case 'R':
200 fRx = true;
201 break;
202 case 'T':
203 fRx = false;
204 break;
205 default:
206 LogRel(("Failed to parse the name of network stat counter (unknown counter): %s\n", pszName));
207 return VINF_SUCCESS;
208 }
209 do
210 --pszEnd;
211 while (pszEnd > pszName && RT_C_IS_DIGIT(*pszEnd));
212 if (RT_SUCCESS(RTStrToUInt8Ex(pszEnd + 1, NULL, 10, &uInstance)))
213 {
214 Guest *pGuest = (Guest *)pvUser;
215 LogFlowFunc(("%s i=%u d=%s %llu %s\n", pszName, uInstance, fRx ? "RX" : "TX",
216 pCnt->c, STAMR3GetUnit(enmUnit)));
217 if (fRx)
218 pGuest->mNetStatRx += pCnt->c;
219 else
220 pGuest->mNetStatTx += pCnt->c;
221 }
222 else
223 LogRel(("Failed to extract the device instance from the name of network stat counter: %s\n", pszEnd));
224 }
225 else
226 LogRel(("Failed to parse the name of network stat counter (no slash): %s\n", pszName));
227
228 return VINF_SUCCESS;
229}
230
231void Guest::updateStats(uint64_t iTick)
232{
233 uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal, uSharedTotal;
234 uint64_t uTotalMem, uPrivateMem, uSharedMem, uZeroMem;
235
236 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
237
238 ULONG uNetStatRx = 0;
239 ULONG uNetStatTx = 0;
240 ULONG aGuestStats[GUESTSTATTYPE_MAX];
241 RT_ZERO(aGuestStats);
242 ULONG validStats = mVmValidStats;
243 /* Check if we have anything to report */
244 if (validStats)
245 {
246 mVmValidStats = pm::VMSTATMASK_NONE;
247 memcpy(aGuestStats, mCurrentGuestStat, sizeof(aGuestStats));
248 }
249 alock.release();
250 /*
251 * Calling SessionMachine may take time as the object resides in VBoxSVC
252 * process. This is why we took a snapshot of currently collected stats
253 * and released the lock.
254 */
255 uFreeTotal = 0;
256 uAllocTotal = 0;
257 uBalloonedTotal = 0;
258 uSharedTotal = 0;
259 uTotalMem = 0;
260 uPrivateMem = 0;
261 uSharedMem = 0;
262 uZeroMem = 0;
263
264 Console::SafeVMPtr pVM(mParent);
265 if (pVM.isOk())
266 {
267 int rc;
268
269 /*
270 * There is no point in collecting VM shared memory if other memory
271 * statistics are not available yet. Or is it?
272 */
273 if (validStats)
274 {
275 /* Query the missing per-VM memory statistics. */
276 rc = PGMR3QueryMemoryStats(pVM.raw(), &uTotalMem, &uPrivateMem, &uSharedMem, &uZeroMem);
277 if (rc == VINF_SUCCESS)
278 {
279 validStats |= pm::VMSTATMASK_GUEST_MEMSHARED;
280 }
281 }
282
283 if (mCollectVMMStats)
284 {
285 rc = PGMR3QueryGlobalMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal, &uSharedTotal);
286 AssertRC(rc);
287 if (rc == VINF_SUCCESS)
288 {
289 validStats |=
290 pm::VMSTATMASK_VMM_ALLOC | pm::VMSTATMASK_VMM_FREE |
291 pm::VMSTATMASK_VMM_BALOON | pm::VMSTATMASK_VMM_SHARED;
292 }
293 }
294
295 uint64_t uRxPrev = mNetStatRx;
296 uint64_t uTxPrev = mNetStatTx;
297 mNetStatRx = mNetStatTx = 0;
298 rc = STAMR3Enum(pVM, "*/ReceiveBytes|*/TransmitBytes", staticEnumStatsCallback, this);
299 uint64_t uTsNow = RTTimeNanoTS();
300 uint64_t uTimePassed = uTsNow - mNetStatLastTs;
301 mNetStatLastTs = uTsNow;
302 uNetStatRx = (ULONG)((mNetStatRx - uRxPrev) * 1000000 / (uTimePassed / 1000)); /* in bytes per second */
303 uNetStatTx = (ULONG)((mNetStatTx - uTxPrev) * 1000000 / (uTimePassed / 1000)); /* in bytes per second */
304 LogFlowThisFunc(("Net Rx=%llu Tx=%llu Ts=%llu Delta=%llu\n", mNetStatRx, mNetStatTx, uTsNow, uTimePassed));
305 AssertRC(rc);
306 validStats |= pm::VMSTATMASK_NET_RX | pm::VMSTATMASK_NET_TX;
307 }
308
309 mParent->reportVmStatistics(validStats,
310 aGuestStats[GUESTSTATTYPE_CPUUSER],
311 aGuestStats[GUESTSTATTYPE_CPUKERNEL],
312 aGuestStats[GUESTSTATTYPE_CPUIDLE],
313 /* Convert the units for RAM usage stats: page (4K) -> 1KB units */
314 mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K),
315 mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K),
316 mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K),
317 (ULONG)(uSharedMem / _1K), /* bytes -> KB */
318 mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K),
319 mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K),
320 (ULONG)(uAllocTotal / _1K), /* bytes -> KB */
321 (ULONG)(uFreeTotal / _1K),
322 (ULONG)(uBalloonedTotal / _1K),
323 (ULONG)(uSharedTotal / _1K),
324 uNetStatRx,
325 uNetStatTx);
326}
327
328// IGuest properties
329/////////////////////////////////////////////////////////////////////////////
330
331STDMETHODIMP Guest::COMGETTER(OSTypeId)(BSTR *a_pbstrOSTypeId)
332{
333 CheckComArgOutPointerValid(a_pbstrOSTypeId);
334
335 AutoCaller autoCaller(this);
336 HRESULT hrc = autoCaller.rc();
337 if (SUCCEEDED(hrc))
338 {
339 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
340 if (!mData.mInterfaceVersion.isEmpty())
341 mData.mOSTypeId.cloneTo(a_pbstrOSTypeId);
342 else
343 {
344 /* Redirect the call to IMachine if no additions are installed. */
345 ComPtr<IMachine> ptrMachine(mParent->machine());
346 alock.release();
347 hrc = ptrMachine->COMGETTER(OSTypeId)(a_pbstrOSTypeId);
348 }
349 }
350 return hrc;
351}
352
353STDMETHODIMP Guest::COMGETTER(AdditionsRunLevel)(AdditionsRunLevelType_T *aRunLevel)
354{
355 AutoCaller autoCaller(this);
356 if (FAILED(autoCaller.rc())) return autoCaller.rc();
357
358 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
359
360 *aRunLevel = mData.mAdditionsRunLevel;
361
362 return S_OK;
363}
364
365STDMETHODIMP Guest::COMGETTER(AdditionsVersion)(BSTR *a_pbstrAdditionsVersion)
366{
367 CheckComArgOutPointerValid(a_pbstrAdditionsVersion);
368
369 AutoCaller autoCaller(this);
370 HRESULT hrc = autoCaller.rc();
371 if (SUCCEEDED(hrc))
372 {
373 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
374
375 /*
376 * Return the ReportGuestInfo2 version info if available.
377 */
378 if ( !mData.mAdditionsVersionNew.isEmpty()
379 || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
380 mData.mAdditionsVersionNew.cloneTo(a_pbstrAdditionsVersion);
381 else
382 {
383 /*
384 * If we're running older guest additions (< 3.2.0) try get it from
385 * the guest properties. Detected switched around Version and
386 * Revision in early 3.1.x releases (see r57115).
387 */
388 ComPtr<IMachine> ptrMachine = mParent->machine();
389 alock.release(); /* No need to hold this during the IPC fun. */
390
391 Bstr bstr;
392 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam());
393 if ( SUCCEEDED(hrc)
394 && !bstr.isEmpty())
395 {
396 Utf8Str str(bstr);
397 if (str.count('.') == 0)
398 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam());
399 str = bstr;
400 if (str.count('.') != 2)
401 hrc = E_FAIL;
402 }
403
404 if (SUCCEEDED(hrc))
405 bstr.detachTo(a_pbstrAdditionsVersion);
406 else
407 {
408 /* Returning 1.4 is better than nothing. */
409 alock.acquire();
410 mData.mInterfaceVersion.cloneTo(a_pbstrAdditionsVersion);
411 hrc = S_OK;
412 }
413 }
414 }
415 return hrc;
416}
417
418STDMETHODIMP Guest::COMGETTER(AdditionsRevision)(ULONG *a_puAdditionsRevision)
419{
420 CheckComArgOutPointerValid(a_puAdditionsRevision);
421
422 AutoCaller autoCaller(this);
423 HRESULT hrc = autoCaller.rc();
424 if (SUCCEEDED(hrc))
425 {
426 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
427
428 /*
429 * Return the ReportGuestInfo2 version info if available.
430 */
431 if ( !mData.mAdditionsVersionNew.isEmpty()
432 || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
433 *a_puAdditionsRevision = mData.mAdditionsRevision;
434 else
435 {
436 /*
437 * If we're running older guest additions (< 3.2.0) try get it from
438 * the guest properties. Detected switched around Version and
439 * Revision in early 3.1.x releases (see r57115).
440 */
441 ComPtr<IMachine> ptrMachine = mParent->machine();
442 alock.release(); /* No need to hold this during the IPC fun. */
443
444 Bstr bstr;
445 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam());
446 if (SUCCEEDED(hrc))
447 {
448 Utf8Str str(bstr);
449 uint32_t uRevision;
450 int vrc = RTStrToUInt32Full(str.c_str(), 0, &uRevision);
451 if (vrc != VINF_SUCCESS && str.count('.') == 2)
452 {
453 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam());
454 if (SUCCEEDED(hrc))
455 {
456 str = bstr;
457 vrc = RTStrToUInt32Full(str.c_str(), 0, &uRevision);
458 }
459 }
460 if (vrc == VINF_SUCCESS)
461 *a_puAdditionsRevision = uRevision;
462 else
463 hrc = VBOX_E_IPRT_ERROR;
464 }
465 if (FAILED(hrc))
466 {
467 /* Return 0 if we don't know. */
468 *a_puAdditionsRevision = 0;
469 hrc = S_OK;
470 }
471 }
472 }
473 return hrc;
474}
475
476STDMETHODIMP Guest::COMGETTER(Facilities)(ComSafeArrayOut(IAdditionsFacility *, aFacilities))
477{
478 CheckComArgOutSafeArrayPointerValid(aFacilities);
479
480 AutoCaller autoCaller(this);
481 if (FAILED(autoCaller.rc())) return autoCaller.rc();
482
483 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
484
485 SafeIfaceArray<IAdditionsFacility> fac(mData.mFacilityMap);
486 fac.detachTo(ComSafeArrayOutArg(aFacilities));
487
488 return S_OK;
489}
490
491STDMETHODIMP Guest::COMGETTER(Sessions)(ComSafeArrayOut(IGuestSession *, aSessions))
492{
493 CheckComArgOutSafeArrayPointerValid(aSessions);
494
495 AutoCaller autoCaller(this);
496 if (FAILED(autoCaller.rc())) return autoCaller.rc();
497
498 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
499
500 SafeIfaceArray<IGuestSession> collection(mData.mGuestSessions);
501 collection.detachTo(ComSafeArrayOutArg(aSessions));
502
503 return S_OK;
504}
505
506BOOL Guest::isPageFusionEnabled()
507{
508 AutoCaller autoCaller(this);
509 if (FAILED(autoCaller.rc())) return false;
510
511 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
512
513 return mfPageFusionEnabled;
514}
515
516STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize)(ULONG *aMemoryBalloonSize)
517{
518 CheckComArgOutPointerValid(aMemoryBalloonSize);
519
520 AutoCaller autoCaller(this);
521 if (FAILED(autoCaller.rc())) return autoCaller.rc();
522
523 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
524
525 *aMemoryBalloonSize = mMemoryBalloonSize;
526
527 return S_OK;
528}
529
530STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize)(ULONG aMemoryBalloonSize)
531{
532 AutoCaller autoCaller(this);
533 if (FAILED(autoCaller.rc())) return autoCaller.rc();
534
535 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
536
537 /* We must be 100% sure that IMachine::COMSETTER(MemoryBalloonSize)
538 * does not call us back in any way! */
539 HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
540 if (ret == S_OK)
541 {
542 mMemoryBalloonSize = aMemoryBalloonSize;
543 /* forward the information to the VMM device */
544 VMMDev *pVMMDev = mParent->getVMMDev();
545 /* MUST release all locks before calling VMM device as its critsect
546 * has higher lock order than anything in Main. */
547 alock.release();
548 if (pVMMDev)
549 {
550 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
551 if (pVMMDevPort)
552 pVMMDevPort->pfnSetMemoryBalloon(pVMMDevPort, aMemoryBalloonSize);
553 }
554 }
555
556 return ret;
557}
558
559STDMETHODIMP Guest::COMGETTER(StatisticsUpdateInterval)(ULONG *aUpdateInterval)
560{
561 CheckComArgOutPointerValid(aUpdateInterval);
562
563 AutoCaller autoCaller(this);
564 if (FAILED(autoCaller.rc())) return autoCaller.rc();
565
566 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
567
568 *aUpdateInterval = mStatUpdateInterval;
569 return S_OK;
570}
571
572STDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval)(ULONG aUpdateInterval)
573{
574 AutoCaller autoCaller(this);
575 if (FAILED(autoCaller.rc())) return autoCaller.rc();
576
577 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
578
579 if (mStatUpdateInterval)
580 if (aUpdateInterval == 0)
581 RTTimerLRStop(mStatTimer);
582 else
583 RTTimerLRChangeInterval(mStatTimer, aUpdateInterval);
584 else
585 if (aUpdateInterval != 0)
586 {
587 RTTimerLRChangeInterval(mStatTimer, aUpdateInterval);
588 RTTimerLRStart(mStatTimer, 0);
589 }
590 mStatUpdateInterval = aUpdateInterval;
591 /* forward the information to the VMM device */
592 VMMDev *pVMMDev = mParent->getVMMDev();
593 /* MUST release all locks before calling VMM device as its critsect
594 * has higher lock order than anything in Main. */
595 alock.release();
596 if (pVMMDev)
597 {
598 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
599 if (pVMMDevPort)
600 pVMMDevPort->pfnSetStatisticsInterval(pVMMDevPort, aUpdateInterval);
601 }
602
603 return S_OK;
604}
605
606STDMETHODIMP Guest::InternalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
607 ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemShared,
608 ULONG *aMemCache, ULONG *aPageTotal,
609 ULONG *aMemAllocTotal, ULONG *aMemFreeTotal, ULONG *aMemBalloonTotal, ULONG *aMemSharedTotal)
610{
611 CheckComArgOutPointerValid(aCpuUser);
612 CheckComArgOutPointerValid(aCpuKernel);
613 CheckComArgOutPointerValid(aCpuIdle);
614 CheckComArgOutPointerValid(aMemTotal);
615 CheckComArgOutPointerValid(aMemFree);
616 CheckComArgOutPointerValid(aMemBalloon);
617 CheckComArgOutPointerValid(aMemShared);
618 CheckComArgOutPointerValid(aMemCache);
619 CheckComArgOutPointerValid(aPageTotal);
620 CheckComArgOutPointerValid(aMemAllocTotal);
621 CheckComArgOutPointerValid(aMemFreeTotal);
622 CheckComArgOutPointerValid(aMemBalloonTotal);
623 CheckComArgOutPointerValid(aMemSharedTotal);
624
625 AutoCaller autoCaller(this);
626 if (FAILED(autoCaller.rc())) return autoCaller.rc();
627
628 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
629
630 *aCpuUser = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER];
631 *aCpuKernel = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL];
632 *aCpuIdle = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE];
633 *aMemTotal = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
634 *aMemFree = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K); /* page (4K) -> 1KB units */
635 *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K); /* page (4K) -> 1KB units */
636 *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K); /* page (4K) -> 1KB units */
637 *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
638
639 /* MUST release all locks before calling any PGM statistics queries,
640 * as they are executed by EMT and that might deadlock us by VMM device
641 * activity which waits for the Guest object lock. */
642 alock.release();
643 Console::SafeVMPtr pVM (mParent);
644 if (pVM.isOk())
645 {
646 uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal, uSharedTotal;
647 *aMemFreeTotal = 0;
648 int rc = PGMR3QueryGlobalMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal, &uSharedTotal);
649 AssertRC(rc);
650 if (rc == VINF_SUCCESS)
651 {
652 *aMemAllocTotal = (ULONG)(uAllocTotal / _1K); /* bytes -> KB */
653 *aMemFreeTotal = (ULONG)(uFreeTotal / _1K);
654 *aMemBalloonTotal = (ULONG)(uBalloonedTotal / _1K);
655 *aMemSharedTotal = (ULONG)(uSharedTotal / _1K);
656 }
657 else
658 return E_FAIL;
659
660 /* Query the missing per-VM memory statistics. */
661 *aMemShared = 0;
662 uint64_t uTotalMem, uPrivateMem, uSharedMem, uZeroMem;
663 rc = PGMR3QueryMemoryStats(pVM.raw(), &uTotalMem, &uPrivateMem, &uSharedMem, &uZeroMem);
664 if (rc == VINF_SUCCESS)
665 {
666 *aMemShared = (ULONG)(uSharedMem / _1K);
667 }
668 else
669 return E_FAIL;
670 }
671 else
672 {
673 *aMemAllocTotal = 0;
674 *aMemFreeTotal = 0;
675 *aMemBalloonTotal = 0;
676 *aMemSharedTotal = 0;
677 *aMemShared = 0;
678 return E_FAIL;
679 }
680
681 return S_OK;
682}
683
684HRESULT Guest::setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal)
685{
686 static ULONG indexToPerfMask[] =
687 {
688 pm::VMSTATMASK_GUEST_CPUUSER,
689 pm::VMSTATMASK_GUEST_CPUKERNEL,
690 pm::VMSTATMASK_GUEST_CPUIDLE,
691 pm::VMSTATMASK_GUEST_MEMTOTAL,
692 pm::VMSTATMASK_GUEST_MEMFREE,
693 pm::VMSTATMASK_GUEST_MEMBALLOON,
694 pm::VMSTATMASK_GUEST_MEMCACHE,
695 pm::VMSTATMASK_GUEST_PAGETOTAL,
696 pm::VMSTATMASK_NONE
697 };
698 AutoCaller autoCaller(this);
699 if (FAILED(autoCaller.rc())) return autoCaller.rc();
700
701 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
702
703 if (enmType >= GUESTSTATTYPE_MAX)
704 return E_INVALIDARG;
705
706 mCurrentGuestStat[enmType] = aVal;
707 mVmValidStats |= indexToPerfMask[enmType];
708 return S_OK;
709}
710
711/**
712 * Returns the status of a specified Guest Additions facility.
713 *
714 * @return aStatus Current status of specified facility.
715 * @param aType Facility to get the status from.
716 * @param aTimestamp Timestamp of last facility status update in ms (optional).
717 */
718STDMETHODIMP Guest::GetFacilityStatus(AdditionsFacilityType_T aType, LONG64 *aTimestamp, AdditionsFacilityStatus_T *aStatus)
719{
720 AutoCaller autoCaller(this);
721 if (FAILED(autoCaller.rc())) return autoCaller.rc();
722
723 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
724
725 CheckComArgNotNull(aStatus);
726 /* Not checking for aTimestamp is intentional; it's optional. */
727
728 FacilityMapIterConst it = mData.mFacilityMap.find(aType);
729 if (it != mData.mFacilityMap.end())
730 {
731 AdditionsFacility *pFacility = it->second;
732 ComAssert(pFacility);
733 *aStatus = pFacility->getStatus();
734 if (aTimestamp)
735 *aTimestamp = pFacility->getLastUpdated();
736 }
737 else
738 {
739 /*
740 * Do not fail here -- could be that the facility never has been brought up (yet) but
741 * the host wants to have its status anyway. So just tell we don't know at this point.
742 */
743 *aStatus = AdditionsFacilityStatus_Unknown;
744 if (aTimestamp)
745 *aTimestamp = RTTimeMilliTS();
746 }
747 return S_OK;
748}
749
750STDMETHODIMP Guest::GetAdditionsStatus(AdditionsRunLevelType_T aLevel, BOOL *aActive)
751{
752 AutoCaller autoCaller(this);
753 if (FAILED(autoCaller.rc())) return autoCaller.rc();
754
755 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
756
757 HRESULT rc = S_OK;
758 switch (aLevel)
759 {
760 case AdditionsRunLevelType_System:
761 *aActive = (mData.mAdditionsRunLevel > AdditionsRunLevelType_None);
762 break;
763
764 case AdditionsRunLevelType_Userland:
765 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Userland);
766 break;
767
768 case AdditionsRunLevelType_Desktop:
769 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Desktop);
770 break;
771
772 default:
773 rc = setError(VBOX_E_NOT_SUPPORTED,
774 tr("Invalid status level defined: %u"), aLevel);
775 break;
776 }
777
778 return rc;
779}
780
781STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
782 IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
783{
784 AutoCaller autoCaller(this);
785 if (FAILED(autoCaller.rc())) return autoCaller.rc();
786
787 /* forward the information to the VMM device */
788 VMMDev *pVMMDev = mParent->getVMMDev();
789 if (pVMMDev)
790 {
791 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
792 if (pVMMDevPort)
793 {
794 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
795 if (!aAllowInteractiveLogon)
796 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
797
798 pVMMDevPort->pfnSetCredentials(pVMMDevPort,
799 Utf8Str(aUserName).c_str(),
800 Utf8Str(aPassword).c_str(),
801 Utf8Str(aDomain).c_str(),
802 u32Flags);
803 return S_OK;
804 }
805 }
806
807 return setError(VBOX_E_VM_ERROR,
808 tr("VMM device is not available (is the VM running?)"));
809}
810
811STDMETHODIMP Guest::DragHGEnter(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
812{
813 /* Input validation */
814 CheckComArgSafeArrayNotNull(allowedActions);
815 CheckComArgSafeArrayNotNull(formats);
816 CheckComArgOutPointerValid(pResultAction);
817
818 AutoCaller autoCaller(this);
819 if (FAILED(autoCaller.rc())) return autoCaller.rc();
820
821#ifdef VBOX_WITH_DRAG_AND_DROP
822 return m_pGuestDnD->dragHGEnter(uScreenId, uX, uY, defaultAction, ComSafeArrayInArg(allowedActions), ComSafeArrayInArg(formats), pResultAction);
823#else /* VBOX_WITH_DRAG_AND_DROP */
824 ReturnComNotImplemented();
825#endif /* !VBOX_WITH_DRAG_AND_DROP */
826}
827
828STDMETHODIMP Guest::DragHGMove(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
829{
830 /* Input validation */
831 CheckComArgSafeArrayNotNull(allowedActions);
832 CheckComArgSafeArrayNotNull(formats);
833 CheckComArgOutPointerValid(pResultAction);
834
835 AutoCaller autoCaller(this);
836 if (FAILED(autoCaller.rc())) return autoCaller.rc();
837
838#ifdef VBOX_WITH_DRAG_AND_DROP
839 return m_pGuestDnD->dragHGMove(uScreenId, uX, uY, defaultAction, ComSafeArrayInArg(allowedActions), ComSafeArrayInArg(formats), pResultAction);
840#else /* VBOX_WITH_DRAG_AND_DROP */
841 ReturnComNotImplemented();
842#endif /* !VBOX_WITH_DRAG_AND_DROP */
843}
844
845STDMETHODIMP Guest::DragHGLeave(ULONG uScreenId)
846{
847 AutoCaller autoCaller(this);
848 if (FAILED(autoCaller.rc())) return autoCaller.rc();
849
850#ifdef VBOX_WITH_DRAG_AND_DROP
851 return m_pGuestDnD->dragHGLeave(uScreenId);
852#else /* VBOX_WITH_DRAG_AND_DROP */
853 ReturnComNotImplemented();
854#endif /* !VBOX_WITH_DRAG_AND_DROP */
855}
856
857STDMETHODIMP Guest::DragHGDrop(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), BSTR *pstrFormat, DragAndDropAction_T *pResultAction)
858{
859 /* Input validation */
860 CheckComArgSafeArrayNotNull(allowedActions);
861 CheckComArgSafeArrayNotNull(formats);
862 CheckComArgOutPointerValid(pstrFormat);
863 CheckComArgOutPointerValid(pResultAction);
864
865 AutoCaller autoCaller(this);
866 if (FAILED(autoCaller.rc())) return autoCaller.rc();
867
868#ifdef VBOX_WITH_DRAG_AND_DROP
869 return m_pGuestDnD->dragHGDrop(uScreenId, uX, uY, defaultAction, ComSafeArrayInArg(allowedActions), ComSafeArrayInArg(formats), pstrFormat, pResultAction);
870#else /* VBOX_WITH_DRAG_AND_DROP */
871 ReturnComNotImplemented();
872#endif /* !VBOX_WITH_DRAG_AND_DROP */
873}
874
875STDMETHODIMP Guest::DragHGPutData(ULONG uScreenId, IN_BSTR bstrFormat, ComSafeArrayIn(BYTE, data), IProgress **ppProgress)
876{
877 /* Input validation */
878 CheckComArgStrNotEmptyOrNull(bstrFormat);
879 CheckComArgSafeArrayNotNull(data);
880 CheckComArgOutPointerValid(ppProgress);
881
882 AutoCaller autoCaller(this);
883 if (FAILED(autoCaller.rc())) return autoCaller.rc();
884
885#ifdef VBOX_WITH_DRAG_AND_DROP
886 return m_pGuestDnD->dragHGPutData(uScreenId, bstrFormat, ComSafeArrayInArg(data), ppProgress);
887#else /* VBOX_WITH_DRAG_AND_DROP */
888 ReturnComNotImplemented();
889#endif /* !VBOX_WITH_DRAG_AND_DROP */
890}
891
892STDMETHODIMP Guest::DragGHPending(ULONG uScreenId, ComSafeArrayOut(BSTR, formats), ComSafeArrayOut(DragAndDropAction_T, allowedActions), DragAndDropAction_T *pDefaultAction)
893{
894 /* Input validation */
895 CheckComArgSafeArrayNotNull(formats);
896 CheckComArgSafeArrayNotNull(allowedActions);
897 CheckComArgOutPointerValid(pDefaultAction);
898
899 AutoCaller autoCaller(this);
900 if (FAILED(autoCaller.rc())) return autoCaller.rc();
901
902#if defined(VBOX_WITH_DRAG_AND_DROP) && defined(VBOX_WITH_DRAG_AND_DROP_GH)
903 return m_pGuestDnD->dragGHPending(uScreenId, ComSafeArrayOutArg(formats), ComSafeArrayOutArg(allowedActions), pDefaultAction);
904#else /* VBOX_WITH_DRAG_AND_DROP */
905 ReturnComNotImplemented();
906#endif /* !VBOX_WITH_DRAG_AND_DROP */
907}
908
909STDMETHODIMP Guest::DragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action, IProgress **ppProgress)
910{
911 /* Input validation */
912 CheckComArgStrNotEmptyOrNull(bstrFormat);
913 CheckComArgOutPointerValid(ppProgress);
914
915 AutoCaller autoCaller(this);
916 if (FAILED(autoCaller.rc())) return autoCaller.rc();
917
918#if defined(VBOX_WITH_DRAG_AND_DROP) && defined(VBOX_WITH_DRAG_AND_DROP_GH)
919 return m_pGuestDnD->dragGHDropped(bstrFormat, action, ppProgress);
920#else /* VBOX_WITH_DRAG_AND_DROP */
921 ReturnComNotImplemented();
922#endif /* !VBOX_WITH_DRAG_AND_DROP */
923}
924
925STDMETHODIMP Guest::DragGHGetData(ComSafeArrayOut(BYTE, data))
926{
927 /* Input validation */
928 CheckComArgSafeArrayNotNull(data);
929
930 AutoCaller autoCaller(this);
931 if (FAILED(autoCaller.rc())) return autoCaller.rc();
932
933#if defined(VBOX_WITH_DRAG_AND_DROP) && defined(VBOX_WITH_DRAG_AND_DROP_GH)
934 return m_pGuestDnD->dragGHGetData(ComSafeArrayOutArg(data));
935#else /* VBOX_WITH_DRAG_AND_DROP */
936 ReturnComNotImplemented();
937#endif /* !VBOX_WITH_DRAG_AND_DROP */
938}
939
940// public methods only for internal purposes
941/////////////////////////////////////////////////////////////////////////////
942
943/**
944 * Sets the general Guest Additions information like
945 * API (interface) version and OS type. Gets called by
946 * vmmdevUpdateGuestInfo.
947 *
948 * @param aInterfaceVersion
949 * @param aOsType
950 */
951void Guest::setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType)
952{
953 RTTIMESPEC TimeSpecTS;
954 RTTimeNow(&TimeSpecTS);
955
956 AutoCaller autoCaller(this);
957 AssertComRCReturnVoid(autoCaller.rc());
958
959 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
960
961
962 /*
963 * Note: The Guest Additions API (interface) version is deprecated
964 * and will not be used anymore! We might need it to at least report
965 * something as version number if *really* ancient Guest Additions are
966 * installed (without the guest version + revision properties having set).
967 */
968 mData.mInterfaceVersion = aInterfaceVersion;
969
970 /*
971 * Older Additions rely on the Additions API version whether they
972 * are assumed to be active or not. Since newer Additions do report
973 * the Additions version *before* calling this function (by calling
974 * VMMDevReportGuestInfo2, VMMDevReportGuestStatus, VMMDevReportGuestInfo,
975 * in that order) we can tell apart old and new Additions here. Old
976 * Additions never would set VMMDevReportGuestInfo2 (which set mData.mAdditionsVersion)
977 * so they just rely on the aInterfaceVersion string (which gets set by
978 * VMMDevReportGuestInfo).
979 *
980 * So only mark the Additions as being active (run level = system) when we
981 * don't have the Additions version set.
982 */
983 if (mData.mAdditionsVersionNew.isEmpty())
984 {
985 if (aInterfaceVersion.isEmpty())
986 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
987 else
988 {
989 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
990
991 /*
992 * To keep it compatible with the old Guest Additions behavior we need to set the
993 * "graphics" (feature) facility to active as soon as we got the Guest Additions
994 * interface version.
995 */
996 facilityUpdate(VBoxGuestFacilityType_Graphics, VBoxGuestFacilityStatus_Active, 0 /*fFlags*/, &TimeSpecTS);
997 }
998 }
999
1000 /*
1001 * Older Additions didn't have this finer grained capability bit,
1002 * so enable it by default. Newer Additions will not enable this here
1003 * and use the setSupportedFeatures function instead.
1004 */
1005 /** @todo r=bird: I don't get the above comment nor the code below...
1006 * One talks about capability bits, the one always does something to a facility.
1007 * Then there is the comment below it all, which is placed like it addresses the
1008 * mOSTypeId, but talks about something which doesn't remotely like mOSTypeId...
1009 *
1010 * Andy, could you please try clarify and make the comments shorter and more
1011 * coherent! Also, explain why this is important and what depends on it.
1012 *
1013 * PS. There is the VMMDEV_GUEST_SUPPORTS_GRAPHICS capability* report... It
1014 * should come in pretty quickly after this update, normally.
1015 */
1016 facilityUpdate(VBoxGuestFacilityType_Graphics,
1017 facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver)
1018 ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
1019 0 /*fFlags*/, &TimeSpecTS); /** @todo the timestamp isn't gonna be right here on saved state restore. */
1020
1021 /*
1022 * Note! There is a race going on between setting mAdditionsRunLevel and
1023 * mSupportsGraphics here and disabling/enabling it later according to
1024 * its real status when using new(er) Guest Additions.
1025 */
1026 mData.mOSTypeId = Global::OSTypeId(aOsType);
1027}
1028
1029/**
1030 * Sets the Guest Additions version information details.
1031 *
1032 * Gets called by vmmdevUpdateGuestInfo2 and vmmdevUpdateGuestInfo (to clear the
1033 * state).
1034 *
1035 * @param a_uFullVersion VBoxGuestInfo2::additionsMajor,
1036 * VBoxGuestInfo2::additionsMinor and
1037 * VBoxGuestInfo2::additionsBuild combined into
1038 * one value by VBOX_FULL_VERSION_MAKE.
1039 *
1040 * When this is 0, it's vmmdevUpdateGuestInfo
1041 * calling to reset the state.
1042 *
1043 * @param a_pszName Build type tag and/or publisher tag, empty
1044 * string if neiter of those are present.
1045 * @param a_uRevision See VBoxGuestInfo2::additionsRevision.
1046 * @param a_fFeatures See VBoxGuestInfo2::additionsFeatures.
1047 */
1048void Guest::setAdditionsInfo2(uint32_t a_uFullVersion, const char *a_pszName, uint32_t a_uRevision, uint32_t a_fFeatures)
1049{
1050 AutoCaller autoCaller(this);
1051 AssertComRCReturnVoid(autoCaller.rc());
1052
1053 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1054
1055 if (a_uFullVersion)
1056 {
1057 mData.mAdditionsVersionNew = BstrFmt(*a_pszName ? "%u.%u.%u_%s" : "%u.%u.%u",
1058 VBOX_FULL_VERSION_GET_MAJOR(a_uFullVersion),
1059 VBOX_FULL_VERSION_GET_MINOR(a_uFullVersion),
1060 VBOX_FULL_VERSION_GET_BUILD(a_uFullVersion),
1061 a_pszName);
1062 mData.mAdditionsVersionFull = a_uFullVersion;
1063 mData.mAdditionsRevision = a_uRevision;
1064 mData.mAdditionsFeatures = a_fFeatures;
1065 }
1066 else
1067 {
1068 Assert(!a_fFeatures && !a_uRevision && !*a_pszName);
1069 mData.mAdditionsVersionNew.setNull();
1070 mData.mAdditionsVersionFull = 0;
1071 mData.mAdditionsRevision = 0;
1072 mData.mAdditionsFeatures = 0;
1073 }
1074}
1075
1076bool Guest::facilityIsActive(VBoxGuestFacilityType enmFacility)
1077{
1078 Assert(enmFacility < INT32_MAX);
1079 FacilityMapIterConst it = mData.mFacilityMap.find((AdditionsFacilityType_T)enmFacility);
1080 if (it != mData.mFacilityMap.end())
1081 {
1082 AdditionsFacility *pFac = it->second;
1083 return (pFac->getStatus() == AdditionsFacilityStatus_Active);
1084 }
1085 return false;
1086}
1087
1088void Guest::facilityUpdate(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus,
1089 uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS)
1090{
1091 AssertReturnVoid( a_enmFacility < VBoxGuestFacilityType_All
1092 && a_enmFacility > VBoxGuestFacilityType_Unknown);
1093
1094 FacilityMapIter it = mData.mFacilityMap.find((AdditionsFacilityType_T)a_enmFacility);
1095 if (it != mData.mFacilityMap.end())
1096 {
1097 AdditionsFacility *pFac = it->second;
1098 pFac->update((AdditionsFacilityStatus_T)a_enmStatus, a_fFlags, a_pTimeSpecTS);
1099 }
1100 else
1101 {
1102 if (mData.mFacilityMap.size() > 64)
1103 {
1104 /* The easy way out for now. We could automatically destroy
1105 inactive facilities like VMMDev does if we like... */
1106 AssertFailedReturnVoid();
1107 }
1108
1109 ComObjPtr<AdditionsFacility> ptrFac;
1110 ptrFac.createObject();
1111 AssertReturnVoid(!ptrFac.isNull());
1112
1113 HRESULT hrc = ptrFac->init(this, (AdditionsFacilityType_T)a_enmFacility, (AdditionsFacilityStatus_T)a_enmStatus,
1114 a_fFlags, a_pTimeSpecTS);
1115 if (SUCCEEDED(hrc))
1116 mData.mFacilityMap.insert(std::make_pair((AdditionsFacilityType_T)a_enmFacility, ptrFac));
1117 }
1118}
1119
1120/**
1121 * Sets the status of a certain Guest Additions facility.
1122 *
1123 * Gets called by vmmdevUpdateGuestStatus, which just passes the report along.
1124 *
1125 * @param a_pInterface Pointer to this interface.
1126 * @param a_enmFacility The facility.
1127 * @param a_enmStatus The status.
1128 * @param a_fFlags Flags assoicated with the update. Currently
1129 * reserved and should be ignored.
1130 * @param a_pTimeSpecTS Pointer to the timestamp of this report.
1131 * @sa PDMIVMMDEVCONNECTOR::pfnUpdateGuestStatus, vmmdevUpdateGuestStatus
1132 * @thread The emulation thread.
1133 */
1134void Guest::setAdditionsStatus(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus,
1135 uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS)
1136{
1137 Assert( a_enmFacility > VBoxGuestFacilityType_Unknown
1138 && a_enmFacility <= VBoxGuestFacilityType_All); /* Paranoia, VMMDev checks for this. */
1139
1140 AutoCaller autoCaller(this);
1141 AssertComRCReturnVoid(autoCaller.rc());
1142
1143 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1144
1145 /*
1146 * Set a specific facility status.
1147 */
1148 if (a_enmFacility == VBoxGuestFacilityType_All)
1149 for (FacilityMapIter it = mData.mFacilityMap.begin(); it != mData.mFacilityMap.end(); ++it)
1150 facilityUpdate((VBoxGuestFacilityType)it->first, a_enmStatus, a_fFlags, a_pTimeSpecTS);
1151 else /* Update one facility only. */
1152 facilityUpdate(a_enmFacility, a_enmStatus, a_fFlags, a_pTimeSpecTS);
1153
1154 /*
1155 * Recalc the runlevel.
1156 */
1157 if (facilityIsActive(VBoxGuestFacilityType_VBoxTrayClient))
1158 mData.mAdditionsRunLevel = AdditionsRunLevelType_Desktop;
1159 else if (facilityIsActive(VBoxGuestFacilityType_VBoxService))
1160 mData.mAdditionsRunLevel = AdditionsRunLevelType_Userland;
1161 else if (facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver))
1162 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
1163 else
1164 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
1165}
1166
1167/**
1168 * Sets the supported features (and whether they are active or not).
1169 *
1170 * @param fCaps Guest capability bit mask (VMMDEV_GUEST_SUPPORTS_XXX).
1171 */
1172void Guest::setSupportedFeatures(uint32_t aCaps)
1173{
1174 AutoCaller autoCaller(this);
1175 AssertComRCReturnVoid(autoCaller.rc());
1176
1177 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1178
1179 /** @todo A nit: The timestamp is wrong on saved state restore. Would be better
1180 * to move the graphics and seamless capability -> facility translation to
1181 * VMMDev so this could be saved. */
1182 RTTIMESPEC TimeSpecTS;
1183 RTTimeNow(&TimeSpecTS);
1184
1185 facilityUpdate(VBoxGuestFacilityType_Seamless,
1186 aCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
1187 0 /*fFlags*/, &TimeSpecTS);
1188 /** @todo Add VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING */
1189 facilityUpdate(VBoxGuestFacilityType_Graphics,
1190 aCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
1191 0 /*fFlags*/, &TimeSpecTS);
1192}
1193
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette