summaryrefslogtreecommitdiffstats
path: root/src/processmanager/qprocessbackend.cpp
blob: 834e6422884a9ae5f86dcc1d927dd8deb05b49f1 (plain)
1
2
3
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/


#include "qprocessbackend.h"

#include <QDateTime>
#include <QUuid>
#include <QDebug>
#include <QFile>
#include <QByteArray>
#include <stdio.h>

/***************************************************************************************/

QT_BEGIN_NAMESPACE_PROCESSMANAGER

/*!
    \class QProcessBackend
    \brief The QProcessBackend class is a generalized representation of a process.
    \inmodule QtProcessManager

    The QProcessBackend class encapsulates a process whose lifecycle is controlled by the process manager.
    It is a generalized representation - in actuality, subclasses of the QProcessBackend class are used
    to control processes.  These subclasses are used to accelerate process launching, wrap
    processes with additional arguments and settings, or fake the existence of a process.
    The QProcessBackend class itself cannot be instantiated.

    A QProcessBackend object always contains a QProcessInfo object, which is the static information
    used to start and execute the process.

    Because QProcessBackends represent actual or fake processes, they can only
    modify a few of the process properties.  Currently the QProcessBackend can
    only modify the process priority (or niceness) and the oomAdjustment score (for Linux
    systems).  All other process properties (such as UID, GID, program name) can
    be considered fixed.

    Furthermore, please note that setting these dynamic values can take time -
    for example, they may require some intra-application communication.  For example,
    if the process manager has delegated starting applications to some kind of
    pipe process, then the process manager itself may not be running with
    sufficient permissions to change the priority or oomAdjustment value to the
    desired setting.  In this case, the process manager must request that the pipe
    process make the changes, which will result in some time delay before the
    changes are real.  In this case, the actualPriority() and desiredPriority()
    functions will return different values until the IPC has completed.
*/

/*!
    \internal
    Constructs a QProcessBackend instance with QProcessInfo \a info and optional \a parent
*/
QProcessBackend::QProcessBackend(const QProcessInfo &info, QObject *parent)
    : QObject(parent)
    , m_info(info)
    , m_echo(QProcessBackend::EchoStdoutStderr)
{
    static int backend_count = 0;
    m_id = ++backend_count;
    createName();
}

/*!
  Destroy this process object.
*/

QProcessBackend::~QProcessBackend()
{
}

/*!
    Return the process name
*/

QString QProcessBackend::name() const
{
    return m_name;
}

/*!
    Return the process identifier
*/

QString QProcessBackend::identifier() const
{
    return m_info.identifier();
}

/*!
    Return the process program
*/

QString QProcessBackend::program() const
{
    return m_info.program();
}

/*!
    Return the process arguments
*/

QStringList QProcessBackend::arguments() const
{
    return m_info.arguments();
}

/*!
    Return the process environment
*/

QVariantMap QProcessBackend::environment() const
{
    return m_info.environment();
}

/*!
    Return the process working directory
*/

QString QProcessBackend::workingDirectory() const
{
    return m_info.workingDirectory();
}

/*!
    Returns a human-readable description of the last device error that
    occurred.
 */
QString QProcessBackend::errorString() const
{
    return QString();
}

/*!
    Returns the PID of this process. If the process has not started up yet properly, its PID will be 0.
*/
Q_PID QProcessBackend::pid() const
{
    return 0;
}

/*!
    Return the desired process priority.  This may not be
    the same as the actual priority
*/

qint32 QProcessBackend::desiredPriority() const
{
    return m_info.priority();
}

/*!
    Return the actual process priority.  This should be
    overridden by a subclass.
*/

qint32 QProcessBackend::actualPriority() const
{
    return 0;
}

/*!
    Set the process priority to \a priority.
    The base class updates the QProcessInfo object
    Subclasses should should override this function.
*/

void QProcessBackend::setDesiredPriority(qint32 priority)
{
    m_info.setPriority(priority);
}

/*!
    Return the desired process oomAdjustment
*/

qint32 QProcessBackend::desiredOomAdjustment() const
{
    return m_info.oomAdjustment();
}

/*!
    Return the actual process oomAdjustment
    Override this in a subclass that actual touches the oomAdjustment
*/

qint32 QProcessBackend::actualOomAdjustment() const
{
    return 0;
}

/*!
    Set the process desired \a oomAdjustment.
    The base class updates the QProcessInfo object
    Subclasses should override this function.

    Please note that there is no guarantee that the actual
    oomAdjustment will match the desired oomAdjustment.
*/

void QProcessBackend::setDesiredOomAdjustment(qint32 oomAdjustment)
{
    m_info.setOomAdjustment(oomAdjustment);
}

/*!
    \fn QProcess::ProcessState QProcessBackend::state() const

    Returns the state of the process.
*/

/*!
    \fn void QProcessBackend::start()
    \brief Starts the process.

    After the process is started, the started() signal is emitted.
    If a process fails to start (e.g. because it doesn't give any output until timeout) then
    the (partly) started process is killed and error(QProcess::FailedToStart) is emitted.

    This function must be overridden in subclasses.

    \sa started()
    \sa error()
*/

/*!
    \fn void QProcessBackend::stop(int timeout)

    Attempts to stop a process by giving it a \a timeout time to die, measured in milliseconds.
    If the process does not die in the given time limit, it is killed.

    \sa finished()
*/

/*!
   Writes at most \a maxSize bytes of data from \a data to the process.
   Returns the number of bytes that were actually written, or -1 if an error occurred.
*/

qint64 QProcessBackend::write(const char *data, qint64 maxSize)
{
    Q_UNUSED(data);
    Q_UNUSED(maxSize);
    return -1;
}

/*!
  Writes \a data from a zero-terminated string of 8-bit characters to the process.
  Returns the number of bytes that were actually written, or -1 if an error occurred.
  This is equivalent to

\code
  ProcessFrontend::write(data, qstrlen(data));
\endcode
 */

qint64 QProcessBackend::write(const char *data)
{
    return write(data, qstrlen(data));
}

/*!
  Writes the content of \a byteArray to the process.
  Returns the number of bytes that were actually written, or -1 if an error occurred.
 */

qint64 QProcessBackend::write(const QByteArray& byteArray)
{
    return write(byteArray.data(), byteArray.length());
}

/*!
  \enum QProcessBackend::EchoOutput

  This enum is used to control if data should be copied from an individual
  process stdout/stderr to the global stdout/stderr.  By default, it is
  set to \c QProcessBackend::EchoStdoutStderr, which means that all data
  from the child process will be copied to stdout and stderr.

  \value EchoNone         No data will be displayed
  \value EchoStdoutOnly   Data from the child's stdout will be displayed
  \value EchoStderrOnly   Data from the child's stderr will be displayed
  \value EchoStdoutStderr All data will be displayed.
 */

/*!
  Return the current echo setting.
 */

QProcessBackend::EchoOutput QProcessBackend::echo() const
{
    return m_echo;
}

/*!
  Set the \a echo setting
 */

void QProcessBackend::setEcho( QProcessBackend::EchoOutput echo )
{
    m_echo = echo;
}

/*!
  Return a copy of the current QProcessInfo
 */

QProcessInfo QProcessBackend::processInfo() const
{
    return m_info;
}

/*!
  \internal
 */

static void _writeByteArrayToFd(const QByteArray& data, const QByteArray& prefix, FILE *fh)
{
    QList<QByteArray> lines = data.split('\n');
    if (lines.isEmpty())
        return;

    // If the last item was a separator, there will be an extra blank item at the end
    if (lines.last().isEmpty())
        lines.removeLast();

    if (!lines.isEmpty()) {
        QFile f;
        f.open(fh, QIODevice::WriteOnly);
        foreach (const QByteArray& line, lines) {
            f.write(prefix);
            f.write(line);
            f.write("\n");
        }
        f.close();
    }
}

/*!
    Handler for standard output \a byteArray, read from the running process.

    Reimplement this method to provide handling for standard output.
*/
void QProcessBackend::handleStandardOutput(const QByteArray &byteArray)
{
    if (m_echo == EchoStdoutOnly || m_echo == EchoStdoutStderr) {
        QByteArray prefix = QString::fromLatin1("%1 [%2]: ").arg(m_name).arg(pid()).toLocal8Bit();
        _writeByteArrayToFd( byteArray, prefix, stderr );
    }
    emit standardOutput(byteArray);
}

/*!
    Handler for standard error \a byteArray, read from the running process.

    Reimplement this method to provide handling for standard error output.
*/
void QProcessBackend::handleStandardError(const QByteArray &byteArray)
{
    if (m_echo == EchoStderrOnly || m_echo == EchoStdoutStderr) {
        QByteArray prefix = QString::fromLatin1("%1 [%2] ERR: ").arg(m_name).arg(pid()).toLocal8Bit();
        _writeByteArrayToFd( byteArray, prefix, stderr );
    }
    emit standardError(byteArray);
}

/*!
    This function set the name of the process to be "NAME-ID".
    If you need to change the name of the process (for example, from a prelaunch backend),
    then call this function after changing the name.
 */

void QProcessBackend::createName()
{
    m_name = QString::fromLatin1("%1-%2").arg(m_info.identifier().isEmpty()
                                  ? QString::fromLatin1("process")
                                  : m_info.identifier()).arg(m_id);
}

/*!
    \fn void QProcessBackend::started()
    This signal is emitted when the process has started successfully.
*/

/*!
    \fn void QProcessBackend::error(QProcess::ProcessError error)
    This signal is emitted on a process error.  The \a error argument
    is the error emitted by the internal QProcess.
*/

/*!
    \fn void QProcessBackend::finished(int exitCode, QProcess::ExitStatus exitStatus)
    This signal is emitted when the process has stopped and its execution is over.
    The \a exitStatus tells you how the process exited; the \a exitCode is the
    return value of the process.

    Please note:  The \a exitStatus will be QProcess::CrashExit only if the
    ProcessManager stops the process externally.  A normal process that crashes
    will have an \a exitStatus of QProcess::NormalExit with a non-zero \a exitCode.
*/

/*!
    \fn void QProcessBackend::stateChanged(QProcess::ProcessState newState)
    This signal is emitted whenever the state of QProcess changes.  The \a newState argument
    is the state the internal QProcess changed to.
*/

/*!
    \fn void QProcessBackend::standardOutput(const QByteArray& data)
    This signal is emitted whenever standard output \a data is received from the child.
*/

/*!
    \fn void QProcessBackend::standardError(const QByteArray& data)
    This signal is emitted whenever standard error \a data is received from the child
*/

#include "moc_qprocessbackend.cpp"

QT_END_NAMESPACE_PROCESSMANAGER