Initial work on a Dumpstate class.

dumpstate used to be a C binary that had to be "converted" to C++ in
order to use the zip_writer library, but it still keeps most of its C
idioms.

This change is the first step towards a new Dumpstate class; for now, it
just moves the state defined on dumpstate.h to it.

BUG: 26379932
Test: manual / refactored code

Change-Id: Ie689b87c4469a8951c35f3e642d7faa0722b0c03
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index e478651..44a994c 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -6,13 +6,23 @@
 LOCAL_CFLAGS := -DFWDUMP_$(BOARD_WLAN_DEVICE)
 endif
 
-LOCAL_SRC_FILES := dumpstate.cpp utils.cpp
+LOCAL_SRC_FILES := \
+        dumpstate.cpp \
+        utils.cpp
 
 LOCAL_MODULE := dumpstate
 
-LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux libbase libhardware_legacy
+LOCAL_SHARED_LIBRARIES := \
+        libbase \
+        libcutils \
+        libhardware_legacy \
+        liblog \
+        libselinux
+
 # ZipArchive support, the order matters here to get all symbols.
-LOCAL_STATIC_LIBRARIES := libziparchive libz libcrypto_static
+ZIP_LIBRARIES := libziparchive libz libcrypto_static
+
+LOCAL_STATIC_LIBRARIES := $(ZIP_LIBRARIES)
 LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
 LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
 LOCAL_INIT_RC := dumpstate.rc
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 92c5780..54b939c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -62,17 +62,14 @@
 static std::string args;
 
 // TODO: variables below should be part of dumpstate object
-static unsigned long id;
 static std::string buildType;
 static time_t now;
 static std::unique_ptr<ZipWriter> zip_writer;
 static std::set<std::string> mount_points;
 void add_mountinfo();
-int control_socket_fd = -1;
 /* 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 bool dryRun = false;
 static std::string extraOptions;
 
 #define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
@@ -99,8 +96,8 @@
 
 static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
 
-const std::string ZIP_ROOT_DIR = "FS";
-std::string bugreport_dir;
+// TODO: temporary variables and functions used during C++ refactoring
+static Dumpstate& ds = Dumpstate::GetInstance();
 
 /*
  * List of supported zip format versions.
@@ -109,6 +106,9 @@
  */
 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";
+
 static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
 static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
 
@@ -116,8 +116,8 @@
     return "user" == buildType;
 }
 
-bool is_dry_run() {
-    return dryRun;
+bool Dumpstate::IsDryRun() {
+    return dryRun_;
 }
 
 /* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
@@ -332,7 +332,7 @@
         MYLOGD("Not dumping systrace because zip_writer is not set\n");
         return;
     }
-    std::string systrace_path = bugreport_dir + "/systrace-" + suffix + ".txt";
+    std::string systrace_path = ds.bugreportDir_ + "/systrace-" + suffix + ".txt";
     if (systrace_path.empty()) {
         MYLOGE("Not dumping systrace because path is empty\n");
         return;
@@ -373,7 +373,7 @@
         return;
     }
 
-    std::string raft_log_path = bugreport_dir + "/raft_log.txt";
+    std::string raft_log_path = ds.bugreportDir_ + "/raft_log.txt";
     if (raft_log_path.empty()) {
         MYLOGD("raft_log_path is empty\n");
         return;
@@ -683,7 +683,7 @@
 /* End copy from system/core/logd/LogBuffer.cpp */
 
 /* dumps the current system state to stdout */
-static void print_header(std::string version) {
+void print_header(const std::string& version) {
     std::string build, fingerprint, radio, bootloader, network;
     char date[80];
 
@@ -711,8 +711,8 @@
     DumpFile(nullptr, "/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", id, getpid(),
-           dryRun, args.c_str(), extraOptions.c_str());
+    printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", ds.id_, getpid(),
+           ds.dryRun_, args.c_str(), extraOptions.c_str());
     printf("\n");
 }
 
@@ -1134,10 +1134,10 @@
     RunDumpsys("APP PROVIDERS", {"activity", "provider", "all"});
 
     printf("========================================================\n");
-    printf("== Final progress (pid %d): %d/%d (originally %d)\n",
-            getpid(), progress, weight_total, WEIGHT_TOTAL);
+    printf("== Final progress (pid %d): %d/%d (originally %d)\n", getpid(), ds.progress_,
+           ds.weightTotal_, WEIGHT_TOTAL);
     printf("========================================================\n");
-    printf("== dumpstate: done (id %lu)\n", id);
+    printf("== dumpstate: done (id %lu)\n", ds.id_);
     printf("========================================================\n");
 }
 
@@ -1193,13 +1193,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, time_t now) {
     // 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", id, date,
-            the_real_now_please_stand_up - now);
+    MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date,
+           the_real_now_please_stand_up - now);
 
     if (!add_zip_entry(bugreport_name, bugreport_path)) {
         MYLOGE("Failed to add text entry to .zip file\n");
@@ -1298,8 +1298,8 @@
         register_sig_handler();
     }
 
-    dryRun = android::base::GetBoolProperty("dumpstate.dry_run", false);
-    if (dryRun) {
+    ds.dryRun_ = android::base::GetBoolProperty("dumpstate.dry_run", false);
+    if (ds.dryRun_) {
         MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
     }
 
@@ -1316,9 +1316,9 @@
 
     /* gets the sequential id */
     int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
-    id = ++lastId;
+    ds.id_ = ++lastId;
     android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(lastId));
-    MYLOGI("dumpstate id: %lu\n", id);
+    MYLOGI("dumpstate id: %lu\n", ds.id_);
 
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
@@ -1340,6 +1340,7 @@
     int c;
     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;
@@ -1348,14 +1349,13 @@
             case 'v': break;  // compatibility no-op
             case 'q': do_vibrate = 0;           break;
             case 'p': do_fb = 1;                break;
-            case 'P': do_update_progress = 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 '?': printf("\n");
-            case 'h':
-                usage();
-                exit(1);
+            case 'h': usage(); exit(1);
+                // clang-format on
         }
     }
 
@@ -1364,7 +1364,7 @@
         // Currently, it contains the type of the requested bugreport.
         if (extraOptions == "bugreportplus") {
             MYLOGD("Running as bugreportplus: add -P, remove -p\n");
-            do_update_progress = 1;
+            ds.updateProgress_ = 1;
             do_fb = 0;
         } else if (extraOptions == "bugreportremote") {
             MYLOGD("Running as bugreportremote: add -q -R, remove -p\n");
@@ -1373,7 +1373,7 @@
             do_fb = 0;
         } else if (extraOptions == "bugreportwear") {
             MYLOGD("Running as bugreportwear: add -P\n");
-            do_update_progress = 1;
+            ds.updateProgress_ = 1;
         } else {
             MYLOGE("Unknown extra option: %s\n", extraOptions.c_str());
         }
@@ -1381,7 +1381,7 @@
         android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
     }
 
-    if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
+    if ((do_zip_file || do_add_date || ds.updateProgress_ || do_broadcast) && !use_outfile) {
         usage();
         exit(1);
     }
@@ -1391,12 +1391,12 @@
         exit(1);
     }
 
-    if (do_update_progress && !do_broadcast) {
+    if (ds.updateProgress_ && !do_broadcast) {
         usage();
         exit(1);
     }
 
-    if (is_remote_mode && (do_update_progress || !do_broadcast || !do_zip_file || !do_add_date)) {
+    if (is_remote_mode && (ds.updateProgress_ || !do_broadcast || !do_zip_file || !do_add_date)) {
         usage();
         exit(1);
     }
@@ -1408,7 +1408,7 @@
 
     MYLOGI("bugreport format version: %s\n", version.c_str());
 
-    do_early_screenshot = do_update_progress;
+    do_early_screenshot = ds.updateProgress_;
 
     // If we are going to use a socket, do it as early as possible
     // to avoid timeouts from bugreport.
@@ -1418,8 +1418,8 @@
 
     if (use_control_socket) {
         MYLOGD("Opening control socket\n");
-        control_socket_fd = open_socket("dumpstate");
-        do_update_progress = 1;
+        ds.controlSocketFd_ = open_socket("dumpstate");
+        ds.updateProgress_ = 1;
     }
 
     /* full path of the temporary file containing the bugreport */
@@ -1447,7 +1447,7 @@
     bool is_redirecting = !use_socket && use_outfile;
 
     if (is_redirecting) {
-        bugreport_dir = dirname(use_outfile);
+        ds.bugreportDir_ = dirname(use_outfile);
         base_name = basename(use_outfile);
         if (do_add_date) {
             char date[80];
@@ -1462,23 +1462,24 @@
             // 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 = bugreport_dir + "/" + base_name + "-" + suffix + ".png";
+            screenshot_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png";
         }
-        tmp_path = bugreport_dir + "/" + base_name + "-" + suffix + ".tmp";
-        log_path = bugreport_dir + "/dumpstate_log-" + suffix + "-"
-                + std::to_string(getpid()) + ".txt";
+        tmp_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".tmp";
+        log_path =
+            ds.bugreportDir_ + "/dumpstate_log-" + suffix + "-" + std::to_string(getpid()) + ".txt";
 
-        MYLOGD("Bugreport dir: %s\n"
-                "Base name: %s\n"
-                "Suffix: %s\n"
-                "Log path: %s\n"
-                "Temporary path: %s\n"
-                "Screenshot path: %s\n",
-                bugreport_dir.c_str(), base_name.c_str(), suffix.c_str(),
-                log_path.c_str(), tmp_path.c_str(), screenshot_path.c_str());
+        MYLOGD(
+            "Bugreport dir: %s\n"
+            "Base name: %s\n"
+            "Suffix: %s\n"
+            "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());
 
         if (do_zip_file) {
-            path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+            path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".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"));
@@ -1491,13 +1492,13 @@
             add_text_zip_entry("version.txt", version);
         }
 
-        if (do_update_progress) {
+        if (ds.updateProgress_) {
             if (do_broadcast) {
                 // clang-format off
                 std::vector<std::string> am_args = {
                      "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
                      "--es", "android.intent.extra.NAME", suffix,
-                     "--ei", "android.intent.extra.ID", std::to_string(id),
+                     "--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),
                 };
@@ -1505,7 +1506,7 @@
                 send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
             }
             if (use_control_socket) {
-                dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
+                dprintf(ds.controlSocketFd_, "BEGIN:%s\n", path.c_str());
             }
         }
     }
@@ -1574,9 +1575,6 @@
         dump_systrace();
     }
 
-    // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
-    dump_raft();
-
     // Invoking the following dumpsys calls before dump_traces() to try and
     // keep the system stats as close to its initial state as possible.
     RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
@@ -1584,6 +1582,9 @@
     RunDumpsys("DUMPSYS CPUINFO", {"cpuinfo", "-a"},
                CommandOptions::WithTimeout(10).DropRoot().Build());
 
+    // TODO: Drop root user and move into dumpstate() once b/28633932 is fixed.
+    dump_raft();
+
     /* collect stack traces from Dalvik and native processes (needs root) */
     dump_traces_path = dump_traces();
 
@@ -1634,7 +1635,7 @@
             suffix = name;
             if (!screenshot_path.empty()) {
                 std::string new_screenshot_path =
-                        bugreport_dir + "/" + base_name + "-" + suffix + ".png";
+                    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));
@@ -1654,7 +1655,7 @@
             } else {
                 do_text_file = false;
                 // Since zip file is already created, it needs to be renamed.
-                std::string new_path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+                std::string new_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".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())) {
@@ -1667,7 +1668,7 @@
             }
         }
         if (do_text_file) {
-            path = bugreport_dir + "/" + base_name + "-" + suffix + ".txt";
+            path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".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));
@@ -1676,10 +1677,12 @@
         }
         if (use_control_socket) {
             if (do_text_file) {
-                dprintf(control_socket_fd, "FAIL:could not create zip file, check %s "
-                        "for more details\n", log_path.c_str());
+                dprintf(ds.controlSocketFd_,
+                        "FAIL:could not create zip file, check %s "
+                        "for more details\n",
+                        log_path.c_str());
             } else {
-                dprintf(control_socket_fd, "OK:%s\n", path.c_str());
+                dprintf(ds.controlSocketFd_, "OK:%s\n", path.c_str());
             }
         }
     }
@@ -1699,9 +1702,9 @@
             // clang-format off
             std::vector<std::string> am_args = {
                  "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
-                 "--ei", "android.intent.extra.ID", std::to_string(id),
+                 "--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),
+                 "--ei", "android.intent.extra.MAX", std::to_string(ds.weightTotal_),
                  "--es", "android.intent.extra.BUGREPORT", path,
                  "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
             };
@@ -1724,16 +1727,16 @@
         }
     }
 
-    MYLOGD("Final progress: %d/%d (originally %d)\n", progress, weight_total, WEIGHT_TOTAL);
-    MYLOGI("done (id %lu)\n", id);
+    MYLOGD("Final progress: %d/%d (originally %d)\n", ds.progress_, ds.weightTotal_, WEIGHT_TOTAL);
+    MYLOGI("done (id %lu)\n", ds.id_);
 
     if (is_redirecting) {
         fclose(stderr);
     }
 
-    if (use_control_socket && control_socket_fd != -1) {
-      MYLOGD("Closing control socket\n");
-      close(control_socket_fd);
+    if (use_control_socket && ds.controlSocketFd_ != -1) {
+        MYLOGD("Closing control socket\n");
+        close(ds.controlSocketFd_);
     }
 
     return 0;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index d50e68c..9236fe3 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -37,6 +37,7 @@
 #include <string>
 #include <vector>
 
+// TODO: remove once dumpstate_board() devices use CommandOptions
 #define SU_PATH "/system/xbin/su"
 
 // Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
@@ -178,10 +179,8 @@
     static CommandOptions AS_ROOT_20;
 };
 
-typedef void (for_each_pid_func)(int, const char *);
-typedef void (for_each_tid_func)(int, int, const char *);
-
-/* Estimated total weight of bugreport generation.
+/*
+ * Estimated total weight of bugreport generation.
  *
  * Each section contributes to the total weight by an individual weight, so the overall progress
  * can be calculated by dividing the all completed weight by the total weight.
@@ -193,24 +192,62 @@
  * example, jumping from 70% to 100%), while a value too low will cause the progress to get stuck
  * at an almost-finished value (like 99%) for a while.
  */
+// TODO: move to dumpstate.cpp / utils.cpp once it's used in just one file
 static const int WEIGHT_TOTAL = 6500;
 
-/* Most simple commands have 10 as timeout, so 5 is a good estimate */
-static const int WEIGHT_FILE = 5;
-
 /*
- * TODO: the dumpstate internal state is getting fragile; for example, this variable is defined
- * here, declared at utils.cpp, and used on utils.cpp and dumpstate.cpp.
- * It would be better to take advantage of the C++ migration and encapsulate the state in an object,
- * but that will be better handled in a major C++ refactoring, which would also get rid of other C
- * idioms (like using std::string instead of char*, removing varargs, etc...) */
-extern int do_update_progress, progress, weight_total, control_socket_fd;
+ * Main class driving a bugreport generation.
+ *
+ * Currently, it only contains variables that are accessed externally, but gradually the functions
+ * that are spread accross utils.cpp and dumpstate.cpp will be moved to it.
+ */
+class Dumpstate {
+  public:
+    static Dumpstate& GetInstance();
 
-/* full path of the directory where the bugreport files will be written */
-extern std::string bugreport_dir;
+    /*
+     * When running in dry-run mode, skips the real dumps and just print the section headers.
+     *
+     * Useful when debugging dumpstate or other bugreport-related activities.
+     *
+     * Dry-run mode is enabled by setting the system property dumpstate.dry_run to true.
+     */
+    bool IsDryRun();
 
-/* root dir for all files copied as-is into the bugreport. */
-extern const std::string ZIP_ROOT_DIR;
+    // TODO: fields below should be private once refactor is finished
+    // TODO: initialize fields on constructor
+
+    // dumpstate id - unique after each device reboot.
+    unsigned long id_;
+
+    // Whether progress updates should be published.
+    bool updateProgress_ = false;
+
+    // Currrent progress.
+    int progress_ = 0;
+
+    // Total estimated progress.
+    int weightTotal_ = WEIGHT_TOTAL;
+
+    // When set, defines a socket file-descriptor use to report progress to bugreportz.
+    int controlSocketFd_ = -1;
+
+    // Whether this is a dry run.
+    bool dryRun_;
+
+    // Full path of the directory where the bugreport files will be written;
+    std::string bugreportDir_;
+
+  private:
+    // Used by GetInstance() only.
+    Dumpstate();
+};
+
+// for_each_pid_func = void (*)(int, const char*);
+// for_each_tid_func = void (*)(int, int, const char*);
+
+typedef void(for_each_pid_func)(int, const char*);
+typedef void(for_each_tid_func)(int, int, const char*);
 
 /* adds a new entry to the existing zip file. */
 bool add_zip_entry(const std::string& entry_name, const std::string& entry_path);
@@ -359,15 +396,6 @@
 /** Tells if the device is running a user build. */
 bool is_user_build();
 
-/*
- * When running in dry-run mode, skips the real dumps and just print the section headers.
- *
- * Useful when debugging dumpstate or other bugreport-related activities.
- *
- * Dry-run mode is enabled by setting the system property dumpstate.dry_run to true.
- */
-bool is_dry_run();
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 1eeef51..641d80c 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -54,6 +54,9 @@
 
 static const int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
 
+// TODO: temporary variables and functions used during C++ refactoring
+static Dumpstate& ds = Dumpstate::GetInstance();
+
 /* list of native processes to include in the native dumps */
 // This matches the /proc/pid/exe link instead of /proc/pid/cmdline.
 static const char* native_processes_to_dump[] = {
@@ -70,6 +73,9 @@
         NULL,
 };
 
+/* Most simple commands have 10 as timeout, so 5 is a good estimate */
+static const int WEIGHT_FILE = 5;
+
 CommandOptions CommandOptions::DEFAULT = CommandOptions::WithTimeout(10).Build();
 CommandOptions CommandOptions::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build();
 CommandOptions CommandOptions::AS_ROOT_5 = CommandOptions::WithTimeout(5).AsRoot().Build();
@@ -144,6 +150,14 @@
     return CommandOptions::CommandOptionsBuilder(timeout);
 }
 
+Dumpstate::Dumpstate() {
+}
+
+Dumpstate& Dumpstate::GetInstance() {
+    static Dumpstate sSingleton;
+    return sSingleton;
+}
+
 DurationReporter::DurationReporter(const char *title) : DurationReporter(title, stdout) {}
 
 DurationReporter::DurationReporter(const char *title, FILE *out) {
@@ -173,6 +187,11 @@
     return (uint64_t) ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
 }
 
+// TODO: temporary function used during the C++ refactoring
+static bool is_dry_run() {
+    return Dumpstate::GetInstance().IsDryRun();
+}
+
 void for_each_userid(void (*func)(int), const char *header) {
     if (is_dry_run()) return;
 
@@ -1261,49 +1280,44 @@
     fclose(fp);
 }
 
-/* overall progress */
-int progress = 0;
-int do_update_progress = 0; // Set by dumpstate.cpp
-int weight_total = WEIGHT_TOTAL;
-
 // TODO: make this function thread safe if sections are generated in parallel.
 void update_progress(int delta) {
-    if (!do_update_progress) return;
+    if (!ds.updateProgress_) return;
 
-    progress += delta;
+    ds.progress_ += delta;
 
     char key[PROPERTY_KEY_MAX];
     char value[PROPERTY_VALUE_MAX];
 
     // adjusts max on the fly
-    if (progress > weight_total) {
-        int new_total = weight_total * 1.2;
-        MYLOGD("Adjusting total weight from %d to %d\n", weight_total, new_total);
-        weight_total = new_total;
+    if (ds.progress_ > ds.weightTotal_) {
+        int newTotal = ds.weightTotal_ * 1.2;
+        MYLOGD("Adjusting total weight from %d to %d\n", ds.weightTotal_, newTotal);
+        ds.weightTotal_ = newTotal;
         snprintf(key, sizeof(key), "dumpstate.%d.max", getpid());
-        snprintf(value, sizeof(value), "%d", weight_total);
+        snprintf(value, sizeof(value), "%d", ds.weightTotal_);
         int status = property_set(key, value);
-        if (status) {
+        if (status != 0) {
             MYLOGE("Could not update max weight by setting system property %s to %s: %d\n",
                     key, value, status);
         }
     }
 
     snprintf(key, sizeof(key), "dumpstate.%d.progress", getpid());
-    snprintf(value, sizeof(value), "%d", progress);
+    snprintf(value, sizeof(value), "%d", ds.progress_);
 
-    if (progress % 100 == 0) {
+    if (ds.progress_ % 100 == 0) {
         // We don't want to spam logcat, so only log multiples of 100.
-        MYLOGD("Setting progress (%s): %s/%d\n", key, value, weight_total);
+        MYLOGD("Setting progress (%s): %s/%d\n", key, value, ds.weightTotal_);
     } else {
         // stderr is ignored on normal invocations, but useful when calling /system/bin/dumpstate
         // directly for debuggging.
-        fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, weight_total);
+        fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, ds.weightTotal_);
     }
 
-    if (control_socket_fd >= 0) {
-        dprintf(control_socket_fd, "PROGRESS:%d/%d\n", progress, weight_total);
-        fsync(control_socket_fd);
+    if (ds.controlSocketFd_ >= 0) {
+        dprintf(ds.controlSocketFd_, "PROGRESS:%d/%d\n", ds.progress_, ds.weightTotal_);
+        fsync(ds.controlSocketFd_);
     }
 
     int status = property_set(key, value);