4
4
** All rights reserved.
5
5
** For any questions to Digia, please use contact form at http://www.qt.io
6
6
**
7
- ** This file is part of QtEnterprise Embedded.
7
+ ** This file is part of Qt Enterprise Embedded.
8
8
**
9
9
** Licensees holding valid Qt Enterprise licenses may use this file in
10
10
** accordance with the Qt Enterprise License Agreement provided with the
18
18
19
19
#include " process.h"
20
20
#include " portlist.h"
21
+ #include " perfprocesshandler.h"
21
22
#include < QCoreApplication>
22
23
#include < QTcpServer>
23
24
#include < QProcess>
29
30
#include < sys/un.h>
30
31
#include < unistd.h>
31
32
#include < fcntl.h>
33
+ #include < signal.h>
34
+ #include < sys/wait.h>
32
35
33
36
#define PID_FILE " /data/user/.appcontroller"
34
37
@@ -42,6 +45,25 @@ static int serverSocket = -1;
42
45
43
46
static const char socketPath[] = " #Boot2Qt_appcontroller" ;
44
47
48
+ static void usage ()
49
+ {
50
+ printf (" appcontroller [--debug-gdb] [--debug-qml] [--port-range <range>] [--stop] [--launch] [--show-platfrom] [--make-default] [--remove-default] [--print-debug] [--version] [--detach] [executable] [arguments]\n "
51
+ " \n "
52
+ " --port-range <range> Port range to use for debugging connections\n "
53
+ " --debug-gdb Start GDB debugging\n "
54
+ " --debug-qml Start QML debugging\n "
55
+ " --stop Stop already running application\n "
56
+ " --launch Start application without stopping already running application\n "
57
+ " --show-platform Show platform information\n "
58
+ " --make-default Make this application the default on boot\n "
59
+ " --remove-default Restore the default application\n "
60
+ " --print-debug Print debug messages to stdout on Android\n "
61
+ " --version Print version information\n "
62
+ " --detach Start application as usual, then go into background\n "
63
+ " --help, -h, -help Show this help\n "
64
+ );
65
+ }
66
+
45
67
static void setupAddressStruct (struct sockaddr_un &address)
46
68
{
47
69
address.sun_family = AF_UNIX;
@@ -123,17 +145,21 @@ static void stop()
123
145
connectSocket ();
124
146
}
125
147
126
- static int findFirstFreePort ( Utils::PortList &range)
148
+ static int openServer (QTcpServer *s, Utils::PortList &range)
127
149
{
128
- QTcpServer s;
129
-
130
150
while (range.hasMore ()) {
131
- if (s. listen (QHostAddress::Any, range.getNext ()))
132
- return s. serverPort ();
151
+ if (s-> listen (QHostAddress::Any, range.getNext ()))
152
+ return s-> serverPort ();
133
153
}
134
154
return -1 ;
135
155
}
136
156
157
+ static int findFirstFreePort (Utils::PortList &range)
158
+ {
159
+ QTcpServer s;
160
+ return openServer (&s, range);
161
+ }
162
+
137
163
static Config parseConfigFile ()
138
164
{
139
165
Config config;
@@ -212,6 +238,30 @@ static bool makeDefault(const QString &filepath)
212
238
return true ;
213
239
}
214
240
241
+ static QStringList extractPerfParams (QString s)
242
+ {
243
+ QStringList lst;
244
+ int h = 0 ;
245
+ int i = 0 ;
246
+ for (;;) {
247
+ i = s.indexOf (QLatin1Char (' ,' ), i);
248
+ if (i >= 0 ) {
249
+ if (i + 1 < s.length () && s.at (i + 1 ) == QLatin1Char (' ,' )) {
250
+ s.remove (i, 1 );
251
+ i++;
252
+ continue ;
253
+ }
254
+ lst << s.mid (h, i - h);
255
+ i++;
256
+ h = i;
257
+ } else {
258
+ lst << s.mid (h);
259
+ break ;
260
+ }
261
+ }
262
+ return lst;
263
+ }
264
+
215
265
int main (int argc, char **argv)
216
266
{
217
267
// Save arguments before QCoreApplication handles them
@@ -223,7 +273,9 @@ int main(int argc, char **argv)
223
273
quint16 gdbDebugPort = 0 ;
224
274
bool useGDB = false ;
225
275
bool useQML = false ;
276
+ QStringList perfParams;
226
277
bool fireAndForget = false ;
278
+ bool detach = false ;
227
279
Utils::PortList range;
228
280
229
281
if (args.isEmpty ()) {
@@ -252,6 +304,15 @@ int main(int argc, char **argv)
252
304
setsid ();
253
305
} else if (arg == " --debug-qml" ) {
254
306
useQML = true ;
307
+ } else if (arg == " --profile-perf" ) {
308
+ if (args.isEmpty ()) {
309
+ fprintf (stderr, " --profile-perf requires comma-separated list of parameters that "
310
+ " get passed to \" perf record\" . Arguments \" -o -\" are "
311
+ " automatically appended to capture the output as stream. "
312
+ " Escape commas by doubling them." );
313
+ return 1 ;
314
+ }
315
+ perfParams = extractPerfParams (args.takeFirst ());
255
316
} else if (arg == " --stop" ) {
256
317
stop ();
257
318
return 0 ;
@@ -280,6 +341,11 @@ int main(int argc, char **argv)
280
341
} else if (arg == " --version" ) {
281
342
printf (" Appcontroller version: " GIT_VERSION " \n Git revision: " GIT_HASH " \n " );
282
343
return 0 ;
344
+ } else if (arg == " --detach" ) {
345
+ detach = true ;
346
+ } else if (arg == " --help" || arg == " -help" || arg == " -h" ) {
347
+ usage ();
348
+ return 0 ;
283
349
} else {
284
350
args.prepend (arg);
285
351
break ;
@@ -296,6 +362,11 @@ int main(int argc, char **argv)
296
362
return 1 ;
297
363
}
298
364
365
+ if (detach && (useGDB || useQML)) {
366
+ fprintf (stderr, " Detached debugging not possible. --detach and one of --useGDB, --useQML must not be used together.\n " );
367
+ return 1 ;
368
+ }
369
+
299
370
if (useGDB) {
300
371
int port = findFirstFreePort (range);
301
372
if (port < 0 ) {
@@ -331,6 +402,38 @@ int main(int argc, char **argv)
331
402
return 1 ;
332
403
}
333
404
405
+ // daemonize
406
+ if (detach) {
407
+ pid_t rc = fork ();
408
+ if (rc == -1 ) {
409
+ printf (" fork failed\n " );
410
+ return -1 ;
411
+ } else if (rc > 0 ) {
412
+ // parent
413
+ ::wait (NULL ); // wait for the child to exit
414
+ return 0 ;
415
+ }
416
+
417
+ setsid ();
418
+ chdir (" /" );
419
+ signal (SIGHUP, SIG_IGN);
420
+
421
+ // child
422
+ int devnull = open (" /dev/null" , O_RDWR);
423
+ if (devnull < 0 )
424
+ return -1 ;
425
+ dup2 (devnull, 0 ); // Replace file descriptors
426
+ dup2 (devnull, 1 );
427
+ dup2 (devnull, 2 );
428
+ rc = fork ();
429
+ if (rc == -1 )
430
+ return -1 ;
431
+ else if (rc > 0 )
432
+ return 0 ;
433
+
434
+ // child
435
+ }
436
+
334
437
// Create QCoreApplication after parameter parsing to prevent printing evaluation
335
438
// message to terminal before QtCreator has parsed the output.
336
439
QCoreApplication app (argc, argv);
@@ -339,7 +442,24 @@ int main(int argc, char **argv)
339
442
if (gdbDebugPort)
340
443
process.setDebug ();
341
444
process.setSocketNotifier (new QSocketNotifier (serverSocket, QSocketNotifier::Read, &process));
342
- process.start (defaultArgs);
445
+
446
+ if (!perfParams.isEmpty ()) {
447
+ QStringList allArgs;
448
+ allArgs << QLatin1String (" perf" ) << QLatin1String (" record" )
449
+ << perfParams << QLatin1String (" -o" ) << QLatin1String (" -" )
450
+ << QLatin1String (" --" ) << defaultArgs.join (QLatin1Char (' ' ));
451
+
452
+ PerfProcessHandler *server = new PerfProcessHandler (&process, allArgs);
453
+ int port = openServer (server->server (), range);
454
+ if (port < 0 ) {
455
+ fprintf (stderr, " Could not find an unused port in range\n " );
456
+ return 1 ;
457
+ }
458
+ printf (" AppController: Going to wait for perf connection on port %d...\n " , port);
459
+ } else {
460
+ process.start (defaultArgs);
461
+ }
462
+
343
463
app.exec ();
344
464
if (!fireAndForget)
345
465
close (serverSocket);
0 commit comments