VirtualBox

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

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

Main/Guest: fix logging which would crash because a smart pointer isn't the same as a pointer

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