VirtualBox

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

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

Main/Machine+Console+Display+VRDEServer,VBoxManage: allow VMs without graphics controller, eliminate annoying spurious error messages about Console not yet powered up when taking screenshots, getting/setting guest properties and updating metrics, make as many parameters to modifyvm as possible case insensitive

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