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

Commit 56efe020 authored by Thierry Strudel's avatar Thierry Strudel Committed by Android (Google) Code Review
Browse files

Merge changes from topic 'enable_persist_kernel_log' into nyc-mr1-dev

* changes:
  logcatd: trampoline persist.logd.logpersistd to logd.logpersistd
  logcatd: add stop and clear actions
  logcatd: Do not su for setprop
  logcat: allow comma-separate list of buffers
  logcat: clear when specifying file output
  logcat: Adjust help to make it more meaningful
parents 087ea18c df5d1285
Loading
Loading
Loading
Loading
+113 −135
Original line number Diff line number Diff line
@@ -278,61 +278,59 @@ static void show_help(const char *cmd)
    fprintf(stderr,"Usage: %s [options] [filterspecs]\n", cmd);

    fprintf(stderr, "options include:\n"
                    "  -s              Set default filter to silent.\n"
                    "                  Like specifying filterspec '*:S'\n"
                    "  -f <filename>   Log to file. Default is stdout\n"
                    "  --file=<filename>\n"
                    "  -r <kbytes>     Rotate log every kbytes. Requires -f\n"
                    "  --rotate-kbytes=<kbytes>\n"
                    "  -n <count>      Sets max number of rotated logs to <count>, default 4\n"
                    "  --rotate-count=<count>\n"
                    "  -v <format>     Sets the log print format, where <format> is:\n"
                    "  --format=<format>\n"
                    "  -s              Set default filter to silent. Equivalent to filterspec '*:S'\n"
                    "  -f <file>, --file=<file>               Log to file. Default is stdout\n"
                    "  -r <kbytes>, --rotate-kbytes=<kbytes>\n"
                    "                  Rotate log every kbytes. Requires -f option\n"
                    "  -n <count>, --rotate-count=<count>\n"
                    "                  Sets max number of rotated logs to <count>, default 4\n"
                    "  -v <format>, --format=<format>\n"
                    "                  Sets the log print format, where <format> is:\n"
                    "                    brief color epoch long monotonic printable process raw\n"
                    "                      tag thread threadtime time uid usec UTC year zone\n\n"
                    "  -D              print dividers between each log buffer\n"
                    "  --dividers\n"
                    "  -c              clear (flush) the entire log and exit\n"
                    "  --clear\n"
                    "  -d              dump the log and then exit (don't block)\n"
                    "  -e <expr>       only print lines where the log message matches <expr>\n"
                    "  --regex <expr>  where <expr> is a regular expression\n"
                    "  -m <count>      quit after printing <count> lines. This is meant to be\n"
                    "  --max-count=<count> paired with --regex, but will work on its own.\n"
                    "  --print         paired with --regex and --max-count to let content bypass\n"
                    "                    tag thread threadtime time uid usec UTC year zone\n"
                    "  -D, --dividers  Print dividers between each log buffer\n"
                    "  -c, --clear     Clear (flush) the entire log and exit\n"
                    "                  if Log to File specified, clear fileset instead\n"
                    "  -d              Dump the log and then exit (don't block)\n"
                    "  -e <expr>, --regex=<expr>\n"
                    "                  Only print lines where the log message matches <expr>\n"
                    "                  where <expr> is a regular expression\n"
                    // Leave --head undocumented as alias for -m
                    "  -m <count>, --max-count=<count>\n"
                    "                  Quit after printing <count> lines. This is meant to be\n"
                    "                  paired with --regex, but will work on its own.\n"
                    "  --print         Paired with --regex and --max-count to let content bypass\n"
                    "                  regex filter but still stop at number of matches.\n"
                    "  -t <count>      print only the most recent <count> lines (implies -d)\n"
                    "  -t '<time>'     print most recent lines since specified time (implies -d)\n"
                    "  -T <count>      print only the most recent <count> lines (does not imply -d)\n"
                    "  -T '<time>'     print most recent lines since specified time (not imply -d)\n"
                    // Leave --tail undocumented as alias for -t
                    "  -t <count>      Print only the most recent <count> lines (implies -d)\n"
                    "  -t '<time>'     Print most recent lines since specified time (implies -d)\n"
                    "  -T <count>      Print only the most recent <count> lines (does not imply -d)\n"
                    "  -T '<time>'     Print most recent lines since specified time (not imply -d)\n"
                    "                  count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'\n"
                    "                  'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format\n"
                    "  -g              get the size of the log's ring buffer and exit\n"
                    "  --buffer-size\n"
                    "  -G <size>       set size of log ring buffer, may suffix with K or M.\n"
                    "  --buffer-size=<size>\n"
                    "  -L              dump logs from prior to last reboot\n"
                    "  --last\n"
                    "  -g, --buffer-size                      Get the size of the ring buffer.\n"
                    "  -G <size>, --buffer-size=<size>\n"
                    "                  Set size of log ring buffer, may suffix with K or M.\n"
                    "  -L, -last       Dump logs from prior to last reboot\n"
                    // Leave security (Device Owner only installations) and
                    // kernel (userdebug and eng) buffers undocumented.
                    "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
                    "  --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
                    "                  parameters are allowed and results are interleaved. The\n"
                    "                  default is -b main -b system -b crash.\n"
                    "  -B              output the log in binary.\n"
                    "  --binary\n"
                    "  -S              output statistics.\n"
                    "  --statistics\n"
                    "  -p              print prune white and ~black list. Service is specified as\n"
                    "  --prune         UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
                    "  -b <buffer>, --buffer=<buffer>         Request alternate ring buffer, 'main',\n"
                    "                  'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
                    "                  Multiple -b parameters or comma separated list of buffers are\n"
                    "                  allowed. Buffers interleaved. Default -b main,system,crash.\n"
                    "  -B, --binary    Output the log in binary.\n"
                    "  -S, --statistics                       Output statistics.\n"
                    "  -p, --prune     Print prune white and ~black list. Service is specified as\n"
                    "                  UID, UID/PID or /PID. Weighed for quicker pruning if prefix\n"
                    "                  with ~, otherwise weighed for longevity if unadorned. All\n"
                    "                  other pruning activity is oldest first. Special case ~!\n"
                    "                  represents an automatic quicker pruning for the noisiest\n"
                    "                  UID as determined by the current statistics.\n"
                    "  -P '<list> ...' set prune white and ~black list, using same format as\n"
                    "  --prune='<list> ...'  printed above. Must be quoted.\n"
                    "  -P '<list> ...', --prune='<list> ...'\n"
                    "                  Set prune white and ~black list, using same format as\n"
                    "                  listed above. Must be quoted.\n"
                    "  --pid=<pid>     Only prints logs from the given pid.\n"
                    // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value
                    // Check ANDROID_LOG_WRAP_DEFAULT_TIMEOUT value for match to 2 hours
                    "  --wrap          Sleep for 2 hours or when buffer about to wrap whichever\n"
                    "                  comes first. Improves efficiency of polling by providing\n"
                    "                  an about-to-wrap wakeup.\n");
@@ -765,55 +763,26 @@ int main(int argc, char **argv)
            break;

            case 'b': {
                unsigned idMask = 0;
                while ((optarg = strtok(optarg, ",:; \t\n\r\f")) != NULL) {
                    if (strcmp(optarg, "default") == 0) {
                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                        switch (i) {
                        case LOG_ID_SECURITY:
                        case LOG_ID_EVENTS:
                            continue;
                        case LOG_ID_MAIN:
                        case LOG_ID_SYSTEM:
                        case LOG_ID_CRASH:
                            break;
                        default:
                            continue;
                        }

                        const char *name = android_log_id_to_name((log_id_t)i);
                        log_id_t log_id = android_name_to_log_id(name);

                        if (log_id != (log_id_t)i) {
                            continue;
                        }

                        bool found = false;
                        for (dev = devices; dev; dev = dev->next) {
                            if (!strcmp(optarg, dev->device)) {
                                found = true;
                                break;
                            }
                            if (!dev->next) {
                                break;
                            }
                        }
                        if (found) {
                            break;
                        }

                        log_device_t* d = new log_device_t(name, false);

                        if (dev) {
                            dev->next = d;
                            dev = d;
                        idMask |= (1 << LOG_ID_MAIN) |
                                  (1 << LOG_ID_SYSTEM) |
                                  (1 << LOG_ID_CRASH);
                    } else if (strcmp(optarg, "all") == 0) {
                        idMask = (unsigned)-1;
                    } else {
                            devices = dev = d;
                        log_id_t log_id = android_name_to_log_id(optarg);
                        const char *name = android_log_id_to_name(log_id);

                        if (strcmp(name, optarg) != 0) {
                            logcat_panic(true, "unknown buffer %s\n", optarg);
                        }
                        g_devCount++;
                        idMask |= (1 << log_id);
                    }
                    break;
                    optarg = NULL;
                }

                if (strcmp(optarg, "all") == 0) {
                for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                    const char *name = android_log_id_to_name((log_id_t)i);
                    log_id_t log_id = android_name_to_log_id(name);
@@ -821,10 +790,13 @@ int main(int argc, char **argv)
                    if (log_id != (log_id_t)i) {
                        continue;
                    }
                    if ((idMask & (1 << i)) == 0) {
                        continue;
                    }

                    bool found = false;
                    for (dev = devices; dev; dev = dev->next) {
                            if (!strcmp(optarg, dev->device)) {
                        if (!strcmp(name, dev->device)) {
                            found = true;
                            break;
                        }
@@ -833,7 +805,7 @@ int main(int argc, char **argv)
                        }
                    }
                    if (found) {
                            break;
                        continue;
                    }

                    bool binary = !strcmp(name, "events") ||
@@ -848,28 +820,6 @@ int main(int argc, char **argv)
                    }
                    g_devCount++;
                }
                    break;
                }

                bool binary = !(strcmp(optarg, "events") &&
                                strcmp(optarg, "security"));

                if (devices) {
                    dev = devices;
                    while (dev->next) {
                        if (!strcmp(optarg, dev->device)) {
                            dev = NULL;
                            break;
                        }
                        dev = dev->next;
                    }
                    if (dev) {
                        dev->next = new log_device_t(optarg, binary);
                    }
                } else {
                    devices = new log_device_t(optarg, binary);
                }
                g_devCount++;
            }
            break;

@@ -1084,7 +1034,35 @@ int main(int argc, char **argv)
        }

        if (clearLog) {
            if (android_logger_clear(dev->logger)) {
            if (g_outputFileName) {
                int maxRotationCountDigits =
                    (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;

                for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
                    char *file;

                    if (i == 0) {
                        asprintf(&file, "%s", g_outputFileName);
                    } else {
                        asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
                    }

                    if (!file) {
                        perror("while clearing log files");
                        clearFail = clearFail ?: dev->device;
                        break;
                    }

                    err = unlink(file);

                    if (err < 0 && errno != ENOENT && clearFail == NULL) {
                        perror("while clearing log files");
                        clearFail = dev->device;
                    }

                    free(file);
                }
            } else if (android_logger_clear(dev->logger)) {
                clearFail = clearFail ?: dev->device;
            }
        }
+53 −2
Original line number Diff line number Diff line
#
# init scriptures for logcatd persistent logging.
#
# Make sure any property changes are only performed with /data mounted, after
# post-fs-data state because otherwise behavior is undefined. The exceptions
# are device adjustments for logcatd service properties (persist.* overrides
# notwithstanding) for logd.logpersistd.size and logd.logpersistd.buffer.

# persist to non-persistent trampolines to permit device properties can be
# overridden when /data mounts, or during runtime.
on property:persist.logd.logpersistd.size=256
    setprop persist.logd.logpersistd.size ""
    setprop logd.logpersistd.size ""

on property:persist.logd.logpersistd.size=*
    # expect /init to report failure if property empty (default)
    setprop logd.logpersistd.size ${persist.logd.logpersistd.size}

on property:persist.logd.logpersistd.buffer=all
    setprop persist.logd.logpersistd.buffer ""
    setprop logd.logpersistd.buffer ""

on property:persist.logd.logpersistd.buffer=*
    # expect /init to report failure if property empty (default)
    setprop logd.logpersistd.buffer ${persist.logd.logpersistd.buffer}

on property:persist.logd.logpersistd=logcatd
    setprop logd.logpersistd logcatd

# enable, prep and start logcatd service
on load_persist_props_action
    setprop logd.logpersistd.enable true

on property:logd.logpersistd.enable=true && property:logd.logpersistd=logcatd
    # all exec/services are called with umask(077), so no gain beyond 0700
    mkdir /data/misc/logd 0700 logd log
    # logd for write to /data/misc/logd, log group for read from pstore (-L)
    exec - logd log -- /system/bin/logcat -L -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
    exec - logd log -- /system/bin/logcat -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
    start logcatd

service logcatd /system/bin/logcat -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
# stop logcatd service and clear data
on property:logd.logpersistd.enable=true && property:logd.logpersistd=clear
    setprop persist.logd.logpersistd ""
    stop logcatd
    # logd for clear of only our files in /data/misc/logd
    exec - logd log -- /system/bin/logcat -c -f /data/misc/logd/logcat -n ${logd.logpersistd.size:-256}
    setprop logd.logpersistd ""

# stop logcatd service
on property:logd.logpersistd=stop
    setprop persist.logd.logpersistd ""
    stop logcatd
    setprop logd.logpersistd ""

on property:logd.logpersistd.enable=false
    stop logcatd

# logcatd service
service logcatd /system/bin/logcat -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${logd.logpersistd.size:-256}
    class late_start
    disabled
    # logd for write to /data/misc/logd, log group for read from log daemon
+45 −25
Original line number Diff line number Diff line
@@ -8,8 +8,16 @@ userdebug|eng) ;;
   ;;
esac

data=/data/misc/logd
property=persist.logd.logpersistd

case `getprop ${property#persist.}.enable` in
true) ;;
*) echo "${progname} - Disabled"
   exit 1
   ;;
esac

data=/data/misc/logd
service=logcatd
size_default=256
buffer_default=all
@@ -69,14 +77,11 @@ case ${progname} in
  su logd xargs cat
  ;;
*.start)
  current_buffer="`getprop ${property}.buffer`"
  current_size="`getprop ${property}.size`"
  if [ "${service}" = "`getprop ${property}`" ]; then
  current_buffer="`getprop ${property#persist.}.buffer`"
  current_size="`getprop ${property#persist.}.size`"
  if [ "${service}" = "`getprop ${property#persist.}`" ]; then
    if [ "true" = "${clear}" ]; then
      su root stop ${service}
      su root setprop ${property} ""
      # 20ms done, guarantees content stop before rm
      sleep 1
      setprop ${property#persist.} "clear"
    elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
      echo   "ERROR: Changing existing collection parameters from" >&2
      if [ "${buffer}" != "${current_buffer}" ]; then
@@ -98,21 +103,31 @@ case ${progname} in
      echo   "       To blindly override and retain data, ${progname%.*}.stop first." >&2
      exit 1
    fi
  fi
  if [ "true" = "${clear}" ]; then
    su logd,misc rm -rf "${data}"
  elif [ "true" = "${clear}" ]; then
    setprop ${property#persist.} "clear"
  fi
  if [ -n "${buffer}${current_buffer}" ]; then
    su root setprop ${property}.buffer "${buffer}"
    setprop ${property}.buffer "${buffer}"
    if [ -z "${buffer}" ]; then
      # deal with trampoline for empty properties
      setprop ${property#persist.}.buffer ""
    fi
  fi
  if [ -n "${size}${current_size}" ]; then
    su root setprop ${property}.size "${size}"
    setprop ${property}.size "${size}"
    if [ -z "${size}" ]; then
      # deal with trampoline for empty properties
      setprop ${property#persist.}.size ""
    fi
  fi
  while [ "clear" = "`getprop ${property#persist.}`" ]; do
    continue
  done
  # ${service}.rc does the heavy lifting with the following trigger
  su root setprop ${property} ${service}
  getprop ${property}
  setprop ${property} ${service}
  # 20ms done, to permit process feedback check
  sleep 1
  getprop ${property#persist.}
  # also generate an error return code if not found running, bonus
  ps -t | grep "${data##*/}.*${service%d}"
  ;;
@@ -120,19 +135,24 @@ case ${progname} in
  if [ -n "${size}${buffer}" ]; then
    echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
  fi
  su root stop ${service}
  su root setprop ${property} ""
  if [ -n "`getprop ${property}.buffer`" ]; then
    su root setprop ${property}.buffer ""
  fi
  if [ -n "`getprop ${property}.size`" ]; then
    su root setprop ${property}.size ""
  fi
  if [ "true" = "${clear}" ]; then
    # 20ms done, guarantees content stop before rm
    sleep 1
    su logd,misc rm -rf "${data}"
  fi
    setprop ${property} "clear"
  else
    setprop ${property} "stop"
  fi
  if [ -n "`getprop ${property#persist.}.buffer`" ]; then
    setprop ${property}.buffer ""
    # deal with trampoline for empty properties
    setprop ${property#persist.}.buffer ""
  fi
  if [ -n "`getprop ${property#persist.}.size`" ]; then
    setprop ${property}.size ""
    # deal with trampoline for empty properties
    setprop ${property#persist.}.size ""
  fi
  while [ "clear" = "`getprop ${property#persist.}`" ]; do
    continue
  done
  ;;
*)
  echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
+118 −22

File changed.

Preview size limit exceeded, changes collapsed.

+11 −2
Original line number Diff line number Diff line
The properties that logd responds to are:
The properties that logd and friends react to are:

name                       type default  description
ro.logd.auditd             bool   true   Enable selinux audit daemon
@@ -10,8 +10,16 @@ ro.logd.kernel bool+ svelte+ Enable klogd daemon
ro.logd.statistics         bool+ svelte+ Enable logcat -S statistics.
ro.build.type              string        if user, logd.statistics &
                                         ro.logd.kernel default false.
logd.logpersistd.enable    bool   auto   Safe to start logpersist daemon service
logd.logpersistd          string persist Enable logpersist daemon, "logcatd"
                                         turns on logcat -f in logd context.
					 Responds to logcatd, clear and stop.
logd.logpersistd.buffer          persist logpersistd buffers to collect
logd.logpersistd.size            persist logpersistd size in MB
persist.logd.logpersistd   string        Enable logpersist daemon, "logcatd"
                                         turns on logcat -f in logd context
                                         turns on logcat -f in logd context.
persist.logd.logpersistd.buffer    all   logpersistd buffers to collect
persist.logd.logpersistd.size      256   logpersistd size in MB
persist.logd.size          number  ro    Global default size of the buffer for
                                         all log ids at initial startup, at
                                         runtime use: logcat -b all -G <value>
@@ -45,6 +53,7 @@ log.tag.<tag> string persist The <tag> specific logging level.
persist.log.tag.<tag>      string build  default for log.tag.<tag>

NB:
- auto - managed by /init
- bool+ - "true", "false" and comma separated list of "eng" (forced false if
  ro.build.type is "user") or "svelte" (forced false if ro.config.low_ram is
  true).