VirtualBox

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

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

enabled shared clipboard support for Linux hosts (guest=>host only)

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