HRESULT USBDeviceFilters::insertDeviceFilter(ULONG aPosition, const ComPtr<IUSBDeviceFilter> &aFilter) { #ifdef VBOX_WITH_USB /* the machine needs to be mutable */ AutoMutableStateDependency adep(m->pParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); IUSBDeviceFilter *iFilter = aFilter; ComObjPtr<USBDeviceFilter> pFilter = static_cast<USBDeviceFilter*>(iFilter); if (pFilter->mInList) return setError(VBOX_E_INVALID_OBJECT_STATE, tr("The given USB device pFilter is already in the list")); /* backup the list before modification */ m->llDeviceFilters.backup(); /* iterate to the position... */ DeviceFilterList::iterator it; if (aPosition < m->llDeviceFilters->size()) { it = m->llDeviceFilters->begin(); std::advance(it, aPosition); } else it = m->llDeviceFilters->end(); /* ...and insert */ m->llDeviceFilters->insert(it, pFilter); pFilter->mInList = true; /* notify the proxy (only when it makes sense) */ if (pFilter->i_getData().mActive && Global::IsOnline(adep.machineState()) && pFilter->i_getData().mRemote.isMatch(false)) { USBProxyService *pProxySvc = m->pHost->i_usbProxyService(); ComAssertRet(pProxySvc, E_FAIL); ComAssertRet(pFilter->i_getId() == NULL, E_FAIL); pFilter->i_getId() = pProxySvc->insertFilter(&pFilter->i_getData().mUSBFilter); } alock.release(); AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); m->pParent->i_setModified(Machine::IsModified_USB); mlock.release(); return S_OK; #else /* VBOX_WITH_USB */ NOREF(aPosition); NOREF(aFilter); ReturnComNotImplemented(); #endif /* VBOX_WITH_USB */ }
/** * Handle a device which state changed in some significant way. * * This means things like running filters and subsequent capturing and * VM attaching. This may result in IPC and temporary lock abandonment. * * @param aDevice The device. * @param pllOpenedMachines list of running session machines (VirtualBox::getOpenedMachines()); if NULL, we don't run filters * @param aIgnoreMachine Machine to ignore when running filters. */ void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine) { /* * Validate preconditions. */ AssertReturnVoid(!isWriteLockOnCurrentThread()); AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread()); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n", (HostUSBDevice *)aDevice, aDevice->i_getName().c_str(), aDevice->i_getStateName(), aDevice->i_getId().raw(), (pllOpenedMachines != NULL), // used to be "bool aRunFilters" aIgnoreMachine)); devLock.release(); /* * Run filters if requested to do so. */ if (pllOpenedMachines) { HRESULT rc = runAllFiltersOnDevice(aDevice, *pllOpenedMachines, aIgnoreMachine); AssertComRC(rc); } }
/** * Performs the required actions when a device has been added. * * This means things like running filters and subsequent capturing and * VM attaching. This may result in IPC and temporary lock abandonment. * * @param aDevice The device in question. * @param aUSBDevice The USB device structure. */ void USBProxyService::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice) { /* * Validate preconditions. */ AssertReturnVoid(!isWriteLockOnCurrentThread()); AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread()); AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n", (HostUSBDevice *)aDevice, aDevice->i_getName().c_str(), aDevice->i_getStateName(), aDevice->i_getId().raw())); /* * Run filters on the device. */ if (aDevice->i_isCapturableOrHeld()) { devLock.release(); HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */); AssertComRC(rc); } NOREF(aUSBDevice); }
/** * Notification from VM process about USB device detaching progress. * * This is in an interface for SessionMachine::DetachUSBDevice(), which is * an internal worker used by Console::DetachUSBDevice() from the VM process. * * @param aMachine The machine which is sending the notification. * @param aId The UUID of the USB device is concerns. * @param aDone \a false for the pre-action notification (necessary * for advancing the device state to avoid confusing * the guest). * \a true for the post-action notification. The device * will be subjected to all filters except those of * of \a Machine. * * @returns COM status code. * * @remarks When \a aDone is \a true this method may end up doing IPC to other * VMs when running filters. In these cases it will temporarily * abandon its locks. */ HRESULT USBProxyService::detachDeviceFromVM(SessionMachine *aMachine, IN_GUID aId, bool aDone) { LogFlowThisFunc(("aMachine=%p{%s} aId={%RTuuid} aDone=%RTbool\n", aMachine, aMachine->i_getName().c_str(), Guid(aId).raw(), aDone)); // get a list of all running machines while we're outside the lock // (getOpenedMachines requests locks which are incompatible with the lock of the machines list) SessionMachinesList llOpenedMachines; mHost->i_parent()->i_getOpenedMachines(llOpenedMachines); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId); ComAssertRet(!pHostDevice.isNull(), E_FAIL); AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS); /* * Work the state machine. */ LogFlowThisFunc(("id={%RTuuid} state=%s aDone=%RTbool name={%s}\n", pHostDevice->i_getId().raw(), pHostDevice->i_getStateName(), aDone, pHostDevice->i_getName().c_str())); bool fRunFilters = false; HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters); /* * Run filters if necessary. */ if ( SUCCEEDED(hrc) && fRunFilters) { Assert(aDone && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->i_getMachine().isNull()); devLock.release(); alock.release(); HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine); ComAssertComRC(hrc2); } return hrc; }
/** * Remove device notification hook for the OS specific code. * * This is means things like * * @param aDevice The device in question. */ void USBProxyService::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice) { /* * Validate preconditions. */ AssertReturnVoid(!isWriteLockOnCurrentThread()); AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread()); AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n", (HostUSBDevice *)aDevice, aDevice->i_getName().c_str(), aDevice->i_getStateName(), aDevice->i_getId().raw())); /* * Detach the device from any machine currently using it, * reset all data and uninitialize the device object. */ devLock.release(); aDevice->i_onPhysicalDetached(); }
HRESULT USBDeviceFilters::removeDeviceFilter(ULONG aPosition, ComPtr<IUSBDeviceFilter> &aFilter) { #ifdef VBOX_WITH_USB /* the machine needs to be mutable */ AutoMutableStateDependency adep(m->pParent); if (FAILED(adep.rc())) return adep.rc(); AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); if (!m->llDeviceFilters->size()) return setError(E_INVALIDARG, tr("The USB device pFilter list is empty")); if (aPosition >= m->llDeviceFilters->size()) return setError(E_INVALIDARG, tr("Invalid position: %lu (must be in range [0, %lu])"), aPosition, m->llDeviceFilters->size() - 1); /* backup the list before modification */ m->llDeviceFilters.backup(); ComObjPtr<USBDeviceFilter> pFilter; { /* iterate to the position... */ DeviceFilterList::iterator it = m->llDeviceFilters->begin(); std::advance(it, aPosition); /* ...get an element from there... */ pFilter = *it; /* ...and remove */ pFilter->mInList = false; m->llDeviceFilters->erase(it); } /* cancel sharing (make an independent copy of data) */ pFilter->unshare(); pFilter.queryInterfaceTo(aFilter.asOutParam()); /* notify the proxy (only when it makes sense) */ if (pFilter->i_getData().mActive && Global::IsOnline(adep.machineState()) && pFilter->i_getData().mRemote.isMatch(false)) { USBProxyService *pProxySvc = m->pHost->i_usbProxyService(); ComAssertRet(pProxySvc, E_FAIL); ComAssertRet(pFilter->i_getId() != NULL, E_FAIL); pProxySvc->removeFilter(pFilter->i_getId()); pFilter->i_getId() = NULL; } alock.release(); AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); m->pParent->i_setModified(Machine::IsModified_USB); mlock.release(); return S_OK; #else /* VBOX_WITH_USB */ NOREF(aPosition); NOREF(aFilter); ReturnComNotImplemented(); #endif /* VBOX_WITH_USB */ }