Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c5440cd authored by Felipe Leme's avatar Felipe Leme Committed by Android (Google) Code Review
Browse files

Merge "Adds a -P option so dumpstate can report its progress."

parents e29bf4fc 71bbfc57
Loading
Loading
Loading
Loading
+63 −35
Original line number Diff line number Diff line
@@ -602,6 +602,7 @@ static void usage() {
            "  -e: play sound file instead of vibrate, at end of job\n"
            "  -q: disable vibrate\n"
            "  -B: send broadcast when finished (requires -o)\n"
            "  -P: send broadacast when started and update system properties on progress (requires -o and -B)\n"
                );
}

@@ -712,7 +713,7 @@ int main(int argc, char *argv[]) {

    /* parse arguments */
    int c;
    while ((c = getopt(argc, argv, "dho:svqzpB")) != -1) {
    while ((c = getopt(argc, argv, "dho:svqzpPB")) != -1) {
        switch (c) {
            case 'd': do_add_date = 1;          break;
            case 'z': do_zip_file = 1;          break;
@@ -721,6 +722,7 @@ int main(int argc, char *argv[]) {
            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 'B': do_broadcast = 1;         break;
            case '?': printf("\n");
            case 'h':
@@ -729,11 +731,15 @@ int main(int argc, char *argv[]) {
        }
    }

    if ((do_zip_file || do_add_date || do_broadcast) && !use_outfile) {
    if ((do_zip_file || do_add_date || do_update_progress || do_broadcast) && !use_outfile) {
        usage();
        exit(1);
    }

    if (do_update_progress && !do_broadcast) {
        usage();
        exit(1);
    }

    // If we are going to use a socket, do it as early as possible
    // to avoid timeouts from bugreport.
@@ -741,6 +747,49 @@ int main(int argc, char *argv[]) {
        redirect_to_socket(stdout, "dumpstate");
    }

    /* redirect output if needed */
    std::string text_path, zip_path, tmp_path, entry_name;

    /* pointer to the actual path, be it zip or text */
    std::string path;

    time_t now = time(NULL);

    bool is_redirecting = !use_socket && use_outfile;

    if (is_redirecting) {
        text_path = use_outfile;
        if (do_add_date) {
            char date[80];
            strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now));
            text_path += date;
        }
        if (do_fb) {
            screenshot_path = text_path + ".png";
        }
        zip_path = text_path + ".zip";
        text_path += ".txt";
        tmp_path = text_path + ".tmp";
        entry_name = basename(text_path.c_str());

        ALOGD("Temporary path: %s\ntext path: %s\nzip path: %s\nzip entry: %s",
              tmp_path.c_str(), text_path.c_str(), zip_path.c_str(), entry_name.c_str());

        if (do_update_progress) {
            if (!entry_name.empty()) {
                std::vector<std::string> am_args = {
                     "--receiver-permission", "android.permission.DUMP",
                     "--es", "android.intent.extra.NAME", entry_name,
                     "--ei", "android.intent.extra.PID", std::to_string(getpid()),
                     "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
                };
                send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
            } else {
                ALOGE("Skipping started broadcast because entry name could not be inferred\n");
            }
        }
    }

    /* open the vibrator before dropping root */
    std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
    if (do_vibrate) {
@@ -802,29 +851,7 @@ int main(int argc, char *argv[]) {
        return -1;
    }

    /* redirect output if needed */
    std::string text_path, zip_path, tmp_path, entry_name;

    /* pointer to the actual path, be it zip or text */
    std::string path;

    time_t now = time(NULL);

    if (!use_socket && use_outfile) {
        text_path = use_outfile;
        if (do_add_date) {
            char date[80];
            strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now));
            text_path += date;
        }
        if (do_fb) {
            screenshot_path = text_path + ".png";
        }
        zip_path = text_path + ".zip";
        text_path += ".txt";
        tmp_path = text_path + ".tmp";
        entry_name = basename(text_path.c_str());

    if (is_redirecting) {
        ALOGD("Temporary path: %s\ntext path: %s\nzip path: %s\nzip entry: %s",
              tmp_path.c_str(), text_path.c_str(), zip_path.c_str(), entry_name.c_str());
        /* TODO: rather than generating a text file now and zipping it later,
@@ -844,7 +871,7 @@ int main(int argc, char *argv[]) {
    }

    /* close output if needed */
    if (!use_socket && use_outfile) {
    if (is_redirecting) {
        fclose(stdout);
    }

@@ -870,11 +897,12 @@ int main(int argc, char *argv[]) {
    }

    /* tell activity manager we're done */
    if (do_broadcast && use_outfile) {
    if (do_broadcast) {
        if (!path.empty()) {
            ALOGI("Final bugreport path: %s\n", path.c_str());
            std::vector<std::string> am_args = {
                 "--receiver-permission", "android.permission.DUMP",
                 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
                 "--es", "android.intent.extra.BUGREPORT", path
            };
            if (do_fb) {
@@ -884,7 +912,7 @@ int main(int argc, char *argv[]) {
            }
            send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
        } else {
            ALOGE("Skipping broadcast because bugreport could not be generated\n");
            ALOGE("Skipping finished broadcast because bugreport could not be generated\n");
        }
    }

+25 −0
Original line number Diff line number Diff line
@@ -45,6 +45,28 @@ extern "C" {
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.
 *
 * 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.
 *
 * This value is defined empirically and it need to be adjusted as more sections are added.
 * It does not need to match the exact sum of all sections, but it should to be more than it,
 * otherwise the calculated progress would be more than 100%.
 */
static const int WEIGHT_TOTAL = 4000;

/* Most simple commands have 10 as timeout, so 5 is a good estimate */
static const int WEIGHT_FILE = 5;

/*
 * TOOD: 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;

/* prints the contents of a file */
int dump_file(const char *title, const char *path);

@@ -74,6 +96,9 @@ int run_command_always(const char *title, int timeout_seconds, const char *args[
/* sends a broadcast using Activity Manager */
void send_broadcast(const std::string& action, const std::vector<std::string>& args);

/* updates the overall progress of dumpstate by the given weight increment */
void update_progress(int weight);

/* prints all the system properties */
void print_properties();

+41 −4
Original line number Diff line number Diff line
@@ -35,7 +35,9 @@
#include <vector>
#include <sys/prctl.h>

#define LOG_TAG "dumpstate"
#include <cutils/debugger.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
@@ -266,7 +268,7 @@ static int _dump_file_from_fd(const char *title, const char *path, int fd) {
        }
        printf(") ------\n");
    }
    ON_DRY_RUN({ close(fd); return 0; });
    ON_DRY_RUN({ update_progress(WEIGHT_FILE); close(fd); return 0; });

    bool newline = false;
    fd_set read_set;
@@ -304,6 +306,7 @@ static int _dump_file_from_fd(const char *title, const char *path, int fd) {
            }
        }
    }
    update_progress(WEIGHT_FILE);
    close(fd);

    if (!newline) printf("\n");
@@ -455,7 +458,6 @@ bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
    return true;
}

/* forks a command and waits for it to finish */
int run_command(const char *title, int timeout_seconds, const char *command, ...) {
    fflush(stdout);

@@ -472,13 +474,19 @@ int run_command(const char *title, int timeout_seconds, const char *command, ...
    if (title) printf(") ------\n");
    fflush(stdout);

    ON_DRY_RUN_RETURN(0);
    ON_DRY_RUN({ update_progress(timeout_seconds); va_end(ap); return 0; });

    return run_command_always(title, timeout_seconds, args);
    int status = run_command_always(title, timeout_seconds, args);
    va_end(ap);
    return status;
}

/* forks a command and waits for it to finish */
int run_command_always(const char *title, int timeout_seconds, const char *args[]) {
    /* TODO: for now we're simplifying the progress calculation by using the timeout as the weight.
     * It's a good approximation for most cases, except when calling dumpsys, where its weight
     * should be much higher proportionally to its timeout. */
    int weight = timeout_seconds;

    const char *command = args[0];
    uint64_t start = nanotime();
@@ -537,6 +545,9 @@ int run_command_always(const char *title, int timeout_seconds, const char *args[
    }
    if (title) printf("[%s: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC);

    if (weight > 0) {
        update_progress(weight);
    }
    return status;
}

@@ -826,3 +837,29 @@ void dump_route_tables() {
    }
    fclose(fp);
}

/* overall progress */
int progress = 0;
int do_update_progress = 1; // Set by dumpstate.cpp

// TODO: make this function thread safe if sections are generated in parallel.
void update_progress(int delta) {
    if (!do_update_progress) return;

    progress += delta;

    char key[PROPERTY_KEY_MAX];
    char value[PROPERTY_VALUE_MAX];
    sprintf(key, "dumpstate.%d.progress", getpid());
    sprintf(value, "%d", progress);

    // 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);

    int status = property_set(key, value);
    if (status) {
        ALOGW("Could not update progress by setting system property %s to %s: %d\n",
                key, value, status);
    }
}