dumpsys: make timeout value an argument

Also rework the args parsing using getopt_long.

Bug: 27788406
Change-Id: I60fd8e614616334d47b8de574f3c81a121a6ac0a
Signed-off-by: Thierry Strudel <tstrudel@google.com>
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 356b68f..b391d76 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -881,10 +881,7 @@
     printf("== Android Framework Services\n");
     printf("========================================================\n");
 
-    /* the full dumpsys is starting to take a long time, so we need
-       to increase its timeout.  we really need to do the timeouts in
-       dumpsys itself... */
-    run_command("DUMPSYS", 60, "dumpsys", "--skip", "meminfo,cpuinfo", NULL);
+    run_command("DUMPSYS", 60, "dumpsys", "-t", "60", "--skip", "meminfo,cpuinfo", NULL);
 
     printf("========================================================\n");
     printf("== Checkins\n");
@@ -1250,8 +1247,8 @@
 
     // Invoking the following dumpsys calls before dump_traces() to try and
     // keep the system stats as close to its initial state as possible.
-    run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "meminfo", "-a", NULL);
-    run_command_as_shell("DUMPSYS CPUINFO", 30, "dumpsys", "cpuinfo", "-a", NULL);
+    run_command_as_shell("DUMPSYS MEMINFO", 30, "dumpsys", "-t", "30", "meminfo", "-a", NULL);
+    run_command_as_shell("DUMPSYS CPUINFO", 10, "dumpsys", "cpuinfo", "-a", NULL);
 
     /* collect stack traces from Dalvik and native processes (needs root) */
     dump_traces_path = dump_traces();
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 003fcc3..db06e99 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -43,9 +43,10 @@
         "usage: dumpsys\n"
             "         To dump all services.\n"
             "or:\n"
-            "       dumpsys [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+            "       dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
             "         --help: shows this help\n"
             "         -l: only list services, do not dump them\n"
+            "         -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
             "         --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
             "         SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
 }
@@ -74,44 +75,80 @@
     Vector<String16> args;
     Vector<String16> skippedServices;
     bool showListOnly = false;
-    if (argc == 2) {
-        // 1 argument: check for special cases (-l or --help)
-        if (strcmp(argv[1], "--help") == 0) {
-            usage();
-            return 0;
+    bool skipServices = false;
+    int timeoutArg = 10;
+    static struct option longOptions[] = {
+        {"skip", no_argument, 0,  0 },
+        {"help", no_argument, 0,  0 },
+        {     0,           0, 0,  0 }
+    };
+
+    while (1) {
+        int c;
+        int optionIndex = 0;
+
+        c = getopt_long(argc, argv, "+t:l", longOptions, &optionIndex);
+
+        if (c == -1) {
+            break;
         }
-        if (strcmp(argv[1], "-l") == 0) {
+
+        switch (c) {
+        case 0:
+            if (!strcmp(longOptions[optionIndex].name, "skip")) {
+                skipServices = true;
+            } else if (!strcmp(longOptions[optionIndex].name, "help")) {
+                usage();
+                return 0;
+            }
+            break;
+
+        case 't':
+            {
+                char *endptr;
+                timeoutArg = strtol(optarg, &endptr, 10);
+                if (*endptr != '\0' || timeoutArg <= 0) {
+                    fprintf(stderr, "Error: invalid timeout number: '%s'\n", optarg);
+                    return -1;
+                }
+            }
+            break;
+
+        case 'l':
             showListOnly = true;
+            break;
+
+        default:
+            fprintf(stderr, "\n");
+            usage();
+            return -1;
         }
     }
-    if (argc == 3) {
-        // 2 arguments: check for special cases (--skip SERVICES)
-        if (strcmp(argv[1], "--skip") == 0) {
-            char* token = strtok(argv[2], ",");
-            while (token != NULL) {
-                skippedServices.add(String16(token));
-                token = strtok(NULL, ",");
+
+    for (int i = optind; i < argc; i++) {
+        if (skipServices) {
+            skippedServices.add(String16(argv[i]));
+        } else {
+            if (i == optind) {
+                services.add(String16(argv[i]));
+            } else {
+                args.add(String16(argv[i]));
             }
         }
     }
-    bool dumpAll = argc == 1;
-    if (dumpAll || !skippedServices.empty() || showListOnly) {
+
+    if ((skipServices && skippedServices.empty()) ||
+            (!skipServices && !showListOnly && services.empty()) ||
+            (showListOnly && (!services.empty() || !skippedServices.empty()))) {
+        usage();
+        return -1;
+    }
+
+    if (!skippedServices.empty() || showListOnly) {
         // gets all services
         services = sm->listServices();
         services.sort(sort_func);
         args.add(String16("-a"));
-    } else {
-        // gets a specific service:
-        // first check if its name is not a special argument...
-        if (strcmp(argv[1], "--skip") == 0 || strcmp(argv[1], "-l") == 0) {
-            usage();
-            return -1;
-        }
-        // ...then gets its arguments
-        services.add(String16(argv[1]));
-        for (int i=2; i<argc; i++) {
-            args.add(String16(argv[i]));
-        }
     }
 
     const size_t N = services.size();
@@ -173,8 +210,7 @@
                 }
             });
 
-            // TODO: Make this configurable at runtime.
-            constexpr auto timeout = std::chrono::seconds(10);
+            auto timeout = std::chrono::seconds(timeoutArg);
             auto end = std::chrono::steady_clock::now() + timeout;
 
             struct pollfd pfd = {