diff options
author | Assam Boudjelthia <assam.boudjelthia@qt.io> | 2021-10-29 18:19:54 +0300 |
---|---|---|
committer | Assam Boudjelthia <assam.boudjelthia@qt.io> | 2022-02-22 21:21:53 +0000 |
commit | c43ba1ae329937db62c4824311fe017b68b6033f (patch) | |
tree | 32b867844606e990c2b37518b648a8de1a17c6ea | |
parent | d8b5d2b7a552547d0c5d4d1ba904fbde76a319a2 (diff) | |
download | qt-creator-c43ba1ae329937db62c4824311fe017b68b6033f.tar.gz |
Monitor Android devices in non-polling method
Use ADB's track-devices command to watch for device
events which would replace the current polling method
with a timer. For AVDs, a QFileSystemWatcher is used
to watch for changes in the AVDs home folder which
would allow updating the AVDs only when a change is done
like edition, deletion, start, stop, even from outside
Qt Creator.
This method would also make device updates faster,
instead of unexpected waits due to timer use.
Task-number: QTCREATORBUG-23991
Change-Id: I08a92252c99c02bc111e597d671f2350817458c7
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
-rw-r--r-- | src/plugins/android/androidconfigurations.cpp | 43 | ||||
-rw-r--r-- | src/plugins/android/androidconfigurations.h | 6 | ||||
-rw-r--r-- | src/plugins/android/androiddevice.cpp | 284 | ||||
-rw-r--r-- | src/plugins/android/androiddevice.h | 24 |
4 files changed, 212 insertions, 145 deletions
diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 9de48da0ee..7400020bbb 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com> ** Contact: https://www.qt.io/licensing/ ** @@ -752,48 +753,6 @@ QString AndroidConfig::getAvdName(const QString &serialnumber) return QString::fromLatin1(name).trimmed(); } -static SdkToolResult emulatorNameAdbCommand(const QString &serialNumber) -{ - QStringList args = AndroidDeviceInfo::adbSelector(serialNumber); - args.append({"emu", "avd", "name"}); - return AndroidManager::runAdbCommand(args); -} - -QString AndroidConfig::getRunningAvdsSerialNumber(const QString &name) const -{ - for (const AndroidDeviceInfo &dev : connectedDevices()) { - if (!dev.serialNumber.startsWith("emulator")) - continue; - SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber); - const QString stdOut = result.stdOut(); - if (stdOut.isEmpty()) - continue; // Not an avd - const QStringList outputLines = stdOut.split('\n'); - if (outputLines.size() > 1 && outputLines.first() == name) - return dev.serialNumber; - } - - return {}; -} - -QStringList AndroidConfig::getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs) -{ - QStringList runningDevs; - for (const AndroidDeviceInfo &dev : devs) { - if (!dev.serialNumber.startsWith("emulator")) - continue; - SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber); - const QString stdOut = result.stdOut(); - if (stdOut.isEmpty()) - continue; // Not an avd - const QStringList outputLines = stdOut.split('\n'); - if (outputLines.size() > 1) - runningDevs.append(outputLines.first()); - } - - return runningDevs; -} - AndroidConfig::OpenGl AndroidConfig::getOpenGLEnabled(const QString &emulator) const { QDir dir = QDir::home(); diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 7492ae0f2a..5338845d0d 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com> ** Contact: https://www.qt.io/licensing/ ** @@ -176,15 +177,12 @@ public: static Utils::FilePath getJdkPath(); static QStringList getAbis(const QString &device); - - QString getRunningAvdsSerialNumber(const QString &name) const; - static QStringList getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs); + static int getSDKVersion(const QString &device); private: static QString getDeviceProperty(const QString &device, const QString &property); Utils::FilePath openJDKBinPath() const; - static int getSDKVersion(const QString &device); static QString getAvdName(const QString &serialnumber); void parseDependenciesJson(); diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index a14b985ad7..b7927d0aa8 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com> ** Contact: https://www.qt.io/licensing/ ** @@ -52,6 +52,9 @@ #include <QLoggingCategory> #include <QMessageBox> #include <QPushButton> +#include <QTimer> + +#include <utils/qtcprocess.h> using namespace ProjectExplorer; @@ -59,9 +62,6 @@ namespace { static Q_LOGGING_CATEGORY(androidDeviceLog, "qtc.android.androiddevice", QtWarningMsg) } -// interval for updating the list of connected Android devices and emulators -constexpr int deviceUpdaterMsInterval = 30000; - namespace Android { namespace Internal { @@ -328,7 +328,7 @@ QString AndroidDevice::serialNumber() const if (machineType() == Hardware) return serialNumber; - return AndroidConfigurations::currentConfig().getRunningAvdsSerialNumber(avdName()); + return AndroidDeviceManager::instance()->getRunningAvdsSerialNumber(avdName()); } QString AndroidDevice::avdName() const @@ -419,36 +419,28 @@ QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const return url; } -void AndroidDeviceManager::updateDevicesList() +void AndroidDeviceManager::updateAvdsList() { - // If a non-Android Kit is currently active, skip the device list update - const Target *startupTarget = SessionManager::startupTarget(); - if (!startupTarget) - return; - - const Kit *kit = startupTarget->kit(); - if (!kit) - return; - - if (DeviceTypeKitAspect::deviceTypeId(kit) != Constants::ANDROID_DEVICE_TYPE) - return; - - updateDevicesListOnce(); + if (!m_avdsFutureWatcher.isRunning() && m_androidConfig.adbToolPath().exists()) + m_avdsFutureWatcher.setFuture(m_avdManager.avdList()); } -void AndroidDeviceManager::updateDevicesListOnce() +IDevice::DeviceState AndroidDeviceManager::getDeviceState(const QString &serial, + IDevice::MachineType type) const { - if (!m_avdsFutureWatcher.isRunning() && m_androidConfig.adbToolPath().exists()) { - m_avdsFutureWatcher.setFuture(m_avdManager.avdList()); - m_devicesFutureWatcher.setFuture(Utils::runAsync([this]() { - return m_androidConfig.connectedDevices(); - })); - } + const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo 1"; + const SdkToolResult result = AndroidManager::runAdbCommand(args); + if (result.success()) + return IDevice::DeviceReadyToUse; + else if (type == IDevice::Emulator || result.stdErr().contains("unauthorized")) + return IDevice::DeviceConnected; + + return IDevice::DeviceDisconnected; } -void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::Ptr &device) +void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::ConstPtr &device) { - const AndroidDevice *dev = static_cast<AndroidDevice *>(device.data()); + const AndroidDevice *dev = static_cast<const AndroidDevice *>(device.data()); const QString serial = dev->serialNumber(); DeviceManager *const devMgr = DeviceManager::instance(); const Utils::Id id = dev->id(); @@ -457,15 +449,7 @@ void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::Ptr return; } - const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo" << "1"; - const SdkToolResult result = AndroidManager::runAdbCommand(args); - const int success = result.success(); - if (success) - devMgr->setDeviceState(id, IDevice::DeviceReadyToUse); - else if (dev->machineType() == IDevice::Emulator || result.stdErr().contains("unauthorized")) - devMgr->setDeviceState(id, IDevice::DeviceConnected); - else - devMgr->setDeviceState(id, IDevice::DeviceDisconnected); + devMgr->setDeviceState(id, getDeviceState(serial, dev->machineType())); } void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent) @@ -523,6 +507,13 @@ void AndroidDeviceManager::handleAvdRemoved() } } +QString AndroidDeviceManager::emulatorName(const QString &serialNumber) const +{ + QStringList args = AndroidDeviceInfo::adbSelector(serialNumber); + args.append({"emu", "avd", "name"}); + return AndroidManager::runAdbCommand(args).stdOut(); +} + void AndroidDeviceManager::setEmulatorArguments(QWidget *parent) { const QString helpUrl = @@ -546,73 +537,121 @@ void AndroidDeviceManager::setEmulatorArguments(QWidget *parent) m_androidConfig.setEmulatorArgs(Utils::ProcessArgs::splitArgs(dialog.textValue())); } -void AndroidDeviceManager::setupDevicesWatcher() +QString AndroidDeviceManager::getRunningAvdsSerialNumber(const QString &name) const { - if (!m_devicesUpdaterTimer.isActive()) { - // The call to avdmanager is always slower than the call to adb devices, - // so connecting the slot to the slower call should be enough. - connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished, - this, &AndroidDeviceManager::devicesListUpdated); - connect(&m_devicesUpdaterTimer, &QTimer::timeout, this, [this]() { - updateDevicesList(); - }); - m_devicesUpdaterTimer.start(deviceUpdaterMsInterval); + for (const AndroidDeviceInfo &dev : m_androidConfig.connectedDevices()) { + if (!dev.serialNumber.startsWith("emulator")) + continue; + const QString stdOut = emulatorName(dev.serialNumber); + if (stdOut.isEmpty()) + continue; // Not an avd + const QStringList outputLines = stdOut.split('\n'); + if (outputLines.size() > 1 && outputLines.first() == name) + return dev.serialNumber; } - updateDevicesListOnce(); + + return {}; } -void AndroidDeviceManager::devicesListUpdated() +void AndroidDeviceManager::setupDevicesWatcher() { - QVector<AndroidDeviceInfo> connectedDevicesInfos; - connectedDevicesInfos = m_devicesFutureWatcher.result(); + if (!m_androidConfig.adbToolPath().exists()) { + qCDebug(androidDeviceLog) << "Cannot start ADB device watcher" + << "because adb path does not exist."; + return; + } - // For checking the state of avds, since running avds are assigned a serial number of - // the form emulator-xxxx, thus we have to manually check for the names. - const QStringList runningAvds = m_androidConfig.getRunningAvdsFromDevices(connectedDevicesInfos); + if (!m_adbDeviceWatcherProcess) + m_adbDeviceWatcherProcess.reset(new Utils::QtcProcess(this)); - AndroidDeviceInfoList devices = m_avdsFutureWatcher.result(); - const QSet<QString> startedAvds = Utils::transform<QSet>(connectedDevicesInfos, - &AndroidDeviceInfo::avdname); - for (const AndroidDeviceInfo &dev : devices) - if (!startedAvds.contains(dev.avdname)) - connectedDevicesInfos << dev; + if (m_adbDeviceWatcherProcess->isRunning()) { + qCDebug(androidDeviceLog) << "ADB device watcher is already running."; + return; + } - DeviceManager *const devMgr = DeviceManager::instance(); + connect(m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::finished, this, + []() { qCDebug(androidDeviceLog) << "ADB device watcher finished."; }); - QVector<IDevice::ConstPtr> existingDevs; - QVector<IDevice::ConstPtr> connectedDevs; + connect(m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::errorOccurred, this, + [this](QProcess::ProcessError error) { + qCDebug(androidDeviceLog) << "ADB device watcher encountered an error:" + << m_adbDeviceWatcherProcess->errorString(); + if (!m_adbDeviceWatcherProcess->isRunning()) { + qCDebug(androidDeviceLog) << "Restarting the ADB device watcher now."; + QTimer::singleShot(0, m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::start); + } + }); + + m_adbDeviceWatcherProcess->setStdErrLineCallback([](const QString &error) { + qCDebug(androidDeviceLog) << "ADB device watcher error" << error; }); + m_adbDeviceWatcherProcess->setStdOutLineCallback([this](const QString &output) { + HandleDevicesListChange(output); + }); + + const Utils::CommandLine command = Utils::CommandLine(m_androidConfig.adbToolPath(), + {"track-devices"}); + m_adbDeviceWatcherProcess->setCommand(command); + m_adbDeviceWatcherProcess->setEnvironment(AndroidConfigurations::toolsEnvironment(m_androidConfig)); + m_adbDeviceWatcherProcess->start(); + + // Setup AVD filesystem watcher to listen for changes when an avd is created/deleted, + // or started/stopped + QString avdEnvVar = qEnvironmentVariable("ANDROID_AVD_HOME"); + if (avdEnvVar.isEmpty()) { + avdEnvVar = qEnvironmentVariable("ANDROID_SDK_HOME"); + if (avdEnvVar.isEmpty()) + avdEnvVar = qEnvironmentVariable("HOME"); + avdEnvVar.append("/.android/avd"); + } + const Utils::FilePath avdPath = Utils::FilePath::fromUserInput(avdEnvVar); + m_avdFileSystemWatcher.addPath(avdPath.toString()); + connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished, + this, &AndroidDeviceManager::HandleAvdsListChange); + connect(&m_avdFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, [this]() { + // If the avd list upate command is running no need to call it again. + if (!m_avdsFutureWatcher.isRunning()) + updateAvdsList(); + }); + // Call initial update + updateAvdsList(); +} +void AndroidDeviceManager::HandleAvdsListChange() +{ + DeviceManager *const devMgr = DeviceManager::instance(); + + QVector<IDevice::ConstPtr> existingAvds; for (int i = 0; i < devMgr->deviceCount(); ++i) { const IDevice::ConstPtr dev = devMgr->deviceAt(i); - if (dev->id().toString().startsWith(Constants::ANDROID_DEVICE_ID)) { - existingDevs.append(dev); - } + const bool isEmulator = dev->machineType() == IDevice::Emulator; + if (isEmulator && dev->type() == Constants::ANDROID_DEVICE_TYPE) + existingAvds.append(dev); } - for (auto item : connectedDevicesInfos) { + QVector<IDevice::ConstPtr> connectedDevs; + for (auto item : m_avdsFutureWatcher.result()) { const Utils::Id deviceId = AndroidDevice::idFromDeviceInfo(item); const QString displayName = AndroidDevice::displayNameFromInfo(item); IDevice::ConstPtr dev = devMgr->find(deviceId); if (!dev.isNull()) { - if (dev->displayName() == displayName) { - IDevice::DeviceState newState; - // If an AVD is not already running set its state to Connected instead of - // ReadyToUse. - if (dev->machineType() == IDevice::Emulator && !runningAvds.contains(displayName)) - newState = IDevice::DeviceConnected; - else - newState = item.state; - if (dev->deviceState() != newState) { + const auto androidDev = static_cast<const AndroidDevice *>(dev.data()); + // DeviceManager doens't seem to hav a way to directly update the name, if the name + // of the device has changed, remove it and register it again with the new name. + // Also account for the case of an AVD registered through old QC which might have + // invalid data by checking the sdcard size value. + if (dev->displayName() != displayName || androidDev->sdcardSize() == tr("Unknown")) { + devMgr->removeDevice(dev->id()); + } else { + // Find the state of the AVD retrieved from the AVD watcher + const QString serial = getRunningAvdsSerialNumber(item.avdname); + const IDevice::DeviceState state = getDeviceState(serial, IDevice::Emulator); + if (dev->deviceState() != state) { + devMgr->setDeviceState(dev->id(), state); qCDebug(androidDeviceLog, "Device id \"%s\" changed its state.", dev->id().toString().toUtf8().data()); - devMgr->setDeviceState(dev->id(), newState); } connectedDevs.append(dev); continue; - } else { - // DeviceManager doens't seem to hav a way to directly update the name, if the name - // of the device has changed, remove it and register it again with the new name. - devMgr->removeDevice(dev->id()); } } @@ -625,17 +664,79 @@ void AndroidDeviceManager::devicesListUpdated() qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".", newDev->id().toString().toUtf8().data()); const IDevice::ConstPtr constNewDev = IDevice::ConstPtr(newDev); - devMgr->addDevice(constNewDev); + devMgr->addDevice(IDevice::ConstPtr(constNewDev)); connectedDevs.append(constNewDev); + + // Set devices no longer connected to disconnected state. + for (const IDevice::ConstPtr &dev : existingAvds) { + if (!connectedDevs.contains(dev)) { + qCDebug(androidDeviceLog, "Removing AVD id \"%s\" because it no longer exists.", + dev->id().toString().toUtf8().data()); + devMgr->removeDevice(dev->id()); + } + } } +} - // Set devices no longer connected to disconnected state. - for (const IDevice::ConstPtr &dev : existingDevs) { - if (dev->id() != Constants::ANDROID_DEVICE_ID && !connectedDevs.contains(dev) - && dev->deviceState() != IDevice::DeviceDisconnected) { - qCDebug(androidDeviceLog, "Device id \"%s\" is no longer connected.", - dev->id().toString().toUtf8().data()); - devMgr->setDeviceState(dev->id(), IDevice::DeviceDisconnected); +void AndroidDeviceManager::HandleDevicesListChange(const QString &serialNumber) +{ + DeviceManager *const devMgr = DeviceManager::instance(); + const QStringList serialBits = serialNumber.split('\t'); + if (serialBits.size() < 2) + return; + + // Sample output of adb track-devices, the first 4 digits are for state type + // and sometimes 4 zeros are reported as part for the serial number. + // 00546db0e8d7 authorizing + // 00546db0e8d7 device + // 0000001711201JEC207789 offline + // emulator-5554 device + QString dirtySerial = serialBits.first().trimmed(); + if (dirtySerial.startsWith("0000")) + dirtySerial = dirtySerial.mid(4); + if (dirtySerial.startsWith("00")) + dirtySerial = dirtySerial.mid(4); + const bool isEmulator = dirtySerial.startsWith("emulator"); + + const QString &serial = dirtySerial; + const QString stateStr = serialBits.at(1).trimmed(); + + IDevice::DeviceState state; + if (stateStr == "device") + state = IDevice::DeviceReadyToUse; + else if (stateStr == "offline") + state = IDevice::DeviceDisconnected; + else + state = IDevice::DeviceConnected; + + if (isEmulator) { + const QString avdName = emulatorName(serial); + const Utils::Id avdId = Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + avdName); + devMgr->setDeviceState(avdId, state); + } else { + const Utils::Id id = Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + serial); + const QString displayName = AndroidConfigurations::currentConfig().getProductModel(serial); + if (IDevice::ConstPtr dev = devMgr->find(id)) { + // DeviceManager doens't seem to have a way to directly update the name, if the name + // of the device has changed, remove it and register it again with the new name. + if (dev->displayName() == displayName) + devMgr->setDeviceState(id, state); + else + devMgr->removeDevice(id); + } else { + AndroidDevice *newDev = new AndroidDevice(); + newDev->setupId(IDevice::AutoDetected, id); + newDev->setDisplayName(displayName); + newDev->setMachineType(IDevice::Hardware); + newDev->setDeviceState(state); + + newDev->setExtraData(Constants::AndroidSerialNumber, serial); + newDev->setExtraData(Constants::AndroidCpuAbi, m_androidConfig.getAbis(serial)); + newDev->setExtraData(Constants::AndroidSdk, m_androidConfig.getSDKVersion(serial)); + + qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".", + newDev->id().toString().toUtf8().data()); + devMgr->addDevice(IDevice::ConstPtr(newDev)); } } } @@ -652,9 +753,10 @@ AndroidDeviceManager::AndroidDeviceManager(QObject *parent) m_avdManager(m_androidConfig) { connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() { - m_devicesUpdaterTimer.stop(); + m_adbDeviceWatcherProcess->terminate(); + m_adbDeviceWatcherProcess->waitForFinished(); + m_adbDeviceWatcherProcess.reset(); m_avdsFutureWatcher.waitForFinished(); - m_devicesFutureWatcher.waitForFinished(); m_removeAvdFutureWatcher.waitForFinished(); }); diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index 3d08f09315..8a8abe70ad 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com> ** Contact: https://www.qt.io/licensing/ ** @@ -33,8 +33,10 @@ #include <projectexplorer/devicesupport/idevice.h> #include <projectexplorer/devicesupport/idevicefactory.h> +#include <utils/qtcprocess.h> + #include <QFutureWatcher> -#include <QTimer> +#include <QFileSystemWatcher> namespace Android { namespace Internal { @@ -70,6 +72,7 @@ public: QString androidTargetName() const; QString sdcardSize() const; QString openGlStatusString() const; + // TODO: remove not used AndroidConfig::OpenGl openGlStatus() const; protected: @@ -98,24 +101,29 @@ class AndroidDeviceManager : public QObject public: static AndroidDeviceManager *instance(); void setupDevicesWatcher(); - void updateDevicesList(); - void updateDevicesListOnce(); - void updateDeviceState(const ProjectExplorer::IDevice::Ptr &device); + void updateAvdsList(); + IDevice::DeviceState getDeviceState(const QString &serial, IDevice::MachineType type) const; + void updateDeviceState(const ProjectExplorer::IDevice::ConstPtr &device); void startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr); void eraseAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr); void setEmulatorArguments(QWidget *parent = nullptr); + QString getRunningAvdsSerialNumber(const QString &name) const; + private: AndroidDeviceManager(QObject *parent = nullptr); - void devicesListUpdated(); + void HandleDevicesListChange(const QString &serialNumber); + void HandleAvdsListChange(); void handleAvdRemoved(); + QString emulatorName(const QString &serialNumber) const; + QFutureWatcher<AndroidDeviceInfoList> m_avdsFutureWatcher; - QFutureWatcher<QVector<AndroidDeviceInfo>> m_devicesFutureWatcher; QFutureWatcher<QPair<ProjectExplorer::IDevice::ConstPtr, bool>> m_removeAvdFutureWatcher; - QTimer m_devicesUpdaterTimer; + QFileSystemWatcher m_avdFileSystemWatcher; + std::unique_ptr<Utils::QtcProcess> m_adbDeviceWatcherProcess; AndroidConfig &m_androidConfig; AndroidAvdManager m_avdManager; }; |