VirtualBox

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

Last change on this file since 40192 was 40084, checked in by vboxsync, 13 years ago

Main/Metrics: Guests now push collected metrics to VBoxSVC instead of being polled (#6029)

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

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