iosrunner.cpp 8.67 KB
Newer Older
1
2
/****************************************************************************
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
** 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 "iosbuildstep.h"
#include "iosconfigurations.h"
#include "iosdevice.h"
#include "iosmanager.h"
#include "iosrunconfiguration.h"
#include "iosrunner.h"
#include "iossimulator.h"
37
#include "iosconstants.h"
38
39
40
41

#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
Fawzi Mohamed's avatar
Fawzi Mohamed committed
42
43
#include <projectexplorer/taskhub.h>
#include <projectexplorer/projectexplorerconstants.h>
Fawzi Mohamed's avatar
Fawzi Mohamed committed
44
#include <debugger/debuggerrunconfigurationaspect.h>
45
46
47
48

#include <QDir>
#include <QTime>
#include <QMessageBox>
Fawzi Mohamed's avatar
Fawzi Mohamed committed
49
#include <QRegExp>
50

51
52
#include <signal.h>

Fawzi Mohamed's avatar
Fawzi Mohamed committed
53
54
using namespace ProjectExplorer;

55
56
57
namespace Ios {
namespace Internal {

Fawzi Mohamed's avatar
Fawzi Mohamed committed
58
IosRunner::IosRunner(QObject *parent, IosRunConfiguration *runConfig, bool cppDebug, bool qmlDebug)
59
    : QObject(parent), m_toolHandler(0), m_bundleDir(runConfig->bundleDirectory().toString()),
60
61
      m_arguments(runConfig->commandLineArguments()),
      m_device(ProjectExplorer::DeviceKitInformation::device(runConfig->target()->kit())),
Fawzi Mohamed's avatar
Fawzi Mohamed committed
62
63
      m_cppDebug(cppDebug), m_qmlDebug(qmlDebug), m_cleanExit(false),
      m_qmlPort(0), m_pid(0)
64
{
65
    m_deviceType = runConfig->deviceType();
66
67
68
69
70
71
72
73
74
75
76
77
78
79
}

IosRunner::~IosRunner()
{
    stop();
}

QString IosRunner::bundlePath()
{
    return m_bundleDir;
}

QStringList IosRunner::extraArgs()
{
Fawzi Mohamed's avatar
Fawzi Mohamed committed
80
81
82
83
    QStringList res = m_arguments;
    if (m_qmlPort != 0)
        res << QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(m_qmlPort);
    return res;
84
85
86
87
88
89
90
91
92
93
94
95
}

QString IosRunner::deviceId()
{
    IosDevice::ConstPtr dev = m_device.dynamicCast<const IosDevice>();
    if (!dev)
        return QString();
    return dev->uniqueDeviceID();
}

IosToolHandler::RunKind IosRunner::runType()
{
Fawzi Mohamed's avatar
Fawzi Mohamed committed
96
    if (m_cppDebug)
97
98
99
100
        return IosToolHandler::DebugRun;
    return IosToolHandler::NormalRun;
}

Fawzi Mohamed's avatar
Fawzi Mohamed committed
101
102
103
104
105
106
107
108
109
110
bool IosRunner::cppDebug() const
{
    return m_cppDebug;
}

bool IosRunner::qmlDebug() const
{
    return m_qmlDebug;
}

111
112
113
114
115
116
117
void IosRunner::start()
{
    if (m_toolHandler) {
        m_toolHandler->stop();
        emit finished(m_cleanExit);
    }
    m_cleanExit = false;
Fawzi Mohamed's avatar
Fawzi Mohamed committed
118
    m_qmlPort = 0;
119
    if (!QFileInfo(m_bundleDir).exists()) {
120
121
122
123
124
125
        TaskHub::addTask(Task::Warning,
                         tr("Could not find %1.").arg(m_bundleDir),
                         ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
        emit finished(m_cleanExit);
        return;
    }
Fawzi Mohamed's avatar
Fawzi Mohamed committed
126
127
128
129
130
131
132
133
134
    if (m_device->type() == Ios::Constants::IOS_DEVICE_TYPE) {
        IosDevice::ConstPtr iosDevice = m_device.dynamicCast<const IosDevice>();
        if (m_device.isNull()) {
            emit finished(m_cleanExit);
            return;
        }
        if (m_qmlDebug)
            m_qmlPort = iosDevice->nextPort();
    } else {
135
136
137
138
139
        IosSimulator::ConstPtr sim = m_device.dynamicCast<const IosSimulator>();
        if (sim.isNull()) {
            emit finished(m_cleanExit);
            return;
        }
Fawzi Mohamed's avatar
Fawzi Mohamed committed
140
141
        if (m_qmlDebug)
            m_qmlPort = sim->nextPort();
142
    }
Fawzi Mohamed's avatar
Fawzi Mohamed committed
143

144
    m_toolHandler = new IosToolHandler(m_deviceType, this);
145
146
147
148
149
150
151
    connect(m_toolHandler, SIGNAL(appOutput(Ios::IosToolHandler*,QString)),
            SLOT(handleAppOutput(Ios::IosToolHandler*,QString)));
    connect(m_toolHandler,
            SIGNAL(didStartApp(Ios::IosToolHandler*,QString,QString,Ios::IosToolHandler::OpStatus)),
            SLOT(handleDidStartApp(Ios::IosToolHandler*,QString,QString,Ios::IosToolHandler::OpStatus)));
    connect(m_toolHandler, SIGNAL(errorMsg(Ios::IosToolHandler*,QString)),
            SLOT(handleErrorMsg(Ios::IosToolHandler*,QString)));
Fawzi Mohamed's avatar
Fawzi Mohamed committed
152
153
    connect(m_toolHandler, SIGNAL(gotServerPorts(Ios::IosToolHandler*,QString,QString,int,int)),
            SLOT(handleGotServerPorts(Ios::IosToolHandler*,QString,QString,int,int)));
154
155
    connect(m_toolHandler, SIGNAL(gotInferiorPid(Ios::IosToolHandler*,QString,QString,Q_PID)),
            SLOT(handleGotInferiorPid(Ios::IosToolHandler*,QString,QString,Q_PID)));
156
157
158
159
160
161
162
163
164
    connect(m_toolHandler, SIGNAL(toolExited(Ios::IosToolHandler*,int)),
            SLOT(handleToolExited(Ios::IosToolHandler*,int)));
    connect(m_toolHandler, SIGNAL(finished(Ios::IosToolHandler*)),
            SLOT(handleFinished(Ios::IosToolHandler*)));
    m_toolHandler->requestRunApp(bundlePath(), extraArgs(), runType(), deviceId());
}

void IosRunner::stop()
{
165
166
167
168
169
    if (m_toolHandler) {
#ifdef Q_OS_UNIX
        if (m_pid > 0)
            kill(m_pid, SIGKILL);
#endif
170
        m_toolHandler->stop();
171
    }
172
173
174
175
176
177
178
179
180
181
}

void IosRunner::handleDidStartApp(IosToolHandler *handler, const QString &bundlePath,
                                  const QString &deviceId, IosToolHandler::OpStatus status)
{
    Q_UNUSED(bundlePath); Q_UNUSED(deviceId);
    if (m_toolHandler == handler)
        emit didStartApp(status);
}

Fawzi Mohamed's avatar
Fawzi Mohamed committed
182
183
void IosRunner::handleGotServerPorts(IosToolHandler *handler, const QString &bundlePath,
                                         const QString &deviceId, int gdbPort, int qmlPort)
184
185
{
    Q_UNUSED(bundlePath); Q_UNUSED(deviceId);
Fawzi Mohamed's avatar
Fawzi Mohamed committed
186
    m_qmlPort = qmlPort;
187
    if (m_toolHandler == handler)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
188
        emit gotServerPorts(gdbPort, qmlPort);
189
190
191
}

void IosRunner::handleGotInferiorPid(IosToolHandler *handler, const QString &bundlePath,
192
                                     const QString &deviceId, Q_PID pid)
193
194
{
    Q_UNUSED(bundlePath); Q_UNUSED(deviceId);
195
    m_pid = pid;
196
    if (m_toolHandler == handler)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
197
        emit gotInferiorPid(pid, m_qmlPort);
198
199
200
201
202
}

void IosRunner::handleAppOutput(IosToolHandler *handler, const QString &output)
{
    Q_UNUSED(handler);
Fawzi Mohamed's avatar
Fawzi Mohamed committed
203
204
205
206
207
208
    QRegExp qmlPortRe(QLatin1String("QML Debugger: Waiting for connection on port ([0-9]+)..."));
    int index = qmlPortRe.indexIn(output);
    QString res(output);
    if (index != -1 && m_qmlPort)
       res.replace(qmlPortRe.cap(1), QString::number(m_qmlPort));
    emit appOutput(res);
209
210
211
212
213
}

void IosRunner::handleErrorMsg(IosToolHandler *handler, const QString &msg)
{
    Q_UNUSED(handler);
214
215
216
    QString res(msg);
    QLatin1String lockedErr = QLatin1String("Unexpected reply: ELocked (454c6f636b6564) vs OK (4f4b)");
    if (msg.contains(QLatin1String("AMDeviceStartService returned -402653150"))) {
Fawzi Mohamed's avatar
Fawzi Mohamed committed
217
218
219
        TaskHub::addTask(Task::Warning,
                         tr("Run failed. The settings in the Organizer window of Xcode might be incorrect."),
                         ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
220
    } else if (res.contains(lockedErr)) {
221
222
        QString message = tr("The device is locked, please unlock.");
        TaskHub::addTask(Task::Error, message,
Fawzi Mohamed's avatar
Fawzi Mohamed committed
223
                         ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
224
        res.replace(lockedErr, message);
225
    }
Fawzi Mohamed's avatar
Fawzi Mohamed committed
226
227
228
229
230
    QRegExp qmlPortRe(QLatin1String("QML Debugger: Waiting for connection on port ([0-9]+)..."));
    int index = qmlPortRe.indexIn(msg);
    if (index != -1 && m_qmlPort)
       res.replace(qmlPortRe.cap(1), QString::number(m_qmlPort));
    emit errorMsg(res);
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
}

void IosRunner::handleToolExited(IosToolHandler *handler, int code)
{
    Q_UNUSED(handler);
    m_cleanExit = (code == 0);
}

void IosRunner::handleFinished(IosToolHandler *handler)
{
    if (m_toolHandler == handler) {
        emit finished(m_cleanExit);
        m_toolHandler = 0;
    }
    handler->deleteLater();
}

QString IosRunner::displayName() const
{
    return QString::fromLatin1("Run on %1").arg(m_device.isNull() ? QString()
                                                                  : m_device->displayName());
}

} // namespace Internal
255
} // namespace Ios