VirtualBox

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

Last change on this file since 45029 was 44903, checked in by vboxsync, 12 years ago

Guest::updateStats: Don't divide by zero.

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

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