Introduce static localProcesses() method to DeviceProcessList.

Add synchronous static getLocalProcesses() (platformspecific)
method to LocalProcessList, use that for the model, simplifying
the code of doUpdate(). Use that for
DeviceProcessList::localProcesses().

Polish the proclist-method for UNIX a bit such that it tries
to read out the 'cmdline' first to obtain the complete
command line and full path to the executable.

Similarly, set the absolute image path on Windows.

Implement doKill() on Windows.

Change-Id: I3a5b990eaa9f6beb4c589406bdf4c7a234e40734
Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
Friedemann Kleint
2012-08-23 10:19:58 +02:00
committed by hjk
parent aee8f8832b
commit 6a56990302
4 changed files with 81 additions and 45 deletions

View File

@@ -28,6 +28,7 @@
**************************************************************************/ **************************************************************************/
#include "deviceprocesslist.h" #include "deviceprocesslist.h"
#include "localprocesslist.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -181,6 +182,10 @@ void DeviceProcessList::reportError(const QString &message)
emit error(message); emit error(message);
} }
QList<DeviceProcess> DeviceProcessList::localProcesses()
{
return LocalProcessList::getLocalProcesses();
}
bool DeviceProcess::operator <(const DeviceProcess &other) const bool DeviceProcess::operator <(const DeviceProcess &other) const
{ {

View File

@@ -63,6 +63,8 @@ public:
void killProcess(int row); void killProcess(int row);
DeviceProcess at(int row) const; DeviceProcess at(int row) const;
static QList<DeviceProcess> localProcesses();
signals: signals:
void processListUpdated(); void processListUpdated();
void error(const QString &errorMsg); void error(const QString &errorMsg);

View File

@@ -97,7 +97,7 @@ LocalProcessList::LocalProcessList(const IDevice::ConstPtr &device, QObject *par
{ {
} }
void LocalProcessList::handleWindowsUpdate() QList<DeviceProcess> LocalProcessList::getLocalProcesses()
{ {
QList<DeviceProcess> processes; QList<DeviceProcess> processes;
@@ -105,30 +105,38 @@ void LocalProcessList::handleWindowsUpdate()
pe.dwSize = sizeof(PROCESSENTRY32); pe.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE) if (snapshot == INVALID_HANDLE_VALUE)
return; return processes;
for (bool hasNext = Process32First(snapshot, &pe); hasNext; hasNext = Process32Next(snapshot, &pe)) { for (bool hasNext = Process32First(snapshot, &pe); hasNext; hasNext = Process32Next(snapshot, &pe)) {
DeviceProcess p; DeviceProcess p;
p.pid = pe.th32ProcessID; p.pid = pe.th32ProcessID;
p.exe = QString::fromUtf16(reinterpret_cast<ushort*>(pe.szExeFile)); // Image has the absolute path, but can fail.
p.cmdLine = imageName(pe.th32ProcessID); const QString image = imageName(pe.th32ProcessID);
if (p.cmdLine.isEmpty()) p.exe = p.cmdLine = image.isEmpty() ?
p.cmdLine = p.exe; QString::fromWCharArray(pe.szExeFile) :
image;
processes << p; processes << p;
} }
CloseHandle(snapshot); CloseHandle(snapshot);
return processes;
reportProcessListUpdated(processes);
}
void LocalProcessList::doUpdate()
{
QTimer::singleShot(0, this, SLOT(handleWindowsUpdate()));
} }
void LocalProcessList::doKillProcess(const DeviceProcess &process) void LocalProcessList::doKillProcess(const DeviceProcess &process)
{ {
Q_UNUSED(process); const DWORD rights = PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION
|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ
|PROCESS_DUP_HANDLE|PROCESS_TERMINATE|PROCESS_CREATE_THREAD|PROCESS_SUSPEND_RESUME;
const HANDLE handle = OpenProcess(rights, FALSE, process.pid);
if (!handle) {
qWarning("Cannot open process %d: %s" , process.pid,
qPrintable(Utils::winErrorMessage(GetLastError())));
return;
}
if (!TerminateProcess(handle, UINT(-1))) {
qWarning("Cannot terminate process %d: %s" , process.pid,
qPrintable(Utils::winErrorMessage(GetLastError())));
}
CloseHandle(handle);
} }
#endif //Q_OS_WIN #endif //Q_OS_WIN
@@ -150,38 +158,53 @@ static bool isUnixProcessId(const QString &procname)
// Determine UNIX processes by reading "/proc". Default to ps if // Determine UNIX processes by reading "/proc". Default to ps if
// it does not exist // it does not exist
void LocalProcessList::updateUsingProc()
static const char procDirC[] = "/proc/";
static QList<DeviceProcess> getLocalProcessesUsingProc(const QDir &procDir)
{ {
QList<DeviceProcess> processes; QList<DeviceProcess> processes;
const QDir procDir(QLatin1String("/proc/")); const QString procDirPath = QLatin1String(procDirC);
const QStringList procIds = procDir.entryList(); const QStringList procIds = procDir.entryList();
foreach (const QString &procId, procIds) { foreach (const QString &procId, procIds) {
if (!isUnixProcessId(procId)) if (!isUnixProcessId(procId))
continue; continue;
QString filename = QLatin1String("/proc/");
filename += procId;
filename += QLatin1String("/stat");
QFile file(filename);
if (!file.open(QIODevice::ReadOnly))
continue; // process may have exited
const QStringList data = QString::fromLocal8Bit(file.readAll()).split(QLatin1Char(' '));
DeviceProcess proc; DeviceProcess proc;
proc.pid = procId.toInt(); proc.pid = procId.toInt();
const QString root = procDirPath + procId;
QFile cmdLineFile(root + QLatin1String("/cmdline"));
if (cmdLineFile.open(QIODevice::ReadOnly)) { // process may have exited
QList<QByteArray> tokens = cmdLineFile.readAll().split('\0');
if (!tokens.isEmpty()) {
proc.exe = QString::fromLocal8Bit(tokens.front());
foreach (const QByteArray &t, tokens) {
if (!proc.cmdLine.isEmpty())
proc.cmdLine.append(QLatin1Char(' '));
proc.cmdLine.append(QString::fromLocal8Bit(t));
}
}
}
if (proc.exe.isEmpty()) {
QFile statFile(root + QLatin1String("/stat"));
if (!statFile.open(QIODevice::ReadOnly)) {
const QStringList data = QString::fromLocal8Bit(statFile.readAll()).split(QLatin1Char(' '));
proc.exe = data.at(1); proc.exe = data.at(1);
proc.cmdLine = data.at(1); proc.cmdLine = data.at(1); // PPID is element 3
if (proc.exe.startsWith(QLatin1Char('(')) && proc.exe.endsWith(QLatin1Char(')'))) { if (proc.exe.startsWith(QLatin1Char('(')) && proc.exe.endsWith(QLatin1Char(')'))) {
proc.exe.truncate(proc.exe.size() - 1); proc.exe.truncate(proc.exe.size() - 1);
proc.exe.remove(0, 1); proc.exe.remove(0, 1);
} }
// PPID is element 3 }
}
if (!proc.exe.isEmpty())
processes.push_back(proc); processes.push_back(proc);
} }
reportProcessListUpdated(processes); return processes;
} }
// Determine UNIX processes by running ps // Determine UNIX processes by running ps
void LocalProcessList::updateUsingPs() static QList<DeviceProcess> getLocalProcessesUsingPs()
{ {
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
static const char formatC[] = "pid state command"; static const char formatC[] = "pid state command";
@@ -214,16 +237,13 @@ void LocalProcessList::updateUsingPs()
} }
} }
} }
reportProcessListUpdated(processes); return processes;
} }
void LocalProcessList::doUpdate() QList<DeviceProcess> LocalProcessList::getLocalProcesses()
{ {
const QDir procDir(QLatin1String("/proc/")); const QDir procDir = QDir(QLatin1String(procDirC));
if (procDir.exists()) return procDir.exists() ? getLocalProcessesUsingProc(procDir) : getLocalProcessesUsingPs();
QTimer::singleShot(0, this, SLOT(updateUsingProc()));
else
QTimer::singleShot(0, this, SLOT(updateUsingPs()));
} }
void LocalProcessList::doKillProcess(const DeviceProcess &process) void LocalProcessList::doKillProcess(const DeviceProcess &process)
@@ -252,5 +272,15 @@ Qt::ItemFlags LocalProcessList::flags(const QModelIndex &index) const
return flags; return flags;
} }
void LocalProcessList::handleUpdate()
{
reportProcessListUpdated(getLocalProcesses());
}
void LocalProcessList::doUpdate()
{
QTimer::singleShot(0, this, SLOT(handleUpdate()));
}
} // namespace Internal } // namespace Internal
} // namespace RemoteLinux } // namespace RemoteLinux

View File

@@ -49,17 +49,16 @@ public:
LocalProcessList(const IDevice::ConstPtr &device, QObject *parent = 0); LocalProcessList(const IDevice::ConstPtr &device, QObject *parent = 0);
virtual Qt::ItemFlags flags(const QModelIndex &index) const; virtual Qt::ItemFlags flags(const QModelIndex &index) const;
static QList<DeviceProcess> getLocalProcesses();
private: private:
void doUpdate(); void doUpdate();
void doKillProcess(const DeviceProcess &process); void doKillProcess(const DeviceProcess &process);
private slots: private slots:
#if defined(Q_OS_WIN) void handleUpdate();
void handleWindowsUpdate(); #ifdef Q_OS_UNIX
#elif defined(Q_OS_UNIX)
void reportDelayedKillStatus(); void reportDelayedKillStatus();
void updateUsingProc();
void updateUsingPs();
#endif #endif
private: private: