VirtualBox

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

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

Main/Guest: whitespace cleanup

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