Minor changes on dumpstate refactoring:

- Moved more attributes into Dumpstate class.
- Created a GetPath() method that encapsulates bugreportDir_.
- Moved TakeScreenshot() into Dumpstate class.
- Uses DropRoot() on TakeScreenshot().

BUG: 26379932

Test: mmm -j32 frameworks/native/cmds/dumpstate/ && adb push ${ANDROID_PRODUCT_OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test

Change-Id: I2d96460f9244d4e257a215e2fb1f00dfd466e059
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 32dbf8d..a48f112 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -56,18 +56,10 @@
 static char cmdline_buf[16384] = "(unknown)";
 static const char *dump_traces_path = NULL;
 
-// Command-line arguments as string
-static std::string args;
-
 // TODO: variables below should be part of dumpstate object
-static time_t now;
 static std::unique_ptr<ZipWriter> zip_writer;
 static std::set<std::string> mount_points;
 void add_mountinfo();
-/* suffix of the bugreport files - it's typically the date (when invoked with -d),
- * although it could be changed by the user using a system property */
-static std::string suffix;
-static std::string extraOptions;
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
 #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
@@ -111,13 +103,6 @@
     return ds.IsUserBuild();
 }
 
-/*
- * List of supported zip format versions.
- *
- * See bugreport-format.md for more info.
- */
-static std::string VERSION_DEFAULT = "1.0";
-
 // Relative directory (inside the zip) for all files copied as-is into the bugreport.
 static const std::string ZIP_ROOT_DIR = "FS";
 
@@ -127,7 +112,7 @@
 /* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
  * otherwise, gets just those modified in the last half an hour. */
 static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
-    time_t thirty_minutes_ago = now - 60*30;
+    time_t thirty_minutes_ago = ds.now_ - 60 * 30;
     for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
         snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
         int fd = TEMP_FAILURE_RETRY(open(data[i].name,
@@ -336,7 +321,7 @@
         MYLOGD("Not dumping systrace because zip_writer is not set\n");
         return;
     }
-    std::string systrace_path = ds.bugreportDir_ + "/systrace-" + suffix + ".txt";
+    std::string systrace_path = ds.GetPath("-systrace.txt");
     if (systrace_path.empty()) {
         MYLOGE("Not dumping systrace because path is empty\n");
         return;
@@ -377,7 +362,7 @@
         return;
     }
 
-    std::string raft_log_path = ds.bugreportDir_ + "/raft_log.txt";
+    std::string raft_log_path = ds.GetPath("-raft_log.txt");
     if (raft_log_path.empty()) {
         MYLOGD("raft_log_path is empty\n");
         return;
@@ -686,8 +671,8 @@
 
 /* End copy from system/core/logd/LogBuffer.cpp */
 
-/* dumps the current system state to stdout */
-void print_header(const std::string& version) {
+// TODO: move to utils.cpp
+void Dumpstate::PrintHeader() {
     std::string build, fingerprint, radio, bootloader, network;
     char date[80];
 
@@ -696,7 +681,7 @@
     radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
     bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
     network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
-    strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
+    strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
 
     printf("========================================================\n");
     printf("== dumpstate: %s\n", date);
@@ -713,9 +698,9 @@
     printf("Kernel: ");
     DumpFile("", "/proc/version");
     printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
-    printf("Bugreport format version: %s\n", version.c_str());
-    printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", ds.id_, getpid(),
-           ds.IsDryRun(), args.c_str(), extraOptions.c_str());
+    printf("Bugreport format version: %s\n", version_.c_str());
+    printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", id_, getpid(),
+           dryRun_, args_.c_str(), extraOptions_.c_str());
     printf("\n");
 }
 
@@ -748,8 +733,8 @@
 
     // Logging statement  below is useful to time how long each entry takes, but it's too verbose.
     // MYLOGD("Adding zip entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
-            ZipWriter::kCompress, get_mtime(fd, now));
+    int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
+                                                 get_mtime(fd, ds.now_));
     if (err) {
         MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
                 ZipWriter::ErrorCodeString(err));
@@ -815,7 +800,7 @@
         return false;
     }
     MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
-    int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
+    int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
     if (err) {
         MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
                 ZipWriter::ErrorCodeString(err));
@@ -849,8 +834,7 @@
     RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
 }
 
-static void dumpstate(const std::string& screenshot_path,
-                      const std::string& version __attribute__((unused))) {
+static void dumpstate() {
     DurationReporter durationReporter("DUMPSTATE");
     unsigned long timeout;
 
@@ -897,10 +881,9 @@
     /* Dump Bluetooth HCI logs */
     add_dir("/data/misc/bluetooth/logs", true);
 
-    if (!screenshot_path.empty()) {
+    if (!ds.doEarlyScreenshot_) {
         MYLOGI("taking late screenshot\n");
-        take_screenshot(screenshot_path);
-        MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
+        ds.TakeScreenshot();
     }
 
     // DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
@@ -1147,7 +1130,7 @@
 
 static void ShowUsageAndExit(int exitCode = 1) {
     fprintf(stderr,
-            "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
+            "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
             "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
             "  -h: display this help message\n"
             "  -b: play sound file instead of vibrate, at beginning of job\n"
@@ -1203,13 +1186,13 @@
    temporary file.
  */
 static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
-                            const std::string& log_path, time_t now) {
+                            const std::string& log_path) {
     // Final timestamp
     char date[80];
     time_t the_real_now_please_stand_up = time(nullptr);
     strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
     MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date,
-           the_real_now_please_stand_up - now);
+           the_real_now_please_stand_up - ds.now_);
 
     if (!add_zip_entry(bugreport_name, bugreport_path)) {
         MYLOGE("Failed to add text entry to .zip file\n");
@@ -1292,11 +1275,7 @@
     int use_control_socket = 0;
     int do_fb = 0;
     int do_broadcast = 0;
-    int do_early_screenshot = 0;
     int is_remote_mode = 0;
-    std::string version = VERSION_DEFAULT;
-
-    now = time(nullptr);
 
     MYLOGI("begin\n");
 
@@ -1314,14 +1293,14 @@
 
     // TODO: use helper function to convert argv into a string
     for (int i = 0; i < argc; i++) {
-        args += argv[i];
+        ds.args_ += argv[i];
         if (i < argc - 1) {
-            args += " ";
+            ds.args_ += " ";
         }
     }
 
-    extraOptions = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
-    MYLOGI("Dumpstate args: %s (extra options: %s)\n", args.c_str(), extraOptions.c_str());
+    ds.extraOptions_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
+    MYLOGI("Dumpstate args: %s (extra options: %s)\n", ds.args_.c_str(), ds.extraOptions_.c_str());
 
     /* gets the sequential id */
     int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
@@ -1350,18 +1329,18 @@
     while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
         switch (c) {
             // clang-format off
-            case 'd': do_add_date = 1;          break;
-            case 'z': do_zip_file = 1;          break;
-            case 'o': use_outfile = optarg;     break;
-            case 's': use_socket = 1;           break;
-            case 'S': use_control_socket = 1;   break;
-            case 'v': break;  // compatibility no-op
-            case 'q': do_vibrate = 0;           break;
-            case 'p': do_fb = 1;                break;
-            case 'P': ds.updateProgress_ = 1;   break;
-            case 'R': is_remote_mode = 1;       break;
-            case 'B': do_broadcast = 1;         break;
-            case 'V': version = optarg;         break;
+            case 'd': do_add_date = 1;           break;
+            case 'z': do_zip_file = 1;           break;
+            case 'o': use_outfile = optarg;      break;
+            case 's': use_socket = 1;            break;
+            case 'S': use_control_socket = 1;    break;
+            case 'v':                            break;  // compatibility no-op
+            case 'q': do_vibrate = 0;            break;
+            case 'p': do_fb = 1;                 break;
+            case 'P': ds.updateProgress_ = true; break;
+            case 'R': is_remote_mode = 1;        break;
+            case 'B': do_broadcast = 1;          break;
+            case 'V': ds.version_ = optarg;      break;
             case 'h':
                 ShowUsageAndExit(0);
                 break;
@@ -1372,23 +1351,23 @@
         }
     }
 
-    if (!extraOptions.empty()) {
+    if (!ds.extraOptions_.empty()) {
         // Framework uses a system property to override some command-line args.
         // Currently, it contains the type of the requested bugreport.
-        if (extraOptions == "bugreportplus") {
+        if (ds.extraOptions_ == "bugreportplus") {
             MYLOGD("Running as bugreportplus: add -P, remove -p\n");
-            ds.updateProgress_ = 1;
+            ds.updateProgress_ = true;
             do_fb = 0;
-        } else if (extraOptions == "bugreportremote") {
+        } else if (ds.extraOptions_ == "bugreportremote") {
             MYLOGD("Running as bugreportremote: add -q -R, remove -p\n");
             do_vibrate = 0;
             is_remote_mode = 1;
             do_fb = 0;
-        } else if (extraOptions == "bugreportwear") {
+        } else if (ds.extraOptions_ == "bugreportwear") {
             MYLOGD("Running as bugreportwear: add -P\n");
-            ds.updateProgress_ = 1;
+            ds.updateProgress_ = true;
         } else {
-            MYLOGE("Unknown extra option: %s\n", extraOptions.c_str());
+            MYLOGE("Unknown extra option: %s\n", ds.extraOptions_.c_str());
         }
         // Reset the property
         android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
@@ -1410,13 +1389,13 @@
         ExitOnInvalidArgs();
     }
 
-    if (version != VERSION_DEFAULT) {
+    if (ds.version_ != VERSION_DEFAULT) {
         ShowUsageAndExit();
     }
 
-    MYLOGI("bugreport format version: %s\n", version.c_str());
+    MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
 
-    do_early_screenshot = ds.updateProgress_;
+    ds.doEarlyScreenshot_ = ds.updateProgress_;
 
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
@@ -1436,15 +1415,6 @@
     /* full path of the file containing the dumpstate logs */
     std::string log_path;
 
-    /* full path of the systrace file, when enabled */
-    std::string systrace_path;
-
-    /* full path of the temporary file containing the screenshot (when requested) */
-    std::string screenshot_path;
-
-    /* base name (without suffix or extensions) of the bugreport files */
-    std::string base_name;
-
     /* pointer to the actual path, be it zip or text */
     std::string path;
 
@@ -1456,25 +1426,21 @@
 
     if (is_redirecting) {
         ds.bugreportDir_ = dirname(use_outfile);
-        base_name = basename(use_outfile);
+        ds.baseName_ = basename(use_outfile);
         if (do_add_date) {
             char date[80];
-            strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
-            suffix = date;
+            strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+            ds.suffix_ = date;
         } else {
-            suffix = "undated";
+            ds.suffix_ = "undated";
         }
         std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
-        base_name = base_name + "-" + buildId;
+        ds.baseName_ = ds.baseName_ + "-" + buildId;
         if (do_fb) {
-            // TODO: if dumpstate was an object, the paths could be internal variables and then
-            // we could have a function to calculate the derived values, such as:
-            //     screenshot_path = GetPath(".png");
-            screenshot_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png";
+            ds.screenshotPath_ = ds.GetPath(".png");
         }
-        tmp_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".tmp";
-        log_path =
-            ds.bugreportDir_ + "/dumpstate_log-" + suffix + "-" + std::to_string(getpid()) + ".txt";
+        tmp_path = ds.GetPath(".tmp");
+        log_path = ds.GetPath("-dumpstate_log-" + std::to_string(getpid()) + ".txt");
 
         MYLOGD(
             "Bugreport dir: %s\n"
@@ -1483,11 +1449,11 @@
             "Log path: %s\n"
             "Temporary path: %s\n"
             "Screenshot path: %s\n",
-            ds.bugreportDir_.c_str(), base_name.c_str(), suffix.c_str(), log_path.c_str(),
-            tmp_path.c_str(), screenshot_path.c_str());
+            ds.bugreportDir_.c_str(), ds.baseName_.c_str(), ds.suffix_.c_str(), log_path.c_str(),
+            tmp_path.c_str(), ds.screenshotPath_.c_str());
 
         if (do_zip_file) {
-            path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip";
+            path = ds.GetPath(".zip");
             MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
             create_parent_dirs(path.c_str());
             zip_file.reset(fopen(path.c_str(), "wb"));
@@ -1497,7 +1463,7 @@
             } else {
                 zip_writer.reset(new ZipWriter(zip_file.get()));
             }
-            add_text_zip_entry("version.txt", version);
+            add_text_zip_entry("version.txt", ds.version_);
         }
 
         if (ds.updateProgress_) {
@@ -1505,7 +1471,7 @@
                 // clang-format off
                 std::vector<std::string> am_args = {
                      "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
-                     "--es", "android.intent.extra.NAME", suffix,
+                     "--es", "android.intent.extra.NAME", ds.suffix_,
                      "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
                      "--ei", "android.intent.extra.PID", std::to_string(getpid()),
                      "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
@@ -1535,18 +1501,13 @@
         }
     }
 
-    if (do_fb && do_early_screenshot) {
-        if (screenshot_path.empty()) {
+    if (do_fb && ds.doEarlyScreenshot_) {
+        if (ds.screenshotPath_.empty()) {
             // should not have happened
             MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
         } else {
             MYLOGI("taking early screenshot\n");
-            take_screenshot(screenshot_path);
-            MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
-            if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
-                MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
-                        screenshot_path.c_str(), strerror(errno));
-            }
+            ds.TakeScreenshot();
         }
     }
 
@@ -1574,7 +1535,7 @@
     // NOTE: there should be no stdout output until now, otherwise it would break the header.
     // In particular, DurationReport objects should be created passing 'title, NULL', so their
     // duration is logged into MYLOG instead.
-    print_header(version);
+    ds.PrintHeader();
 
     // Dumps systrace right away, otherwise it will be filled with unnecessary events.
     // First try to dump anrd trace if the daemon is running. Otherwise, dump
@@ -1619,7 +1580,7 @@
         return -1;
     }
 
-    dumpstate(do_early_screenshot ? "": screenshot_path, version);
+    dumpstate();
 
     /* close output if needed */
     if (is_redirecting) {
@@ -1643,31 +1604,30 @@
             }
         }
         if (change_suffix) {
-            MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), name.c_str());
-            suffix = name;
-            if (!screenshot_path.empty()) {
-                std::string new_screenshot_path =
-                    ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png";
-                if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
-                    MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
-                            new_screenshot_path.c_str(), strerror(errno));
+            MYLOGI("changing suffix from %s to %s\n", ds.suffix_.c_str(), name.c_str());
+            ds.suffix_ = name;
+            if (!ds.screenshotPath_.empty()) {
+                std::string newScreenshotPath = ds.GetPath(".png");
+                if (rename(ds.screenshotPath_.c_str(), newScreenshotPath.c_str())) {
+                    MYLOGE("rename(%s, %s): %s\n", ds.screenshotPath_.c_str(),
+                           newScreenshotPath.c_str(), strerror(errno));
                 } else {
-                    screenshot_path = new_screenshot_path;
+                    ds.screenshotPath_ = newScreenshotPath;
                 }
             }
         }
 
         bool do_text_file = true;
         if (do_zip_file) {
-            std::string entry_name = base_name + "-" + suffix + ".txt";
+            std::string entry_name = ds.baseName_ + "-" + ds.suffix_ + ".txt";
             MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
-            if (!finish_zip_file(entry_name, tmp_path, log_path, now)) {
+            if (!finish_zip_file(entry_name, tmp_path, log_path)) {
                 MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
                 do_text_file = true;
             } else {
                 do_text_file = false;
                 // Since zip file is already created, it needs to be renamed.
-                std::string new_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip";
+                std::string new_path = ds.GetPath(".zip");
                 if (path != new_path) {
                     MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
                     if (rename(path.c_str(), new_path.c_str())) {
@@ -1680,7 +1640,7 @@
             }
         }
         if (do_text_file) {
-            path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".txt";
+            path = ds.GetPath(".txt");
             MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
             if (rename(tmp_path.c_str(), path.c_str())) {
                 MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
@@ -1724,7 +1684,7 @@
             if (do_fb) {
                 am_args.push_back("--es");
                 am_args.push_back("android.intent.extra.SCREENSHOT");
-                am_args.push_back(screenshot_path);
+                am_args.push_back(ds.screenshotPath_);
             }
             if (is_remote_mode) {
                 am_args.push_back("--es");