VirtualBox

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

Last change on this file since 44535 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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