From 7243def78ca0f3ca56ad0a852cc40870046f12a3 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 30 Sep 2013 13:20:02 +0200 Subject: [PATCH] Android: Add AndroidSignalOperation. Allows to kill and interrupt remote processes with the pid. Change-Id: I22befc04dafbe2a7f132bddb3e17a2b48579ef3c Reviewed-by: Daniel Teske Reviewed-by: hjk --- src/plugins/android/android.pro | 6 +- src/plugins/android/android.qbs | 2 + src/plugins/android/androiddevice.cpp | 3 +- .../android/androidsignaloperation.cpp | 157 ++++++++++++++++++ src/plugins/android/androidsignaloperation.h | 82 +++++++++ 5 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 src/plugins/android/androidsignaloperation.cpp create mode 100644 src/plugins/android/androidsignaloperation.h diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro index 93df5b12456..5833827e345 100644 --- a/src/plugins/android/android.pro +++ b/src/plugins/android/android.pro @@ -48,7 +48,8 @@ HEADERS += \ androiddeployqtwidget.h \ createandroidmanifestwizard.h \ androidpotentialkit.h \ - androidextralibrarylistmodel.h + androidextralibrarylistmodel.h \ + androidsignaloperation.h SOURCES += \ androidconfigurations.cpp \ @@ -91,7 +92,8 @@ SOURCES += \ androiddeployqtwidget.cpp \ createandroidmanifestwizard.cpp \ androidpotentialkit.cpp \ - androidextralibrarylistmodel.cpp + androidextralibrarylistmodel.cpp \ + androidsignaloperation.cpp FORMS += \ androidsettingswidget.ui \ diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index ef1ffa7ea6e..9e9c1f867fb 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -104,6 +104,8 @@ QtcPlugin { "androidsettingswidget.cpp", "androidsettingswidget.h", "androidsettingswidget.ui", + "androidsignaloperation.cpp", + "androidsignaloperation.h", "androidtoolchain.cpp", "androidtoolchain.h", "certificatesmodel.cpp", diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index a1b75218970..20f9ceea6d6 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -29,6 +29,7 @@ #include "androiddevice.h" #include "androidconstants.h" +#include "androidsignaloperation.h" #include @@ -91,7 +92,7 @@ bool AndroidDevice::canAutoDetectPorts() const DeviceProcessSignalOperation::Ptr AndroidDevice::signalOperation() const { - return DeviceProcessSignalOperation::Ptr(); + return DeviceProcessSignalOperation::Ptr(new AndroidSignalOperation()); } IDevice::Ptr AndroidDevice::clone() const diff --git a/src/plugins/android/androidsignaloperation.cpp b/src/plugins/android/androidsignaloperation.cpp new file mode 100644 index 00000000000..8aa31400bbb --- /dev/null +++ b/src/plugins/android/androidsignaloperation.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "androidconfigurations.h" +#include "androidsignaloperation.h" + +#include + +#include + +Android::Internal::AndroidSignalOperation::AndroidSignalOperation() + : m_adbPath(AndroidConfigurations::instance().adbToolPath().toString()) + , m_adbProcess(new QProcess(this)) + , m_timeout(new QTimer(this)) + , m_state(Idle) + , m_pid(0) + , m_signal(0) +{ + m_timeout->setInterval(5000); + connect(m_timeout, SIGNAL(timeout()), this, SLOT(handleTimeout())); +} + +void Android::Internal::AndroidSignalOperation::adbFindRunAsFinished(int exitCode, + QProcess::ExitStatus exitStatus) +{ + QTC_ASSERT(m_state == RunAs, return); + m_timeout->stop(); + m_adbProcess->disconnect(this); + + QString runAs = QString::fromLatin1(m_adbProcess->readAllStandardOutput()); + if (exitStatus != QProcess::NormalExit) { + m_errorMessage = QLatin1String(" adb Exit code: ") + QString::number(exitCode); + QString adbError = m_adbProcess->errorString(); + if (!adbError.isEmpty()) + m_errorMessage += QLatin1String(" adb process error: ") + adbError; + } + if (runAs.isEmpty() || !m_errorMessage.isEmpty()) { + m_errorMessage = QLatin1String("Can not find User for process: ") + + QString::number(m_pid) + + m_errorMessage; + m_state = Idle; + emit finished(m_errorMessage); + } else { + connect(m_adbProcess, SIGNAL(finished(int,QProcess::ExitStatus)), + SLOT(adbKillFinished(int,QProcess::ExitStatus))); + m_state = Kill; + m_timeout->start(); + m_adbProcess->start(m_adbPath, QStringList() + << QLatin1String("shell") + << QLatin1String("run-as") + << runAs + << QLatin1String("kill") + << QString(QLatin1String("-%1")).arg(m_signal) + << QString::number(m_pid)); + } +} + +void Android::Internal::AndroidSignalOperation::adbKillFinished(int exitCode, + QProcess::ExitStatus exitStatus) +{ + QTC_ASSERT(m_state == Kill, return); + m_timeout->stop(); + m_adbProcess->disconnect(this); + + if (exitStatus != QProcess::NormalExit) { + m_errorMessage = QLatin1String(" adb process exit code: ") + QString::number(exitCode); + QString adbError = m_adbProcess->errorString(); + if (!adbError.isEmpty()) + m_errorMessage += QLatin1String(" adb process error: ") + adbError; + } else { + m_errorMessage = QString::fromLatin1(m_adbProcess->readAllStandardError()); + } + if (!m_errorMessage.isEmpty()) { + m_errorMessage = QLatin1String("Can not kill process: ") + QString::number(m_pid) + + m_errorMessage; + } + m_state = Idle; + emit finished(m_errorMessage); +} + +void Android::Internal::AndroidSignalOperation::handleTimeout() +{ + m_adbProcess->disconnect(this); + m_adbProcess->kill(); + m_timeout->stop(); + m_state = Idle; + m_errorMessage = QLatin1String("adb process timed out"); + emit finished(m_errorMessage); +} + +void Android::Internal::AndroidSignalOperation::signalOperationViaADB(int pid, int signal) +{ + QTC_ASSERT(m_state == Idle, return); + m_adbProcess->disconnect(this); + m_pid = pid; + m_signal = signal; + connect(m_adbProcess, SIGNAL(finished(int,QProcess::ExitStatus)), + SLOT(adbFindRunAsFinished(int,QProcess::ExitStatus))); + m_state = RunAs; + m_timeout->start(); + m_adbProcess->start(m_adbPath, QStringList() + << QLatin1String("shell") + << QLatin1String("cat") + << QString(QLatin1String("/proc/%1/cmdline")).arg(m_pid)); +} + +void Android::Internal::AndroidSignalOperation::killProcess(int pid) +{ + signalOperationViaADB(pid, 9); +} + +void Android::Internal::AndroidSignalOperation::killProcess(const QString &filePath) +{ + Q_UNUSED(filePath); + m_errorMessage = QLatin1String("The android signal operation does " + "not support killing by filepath."); + emit finished(m_errorMessage); +} + +void Android::Internal::AndroidSignalOperation::interruptProcess(int pid) +{ + signalOperationViaADB(pid, 2); +} + +void Android::Internal::AndroidSignalOperation::interruptProcess(const QString &filePath) +{ + Q_UNUSED(filePath); + m_errorMessage = QLatin1String("The android signal operation does " + "not support interrupting by filepath."); + emit finished(m_errorMessage); +} diff --git a/src/plugins/android/androidsignaloperation.h b/src/plugins/android/androidsignaloperation.h new file mode 100644 index 00000000000..8ee6f390f43 --- /dev/null +++ b/src/plugins/android/androidsignaloperation.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef ANDROIDSIGNALOPERATION_H +#define ANDROIDSIGNALOPERATION_H + +#include + +#include +#include +#include + +namespace Android { +namespace Internal { + +class AndroidSignalOperation : public ProjectExplorer::DeviceProcessSignalOperation +{ + Q_OBJECT +public: + ~AndroidSignalOperation() {} + void killProcess(int pid); + void killProcess(const QString &filePath); + void interruptProcess(int pid); + void interruptProcess(const QString &filePath); + +protected: + explicit AndroidSignalOperation(); + +private slots: + void adbFindRunAsFinished(int exitCode, QProcess::ExitStatus exitStatus); + void adbKillFinished(int exitCode, QProcess::ExitStatus exitStatus); + void handleTimeout(); + +private: + void signalOperationViaADB(int pid, int signal); + + QString m_adbPath; + QProcess *m_adbProcess; + QTimer *m_timeout; + + enum State { + Idle, + RunAs, + Kill + } m_state; + + int m_pid; + int m_signal; + + friend class AndroidDevice; +}; + +} // namespace Internal +} // namespace Android + +#endif // ANDROIDSIGNALOPERATION_H