VirtualBox

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

Last change on this file since 39435 was 39418, checked in by vboxsync, 13 years ago

GuestCtrl: Added support for explicitly waiting on stdout/stderr, bugfixes, logging adjustments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.3 KB
Line 
1/* $Id: GuestImpl.cpp 39418 2011-11-25 10:11:06Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Guest
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "GuestImpl.h"
19
20#include "Global.h"
21#include "ConsoleImpl.h"
22#include "ProgressImpl.h"
23#include "VMMDev.h"
24
25#include "AutoCaller.h"
26#include "Logging.h"
27
28#include <VBox/VMMDev.h>
29#ifdef VBOX_WITH_GUEST_CONTROL
30# include <VBox/com/array.h>
31# include <VBox/com/ErrorInfo.h>
32#endif
33#include <iprt/cpp/utils.h>
34#include <VBox/vmm/pgm.h>
35
36// defines
37/////////////////////////////////////////////////////////////////////////////
38
39// constructor / destructor
40/////////////////////////////////////////////////////////////////////////////
41
42DEFINE_EMPTY_CTOR_DTOR (Guest)
43
44HRESULT Guest::FinalConstruct()
45{
46 return BaseFinalConstruct();
47}
48
49void Guest::FinalRelease()
50{
51 uninit ();
52 BaseFinalRelease();
53}
54
55// public methods only for internal purposes
56/////////////////////////////////////////////////////////////////////////////
57
58/**
59 * Initializes the guest object.
60 */
61HRESULT Guest::init(Console *aParent)
62{
63 LogFlowThisFunc(("aParent=%p\n", aParent));
64
65 ComAssertRet(aParent, E_INVALIDARG);
66
67 /* Enclose the state transition NotReady->InInit->Ready */
68 AutoInitSpan autoInitSpan(this);
69 AssertReturn(autoInitSpan.isOk(), E_FAIL);
70
71 unconst(mParent) = aParent;
72
73 /* Confirm a successful initialization when it's the case */
74 autoInitSpan.setSucceeded();
75
76 ULONG aMemoryBalloonSize;
77 HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
78 if (ret == S_OK)
79 mMemoryBalloonSize = aMemoryBalloonSize;
80 else
81 mMemoryBalloonSize = 0; /* Default is no ballooning */
82
83 BOOL fPageFusionEnabled;
84 ret = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
85 if (ret == S_OK)
86 mfPageFusionEnabled = fPageFusionEnabled;
87 else
88 mfPageFusionEnabled = false; /* Default is no page fusion*/
89
90 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
91
92 /* Clear statistics. */
93 for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++)
94 mCurrentGuestStat[i] = 0;
95
96#ifdef VBOX_WITH_GUEST_CONTROL
97 /* Init the context ID counter at 1000. */
98 mNextContextID = 1000;
99#endif
100
101 return S_OK;
102}
103
104/**
105 * Uninitializes the instance and sets the ready flag to FALSE.
106 * Called either from FinalRelease() or by the parent when it gets destroyed.
107 */
108void Guest::uninit()
109{
110 LogFlowThisFunc(("\n"));
111
112#ifdef VBOX_WITH_GUEST_CONTROL
113 /* Scope write lock as much as possible. */
114 {
115 /*
116 * Cleanup must be done *before* AutoUninitSpan to cancel all
117 * all outstanding waits in API functions (which hold AutoCaller
118 * ref counts).
119 */
120 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
121
122 /* Notify left over callbacks that we are about to shutdown ... */
123 CallbackMapIter it;
124 for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
125 {
126 int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
127 Guest::tr("VM is shutting down, canceling uncompleted guest requests ..."));
128 AssertRC(rc2);
129 }
130
131 /* Destroy left over callback data. */
132 for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
133 callbackDestroy(it->first);
134
135 /* Clear process map. */
136 mGuestProcessMap.clear();
137 }
138#endif
139
140 /* Enclose the state transition Ready->InUninit->NotReady */
141 AutoUninitSpan autoUninitSpan(this);
142 if (autoUninitSpan.uninitDone())
143 return;
144
145 unconst(mParent) = NULL;
146}
147
148// IGuest properties
149/////////////////////////////////////////////////////////////////////////////
150
151STDMETHODIMP Guest::COMGETTER(OSTypeId)(BSTR *aOSTypeId)
152{
153 CheckComArgOutPointerValid(aOSTypeId);
154
155 AutoCaller autoCaller(this);
156 if (FAILED(autoCaller.rc())) return autoCaller.rc();
157
158 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
159
160 /* Redirect the call to IMachine if no additions are installed. */
161 if (mData.mAdditionsVersion.isEmpty())
162 return mParent->machine()->COMGETTER(OSTypeId)(aOSTypeId);
163
164 mData.mOSTypeId.cloneTo(aOSTypeId);
165
166 return S_OK;
167}
168
169STDMETHODIMP Guest::COMGETTER(AdditionsRunLevel) (AdditionsRunLevelType_T *aRunLevel)
170{
171 AutoCaller autoCaller(this);
172 if (FAILED(autoCaller.rc())) return autoCaller.rc();
173
174 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
175
176 *aRunLevel = mData.mAdditionsRunLevel;
177
178 return S_OK;
179}
180
181STDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
182{
183 CheckComArgOutPointerValid(aAdditionsVersion);
184
185 AutoCaller autoCaller(this);
186 if (FAILED(autoCaller.rc())) return autoCaller.rc();
187
188 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
189
190 HRESULT hr = S_OK;
191 if ( mData.mAdditionsVersion.isEmpty()
192 /* Only try alternative way if GA are active! */
193 && mData.mAdditionsRunLevel > AdditionsRunLevelType_None)
194 {
195 /*
196 * If we got back an empty string from GetAdditionsVersion() we either
197 * really don't have the Guest Additions version yet or the guest is running
198 * older Guest Additions (< 3.2.0) which don't provide VMMDevReq_ReportGuestInfo2,
199 * so get the version + revision from the (hopefully) provided guest properties
200 * instead.
201 */
202 Bstr addVersion;
203 LONG64 u64Timestamp;
204 Bstr flags;
205 hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Version").raw(),
206 addVersion.asOutParam(), &u64Timestamp, flags.asOutParam());
207 if (hr == S_OK)
208 {
209 Bstr addRevision;
210 hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Revision").raw(),
211 addRevision.asOutParam(), &u64Timestamp, flags.asOutParam());
212 if ( hr == S_OK
213 && !addVersion.isEmpty()
214 && !addRevision.isEmpty())
215 {
216 /* Some Guest Additions versions had interchanged version + revision values,
217 * so check if the version value at least has a dot to identify it and change
218 * both values to reflect the right content. */
219 if (!Utf8Str(addVersion).contains("."))
220 {
221 Bstr addTemp = addVersion;
222 addVersion = addRevision;
223 addRevision = addTemp;
224 }
225
226 Bstr additionsVersion = BstrFmt("%ls r%ls",
227 addVersion.raw(), addRevision.raw());
228 additionsVersion.cloneTo(aAdditionsVersion);
229 }
230 /** @todo r=bird: else: Should not return failure! */
231 }
232 else
233 {
234 /* If getting the version + revision above fails or they simply aren't there
235 * because of *really* old Guest Additions we only can report the interface
236 * version to at least have something. */
237 mData.mInterfaceVersion.cloneTo(aAdditionsVersion);
238 /** @todo r=bird: hr is still indicating failure! */
239 }
240 }
241 else
242 mData.mAdditionsVersion.cloneTo(aAdditionsVersion);
243
244 return hr;
245}
246
247STDMETHODIMP Guest::COMGETTER(Facilities)(ComSafeArrayOut(IAdditionsFacility*, aFacilities))
248{
249 CheckComArgOutPointerValid(aFacilities);
250
251 AutoCaller autoCaller(this);
252 if (FAILED(autoCaller.rc())) return autoCaller.rc();
253
254 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
255
256 SafeIfaceArray<IAdditionsFacility> fac(mData.mFacilityMap);
257 fac.detachTo(ComSafeArrayOutArg(aFacilities));
258
259 return S_OK;
260}
261
262BOOL Guest::isPageFusionEnabled()
263{
264 AutoCaller autoCaller(this);
265 if (FAILED(autoCaller.rc())) return false;
266
267 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
268
269 return mfPageFusionEnabled;
270}
271
272STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize)(ULONG *aMemoryBalloonSize)
273{
274 CheckComArgOutPointerValid(aMemoryBalloonSize);
275
276 AutoCaller autoCaller(this);
277 if (FAILED(autoCaller.rc())) return autoCaller.rc();
278
279 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
280
281 *aMemoryBalloonSize = mMemoryBalloonSize;
282
283 return S_OK;
284}
285
286STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize)(ULONG aMemoryBalloonSize)
287{
288 AutoCaller autoCaller(this);
289 if (FAILED(autoCaller.rc())) return autoCaller.rc();
290
291 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
292
293 /* We must be 100% sure that IMachine::COMSETTER(MemoryBalloonSize)
294 * does not call us back in any way! */
295 HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
296 if (ret == S_OK)
297 {
298 mMemoryBalloonSize = aMemoryBalloonSize;
299 /* forward the information to the VMM device */
300 VMMDev *pVMMDev = mParent->getVMMDev();
301 /* MUST release all locks before calling VMM device as its critsect
302 * has higher lock order than anything in Main. */
303 alock.release();
304 if (pVMMDev)
305 {
306 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
307 if (pVMMDevPort)
308 pVMMDevPort->pfnSetMemoryBalloon(pVMMDevPort, aMemoryBalloonSize);
309 }
310 }
311
312 return ret;
313}
314
315STDMETHODIMP Guest::COMGETTER(StatisticsUpdateInterval)(ULONG *aUpdateInterval)
316{
317 CheckComArgOutPointerValid(aUpdateInterval);
318
319 AutoCaller autoCaller(this);
320 if (FAILED(autoCaller.rc())) return autoCaller.rc();
321
322 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
323
324 *aUpdateInterval = mStatUpdateInterval;
325 return S_OK;
326}
327
328STDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval)(ULONG aUpdateInterval)
329{
330 AutoCaller autoCaller(this);
331 if (FAILED(autoCaller.rc())) return autoCaller.rc();
332
333 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
334
335 mStatUpdateInterval = aUpdateInterval;
336 /* forward the information to the VMM device */
337 VMMDev *pVMMDev = mParent->getVMMDev();
338 /* MUST release all locks before calling VMM device as its critsect
339 * has higher lock order than anything in Main. */
340 alock.release();
341 if (pVMMDev)
342 {
343 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
344 if (pVMMDevPort)
345 pVMMDevPort->pfnSetStatisticsInterval(pVMMDevPort, aUpdateInterval);
346 }
347
348 return S_OK;
349}
350
351STDMETHODIMP Guest::InternalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
352 ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemShared,
353 ULONG *aMemCache, ULONG *aPageTotal,
354 ULONG *aMemAllocTotal, ULONG *aMemFreeTotal, ULONG *aMemBalloonTotal, ULONG *aMemSharedTotal)
355{
356 CheckComArgOutPointerValid(aCpuUser);
357 CheckComArgOutPointerValid(aCpuKernel);
358 CheckComArgOutPointerValid(aCpuIdle);
359 CheckComArgOutPointerValid(aMemTotal);
360 CheckComArgOutPointerValid(aMemFree);
361 CheckComArgOutPointerValid(aMemBalloon);
362 CheckComArgOutPointerValid(aMemShared);
363 CheckComArgOutPointerValid(aMemCache);
364 CheckComArgOutPointerValid(aPageTotal);
365 CheckComArgOutPointerValid(aMemAllocTotal);
366 CheckComArgOutPointerValid(aMemFreeTotal);
367 CheckComArgOutPointerValid(aMemBalloonTotal);
368 CheckComArgOutPointerValid(aMemSharedTotal);
369
370 AutoCaller autoCaller(this);
371 if (FAILED(autoCaller.rc())) return autoCaller.rc();
372
373 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
374
375 *aCpuUser = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER];
376 *aCpuKernel = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL];
377 *aCpuIdle = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE];
378 *aMemTotal = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
379 *aMemFree = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K); /* page (4K) -> 1KB units */
380 *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K); /* page (4K) -> 1KB units */
381 *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K); /* page (4K) -> 1KB units */
382 *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
383
384 /* MUST release all locks before calling any PGM statistics queries,
385 * as they are executed by EMT and that might deadlock us by VMM device
386 * activity which waits for the Guest object lock. */
387 alock.release();
388 Console::SafeVMPtr pVM (mParent);
389 if (pVM.isOk())
390 {
391 uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal, uSharedTotal;
392 *aMemFreeTotal = 0;
393 int rc = PGMR3QueryGlobalMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal, &uSharedTotal);
394 AssertRC(rc);
395 if (rc == VINF_SUCCESS)
396 {
397 *aMemAllocTotal = (ULONG)(uAllocTotal / _1K); /* bytes -> KB */
398 *aMemFreeTotal = (ULONG)(uFreeTotal / _1K);
399 *aMemBalloonTotal = (ULONG)(uBalloonedTotal / _1K);
400 *aMemSharedTotal = (ULONG)(uSharedTotal / _1K);
401 }
402 else
403 return E_FAIL;
404
405 /* Query the missing per-VM memory statistics. */
406 *aMemShared = 0;
407 uint64_t uTotalMem, uPrivateMem, uSharedMem, uZeroMem;
408 rc = PGMR3QueryMemoryStats(pVM.raw(), &uTotalMem, &uPrivateMem, &uSharedMem, &uZeroMem);
409 if (rc == VINF_SUCCESS)
410 {
411 *aMemShared = (ULONG)(uSharedMem / _1K);
412 }
413 else
414 return E_FAIL;
415 }
416 else
417 {
418 *aMemAllocTotal = 0;
419 *aMemFreeTotal = 0;
420 *aMemBalloonTotal = 0;
421 *aMemSharedTotal = 0;
422 *aMemShared = 0;
423 return E_FAIL;
424 }
425
426 return S_OK;
427}
428
429HRESULT Guest::setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal)
430{
431 AutoCaller autoCaller(this);
432 if (FAILED(autoCaller.rc())) return autoCaller.rc();
433
434 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
435
436 if (enmType >= GUESTSTATTYPE_MAX)
437 return E_INVALIDARG;
438
439 mCurrentGuestStat[enmType] = aVal;
440 return S_OK;
441}
442
443/**
444 * Returns the status of a specified Guest Additions facility.
445 *
446 * @return aStatus Current status of specified facility.
447 * @param aType Facility to get the status from.
448 * @param aTimestamp Timestamp of last facility status update in ms (optional).
449 */
450STDMETHODIMP Guest::GetFacilityStatus(AdditionsFacilityType_T aType, LONG64 *aTimestamp, AdditionsFacilityStatus_T *aStatus)
451{
452 AutoCaller autoCaller(this);
453 if (FAILED(autoCaller.rc())) return autoCaller.rc();
454
455 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
456
457 CheckComArgNotNull(aStatus);
458 /* Not checking for aTimestamp is intentional; it's optional. */
459
460 FacilityMapIterConst it = mData.mFacilityMap.find(aType);
461 if (it != mData.mFacilityMap.end())
462 {
463 AdditionsFacility *pFacility = it->second;
464 ComAssert(pFacility);
465 *aStatus = pFacility->getStatus();
466 if (aTimestamp)
467 *aTimestamp = pFacility->getLastUpdated();
468 }
469 else
470 {
471 /*
472 * Do not fail here -- could be that the facility never has been brought up (yet) but
473 * the host wants to have its status anyway. So just tell we don't know at this point.
474 */
475 *aStatus = AdditionsFacilityStatus_Unknown;
476 if (aTimestamp)
477 *aTimestamp = RTTimeMilliTS();
478 }
479 return S_OK;
480}
481
482STDMETHODIMP Guest::GetAdditionsStatus(AdditionsRunLevelType_T aLevel, BOOL *aActive)
483{
484 AutoCaller autoCaller(this);
485 if (FAILED(autoCaller.rc())) return autoCaller.rc();
486
487 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
488
489 HRESULT rc = S_OK;
490 switch (aLevel)
491 {
492 case AdditionsRunLevelType_System:
493 *aActive = (mData.mAdditionsRunLevel > AdditionsRunLevelType_None);
494 break;
495
496 case AdditionsRunLevelType_Userland:
497 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Userland);
498 break;
499
500 case AdditionsRunLevelType_Desktop:
501 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Desktop);
502 break;
503
504 default:
505 rc = setError(VBOX_E_NOT_SUPPORTED,
506 tr("Invalid status level defined: %u"), aLevel);
507 break;
508 }
509
510 return rc;
511}
512
513STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
514 IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
515{
516 AutoCaller autoCaller(this);
517 if (FAILED(autoCaller.rc())) return autoCaller.rc();
518
519 /* forward the information to the VMM device */
520 VMMDev *pVMMDev = mParent->getVMMDev();
521 if (pVMMDev)
522 {
523 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
524 if (pVMMDevPort)
525 {
526 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
527 if (!aAllowInteractiveLogon)
528 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
529
530 pVMMDevPort->pfnSetCredentials(pVMMDevPort,
531 Utf8Str(aUserName).c_str(),
532 Utf8Str(aPassword).c_str(),
533 Utf8Str(aDomain).c_str(),
534 u32Flags);
535 return S_OK;
536 }
537 }
538
539 return setError(VBOX_E_VM_ERROR,
540 tr("VMM device is not available (is the VM running?)"));
541}
542
543// public methods only for internal purposes
544/////////////////////////////////////////////////////////////////////////////
545
546/**
547 * Sets the general Guest Additions information like
548 * API (interface) version and OS type. Gets called by
549 * vmmdevUpdateGuestInfo.
550 *
551 * @param aInterfaceVersion
552 * @param aOsType
553 */
554void Guest::setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType)
555{
556 AutoCaller autoCaller(this);
557 AssertComRCReturnVoid(autoCaller.rc());
558
559 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
560
561 /*
562 * Note: The Guest Additions API (interface) version is deprecated
563 * and will not be used anymore! We might need it to at least report
564 * something as version number if *really* ancient Guest Additions are
565 * installed (without the guest version + revision properties having set).
566 */
567 mData.mInterfaceVersion = aInterfaceVersion;
568
569 /*
570 * Older Additions rely on the Additions API version whether they
571 * are assumed to be active or not. Since newer Additions do report
572 * the Additions version *before* calling this function (by calling
573 * VMMDevReportGuestInfo2, VMMDevReportGuestStatus, VMMDevReportGuestInfo,
574 * in that order) we can tell apart old and new Additions here. Old
575 * Additions never would set VMMDevReportGuestInfo2 (which set mData.mAdditionsVersion)
576 * so they just rely on the aInterfaceVersion string (which gets set by
577 * VMMDevReportGuestInfo).
578 *
579 * So only mark the Additions as being active (run level = system) when we
580 * don't have the Additions version set.
581 */
582 if (mData.mAdditionsVersion.isEmpty())
583 {
584 if (aInterfaceVersion.isEmpty())
585 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
586 else
587 {
588 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
589
590 /*
591 * To keep it compatible with the old Guest Additions behavior we need to set the
592 * "graphics" (feature) facility to active as soon as we got the Guest Additions
593 * interface version.
594 */
595 facilityUpdate(VBoxGuestFacilityType_Graphics, VBoxGuestFacilityStatus_Active);
596 }
597 }
598
599 /*
600 * Older Additions didn't have this finer grained capability bit,
601 * so enable it by default. Newer Additions will not enable this here
602 * and use the setSupportedFeatures function instead.
603 */
604 facilityUpdate(VBoxGuestFacilityType_Graphics, facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver) ?
605 VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive);
606
607 /*
608 * Note! There is a race going on between setting mAdditionsRunLevel and
609 * mSupportsGraphics here and disabling/enabling it later according to
610 * its real status when using new(er) Guest Additions.
611 */
612 mData.mOSTypeId = Global::OSTypeId(aOsType);
613}
614
615/**
616 * Sets the Guest Additions version information details.
617 * Gets called by vmmdevUpdateGuestInfo2.
618 *
619 * @param aAdditionsVersion
620 * @param aVersionName
621 */
622void Guest::setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision)
623{
624 AutoCaller autoCaller(this);
625 AssertComRCReturnVoid(autoCaller.rc());
626
627 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
628
629 if (!aVersionName.isEmpty())
630 /*
631 * aVersionName could be "x.y.z_BETA1_FOOBAR", so append revision manually to
632 * become "x.y.z_BETA1_FOOBAR r12345".
633 */
634 mData.mAdditionsVersion = BstrFmt("%ls r%ls", aVersionName.raw(), aRevision.raw());
635 else /* aAdditionsVersion is in x.y.zr12345 format. */
636 mData.mAdditionsVersion = aAdditionsVersion;
637}
638
639bool Guest::facilityIsActive(VBoxGuestFacilityType enmFacility)
640{
641 Assert(enmFacility < INT32_MAX);
642 FacilityMapIterConst it = mData.mFacilityMap.find((AdditionsFacilityType_T)enmFacility);
643 if (it != mData.mFacilityMap.end())
644 {
645 AdditionsFacility *pFac = it->second;
646 return (pFac->getStatus() == AdditionsFacilityStatus_Active);
647 }
648 return false;
649}
650
651HRESULT Guest::facilityUpdate(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus)
652{
653 ComAssertRet(enmFacility < INT32_MAX, E_INVALIDARG);
654
655 HRESULT rc;
656 RTTIMESPEC tsNow;
657 RTTimeNow(&tsNow);
658
659 FacilityMapIter it = mData.mFacilityMap.find((AdditionsFacilityType_T)enmFacility);
660 if (it != mData.mFacilityMap.end())
661 {
662 AdditionsFacility *pFac = it->second;
663 rc = pFac->update((AdditionsFacilityStatus_T)enmStatus, tsNow);
664 }
665 else
666 {
667 ComObjPtr<AdditionsFacility> pFacility;
668 pFacility.createObject();
669 ComAssert(!pFacility.isNull());
670 rc = pFacility->init(this,
671 (AdditionsFacilityType_T)enmFacility,
672 (AdditionsFacilityStatus_T)enmStatus);
673 if (SUCCEEDED(rc))
674 mData.mFacilityMap.insert(std::make_pair((AdditionsFacilityType_T)enmFacility, pFacility));
675 }
676
677 LogFlowFunc(("Returned with rc=%Rrc\n"));
678 return rc;
679}
680
681/**
682 * Sets the status of a certain Guest Additions facility.
683 * Gets called by vmmdevUpdateGuestStatus.
684 *
685 * @param enmFacility Facility to set the status for.
686 * @param enmStatus Actual status to set.
687 * @param aFlags
688 */
689void Guest::setAdditionsStatus(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus, ULONG aFlags)
690{
691 AutoCaller autoCaller(this);
692 AssertComRCReturnVoid(autoCaller.rc());
693
694 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
695
696 /*
697 * Set overall additions run level.
698 */
699
700 /* First check for disabled status. */
701 uint32_t uCurFacility = enmFacility + (enmStatus == VBoxGuestFacilityStatus_Active ? 0 : -1);
702 if ( enmFacility < VBoxGuestFacilityType_VBoxGuestDriver
703 || ( enmFacility == VBoxGuestFacilityType_All
704 && enmStatus == VBoxGuestFacilityStatus_Inactive)
705 )
706 {
707 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
708 }
709 else if (uCurFacility >= VBoxGuestFacilityType_VBoxTrayClient)
710 {
711 mData.mAdditionsRunLevel = AdditionsRunLevelType_Desktop;
712 }
713 else if (uCurFacility >= VBoxGuestFacilityType_VBoxService)
714 {
715 mData.mAdditionsRunLevel = AdditionsRunLevelType_Userland;
716 }
717 else if (uCurFacility >= VBoxGuestFacilityType_VBoxGuestDriver)
718 {
719 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
720 }
721 else /* Should never happen! */
722 AssertMsgFailed(("Invalid facility status/run level detected! uCurFacility=%d\n", uCurFacility));
723
724 /*
725 * Set a specific facility status.
726 */
727 if (enmFacility > VBoxGuestFacilityType_Unknown)
728 {
729 if (enmFacility == VBoxGuestFacilityType_All)
730 {
731 FacilityMapIter it = mData.mFacilityMap.begin();
732 while (it != mData.mFacilityMap.end())
733 {
734 facilityUpdate((VBoxGuestFacilityType)it->first, enmStatus);
735 it++;
736 }
737 }
738 else /* Update one facility only. */
739 facilityUpdate(enmFacility, enmStatus);
740 }
741}
742
743/**
744 * Sets the supported features (and whether they are active or not).
745 *
746 * @param fCaps Guest capability bit mask (VMMDEV_GUEST_SUPPORTS_XXX).
747 */
748void Guest::setSupportedFeatures(uint32_t aCaps)
749{
750 AutoCaller autoCaller(this);
751 AssertComRCReturnVoid(autoCaller.rc());
752
753 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
754
755 facilityUpdate(VBoxGuestFacilityType_Seamless, aCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ?
756 VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive);
757 /** @todo Add VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING */
758 facilityUpdate(VBoxGuestFacilityType_Graphics, aCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ?
759 VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive);
760}
761/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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