VirtualBox

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

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

Missing DECLCALLBACK on Guest::staticUpdateStats.

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