VirtualBox

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

Last change on this file since 51612 was 51612, checked in by vboxsync, 10 years ago

6813 Use of server side API wrapper code - ConsoleImpl.cpp

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