tizendevice.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2013 Jarek Pelczar <jpelczar@gmail.com>
  4. **
  5. ** This file is part of Qt Creator.
  6. **
  7. ** Commercial License Usage
  8. ** Licensees holding valid commercial Qt licenses may use this file in
  9. ** accordance with the commercial license agreement provided with the
  10. ** Software or, alternatively, in accordance with the terms contained in
  11. ** a written agreement between you and Digia. For licensing terms and
  12. ** conditions see http://qt.digia.com/licensing. For further information
  13. ** use the contact form at http://qt.digia.com/contact-us.
  14. **
  15. ** GNU Lesser General Public License Usage
  16. ** Alternatively, this file may be used under the terms of the GNU Lesser
  17. ** General Public License version 2.1 as published by the Free Software
  18. ** Foundation and appearing in the file LICENSE.LGPL included in the
  19. ** packaging of this file. Please review the following information to
  20. ** ensure the GNU Lesser General Public License version 2.1 requirements
  21. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  22. **
  23. ** In addition, as a special exception, Digia gives you certain additional
  24. ** rights. These rights are described in the Digia Qt LGPL Exception
  25. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  26. **
  27. ****************************************************************************/
  28. #include "tizendevice.h"
  29. #include "tizenconstants.h"
  30. #include "tizendevicetester.h"
  31. #include "sdbcommandexecutor.h"
  32. #include <QCoreApplication>
  33. #include <projectexplorer/devicesupport/deviceprocesslist.h>
  34. #include <utils/qtcassert.h>
  35. #include <utils/consoleprocess.h>
  36. #include "tizenconfigurations.h"
  37. using namespace ProjectExplorer;
  38. namespace Tizen {
  39. const char Delimiter0[] = "x--";
  40. const char Delimiter1[] = "---";
  41. static QString visualizeNull(QString s)
  42. {
  43. return s.replace(QLatin1Char('\0'), QLatin1String("<null>"));
  44. }
  45. class TizenDeviceProcessList : public ProjectExplorer::DeviceProcessList
  46. {
  47. Q_OBJECT
  48. public:
  49. Tizen::SdbCommandExecutor * m_executor;
  50. QPointer<Tizen::SdbConnector> m_connector;
  51. TizenDeviceProcessList(const ProjectExplorer::IDevice::ConstPtr& device, QPointer<Tizen::SdbConnector> conn, QObject * parent = 0);
  52. virtual ~TizenDeviceProcessList();
  53. virtual void doUpdate();
  54. virtual void doKillProcess(const ProjectExplorer::DeviceProcess &process);
  55. QList<DeviceProcess> buildProcessList(const QString &listProcessesReply) const
  56. {
  57. qDebug() << "Response is " << listProcessesReply;
  58. QList<DeviceProcess> processes;
  59. const QStringList lines = listProcessesReply.split(QString::fromLatin1(Delimiter0)
  60. + QString::fromLatin1(Delimiter1), QString::SkipEmptyParts);
  61. foreach (const QString &line, lines) {
  62. const QStringList elements = line.split(QLatin1Char('\n'));
  63. if (elements.count() < 4) {
  64. qDebug("%s: Expected four list elements, got %d. Line was '%s'.", Q_FUNC_INFO,
  65. elements.count(), qPrintable(visualizeNull(line)));
  66. continue;
  67. }
  68. bool ok;
  69. const int pid = elements.first().mid(6).toInt(&ok);
  70. if (!ok) {
  71. qDebug("%s: Expected number in %s. Line was '%s'.", Q_FUNC_INFO,
  72. qPrintable(elements.first()), qPrintable(visualizeNull(line)));
  73. continue;
  74. }
  75. QString command = elements.at(1);
  76. command.replace(QLatin1Char('\0'), QLatin1Char(' '));
  77. if (command.isEmpty()) {
  78. const QString &statString = elements.at(2);
  79. const int openParenPos = statString.indexOf(QLatin1Char('('));
  80. const int closedParenPos = statString.indexOf(QLatin1Char(')'), openParenPos);
  81. if (openParenPos == -1 || closedParenPos == -1)
  82. continue;
  83. command = QLatin1Char('[')
  84. + statString.mid(openParenPos + 1, closedParenPos - openParenPos - 1)
  85. + QLatin1Char(']');
  86. }
  87. DeviceProcess process;
  88. process.pid = pid;
  89. process.cmdLine = command;
  90. process.exe = elements.at(3);
  91. processes.append(process);
  92. }
  93. qSort(processes);
  94. return processes;
  95. }
  96. public slots:
  97. void handleListFinished();
  98. void handleKillFinished();
  99. void handleError();
  100. };
  101. TizenDeviceProcessList::TizenDeviceProcessList(const ProjectExplorer::IDevice::ConstPtr& device, QPointer<Tizen::SdbConnector> conn, QObject * parent) :
  102. ProjectExplorer::DeviceProcessList(device, parent),
  103. m_executor(NULL),
  104. m_connector(conn)
  105. {
  106. }
  107. TizenDeviceProcessList::~TizenDeviceProcessList()
  108. {
  109. }
  110. static QString listProcessesCommandLine()
  111. {
  112. return QString::fromLatin1(
  113. "for dir in `ls -d /proc/[0123456789]*`; do "
  114. "test -d $dir || continue;" // Decrease the likelihood of a race condition.
  115. "echo $dir;"
  116. "cat $dir/cmdline;echo;" // cmdline does not end in newline
  117. "cat $dir/stat;"
  118. "readlink -q $dir/exe;"
  119. "printf '%1''%2';"
  120. "done").arg(QLatin1String(Delimiter0)).arg(QLatin1String(Delimiter1));
  121. }
  122. void TizenDeviceProcessList::doUpdate()
  123. {
  124. QTC_ASSERT(!m_executor, return);
  125. QTC_ASSERT(!m_connector.isNull(), return);
  126. m_executor = new Tizen::SdbCommandExecutor(m_connector.data(), this);
  127. connect(m_executor, SIGNAL(finished()), SLOT(handleListFinished()));
  128. connect(m_executor, SIGNAL(failed()), SLOT(handleError()));
  129. m_executor->start(device()->id().toString(), listProcessesCommandLine());
  130. }
  131. void TizenDeviceProcessList::doKillProcess(const DeviceProcess &process)
  132. {
  133. QTC_ASSERT(!m_executor, return);
  134. QTC_ASSERT(!m_connector.isNull(), return);
  135. m_executor = new Tizen::SdbCommandExecutor(m_connector.data(), this);
  136. connect(m_executor, SIGNAL(finished()), SLOT(handleKillFinished()));
  137. connect(m_executor, SIGNAL(failed()), SLOT(handleError()));
  138. m_executor->start(device()->id().toString(),
  139. device()->processSupport()->killProcessByPidCommandLine(process.pid));
  140. }
  141. void TizenDeviceProcessList::handleListFinished()
  142. {
  143. QByteArray remoteStdout = m_executor->readAll();
  144. m_executor->disconnect(this);
  145. m_executor->deleteLater();
  146. m_executor = NULL;
  147. reportProcessListUpdated(buildProcessList(QString::fromUtf8(remoteStdout.constData(), remoteStdout.size())));
  148. }
  149. void TizenDeviceProcessList::handleKillFinished()
  150. {
  151. m_executor->disconnect(this);
  152. m_executor->deleteLater();
  153. m_executor = NULL;
  154. reportProcessKilled();
  155. }
  156. void TizenDeviceProcessList::handleError()
  157. {
  158. reportError(tr("Communication failure"));
  159. }
  160. QString TizenDeviceProcessSupport::killProcessByPidCommandLine(int pid) const
  161. {
  162. return QLatin1String("kill -9 ") + QString::number(pid);
  163. }
  164. QString TizenDeviceProcessSupport::killProcessByNameCommandLine(const QString &filePath) const
  165. {
  166. return QString::fromLatin1("cd /proc; for pid in `ls -d [0123456789]*`; "
  167. "do "
  168. "if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then "
  169. " kill $pid; sleep 1; kill -9 $pid; "
  170. "fi; "
  171. "done").arg(filePath);
  172. }
  173. static QString signalProcessByNameCommandLine(const QString &filePath, int signal)
  174. {
  175. return QString::fromLatin1("cd /proc; for pid in `ls -d [0123456789]*`; "
  176. "do "
  177. "if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then "
  178. " kill %2 $pid;"
  179. "fi; "
  180. "done").arg(filePath).arg(signal);
  181. }
  182. QString TizenDeviceProcessSupport::interruptProcessByNameCommandLine(const QString &filePath) const
  183. {
  184. return signalProcessByNameCommandLine(filePath, 2);
  185. }
  186. TizenDevice::DevPtr TizenDevice::create(Core::Id id, DeviceState state, const QString &name)
  187. {
  188. return DevPtr(new TizenDevice(id, state, name));
  189. }
  190. TizenPortsGatheringMethod::~TizenPortsGatheringMethod()
  191. {
  192. }
  193. QByteArray TizenPortsGatheringMethod::commandLine(QAbstractSocket::NetworkLayerProtocol protocol) const
  194. {
  195. QString procFilePath;
  196. int addressLength;
  197. if (protocol == QAbstractSocket::IPv4Protocol) {
  198. procFilePath = QLatin1String("/proc/net/tcp");
  199. addressLength = 8;
  200. } else {
  201. procFilePath = QLatin1String("/proc/net/tcp6");
  202. addressLength = 32;
  203. }
  204. return QString::fromLatin1("sed "
  205. "'s/.*: [[:xdigit:]]\\{%1\\}:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' %2")
  206. .arg(addressLength).arg(procFilePath).toUtf8();
  207. }
  208. QList<int> TizenPortsGatheringMethod::usedPorts(const QByteArray &output) const
  209. {
  210. QList<int> ports;
  211. QList<QByteArray> portStrings = output.split('\n');
  212. portStrings.removeFirst();
  213. foreach (const QByteArray &portString, portStrings) {
  214. if (portString.isEmpty())
  215. continue;
  216. bool ok;
  217. const int port = portString.toInt(&ok, 16);
  218. if (ok) {
  219. if (!ports.contains(port))
  220. ports << port;
  221. } else {
  222. qWarning("%s: Unexpected string '%s' is not a port.",
  223. Q_FUNC_INFO, portString.data());
  224. }
  225. }
  226. return ports;
  227. }
  228. TizenDevice::TizenDevice()
  229. {
  230. }
  231. TizenDevice::TizenDevice(Core::Id id, DeviceState state, const QString& name) :
  232. IDevice(Constants::TIZEN_DEVICE_TYPE, AutoDetected, Hardware, id)
  233. {
  234. setDeviceState(state);
  235. setDisplayName(name);
  236. }
  237. TizenDevice::~TizenDevice()
  238. {
  239. }
  240. QString TizenDevice::displayType() const
  241. {
  242. return tr("Tizen Device");
  243. }
  244. ProjectExplorer::IDeviceWidget * TizenDevice::createWidget()
  245. {
  246. return NULL;
  247. }
  248. QList<Core::Id> TizenDevice::actionIds() const
  249. {
  250. return QList<Core::Id>() << Constants::DEVICE_ACTION_ROOT << Constants::DEVICE_ACTION_SHELL;
  251. }
  252. QString TizenDevice::displayNameForActionId(Core::Id id) const
  253. {
  254. if(id == Constants::DEVICE_ACTION_ROOT)
  255. return tr("Root mode");
  256. if(id == Constants::DEVICE_ACTION_SHELL)
  257. return tr("Shell");
  258. return QString();
  259. }
  260. void TizenDevice::executeAction(Core::Id id, QWidget *) const
  261. {
  262. if(id == Constants::DEVICE_ACTION_SHELL) {
  263. QString sdbPath = TizenConfigurations::instance()->tizenConfig().m_sdbLocation.toString();
  264. Utils::ConsoleProcess * process = new Utils::ConsoleProcess();
  265. if(!process->start(sdbPath, QString(QLatin1String("-s %1 shell")).arg(this->id().toString()))) {
  266. delete process;
  267. return;
  268. }
  269. QObject::connect(process, SIGNAL(processStopped(int,QProcess::ExitStatus)), process, SLOT(deleteLater()));
  270. }
  271. }
  272. TizenDevice::Ptr TizenDevice::clone() const
  273. {
  274. return Ptr(new TizenDevice(*this));
  275. }
  276. ProjectExplorer::DeviceProcessSupport::Ptr TizenDevice::processSupport() const
  277. {
  278. return DeviceProcessSupport::Ptr(new TizenDeviceProcessSupport);
  279. }
  280. ProjectExplorer::DeviceProcessList * TizenDevice::createProcessListModel(QObject *parent) const
  281. {
  282. return new TizenDeviceProcessList(sharedFromThis(), m_connector, parent);
  283. }
  284. ProjectExplorer::PortsGatheringMethod::Ptr TizenDevice::portsGatheringMethod() const
  285. {
  286. return ProjectExplorer::PortsGatheringMethod::Ptr(new TizenPortsGatheringMethod);
  287. }
  288. //ProjectExplorer::DeviceTester * TizenDevice::createDeviceTester() const
  289. //{
  290. // return new TizenDeviceTester(m_connector);
  291. //}
  292. } // namespace Tizen
  293. #include "tizendevice.moc"