Merge "Make the root/unroot test more robust."
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index db63bcc..028791c 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -42,9 +42,24 @@
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_verity.h"
+#define FSTAB_PREFIX "/fstab."
+
#define VERITY_METADATA_SIZE 32768
#define VERITY_TABLE_RSA_KEY "/verity_key"
+#define VERITY_STATE_HEADER 0x83c0ae9d
+#define VERITY_STATE_VERSION 1
+
+#define VERITY_KMSG_RESTART "dm-verity device corrupted"
+#define VERITY_KMSG_BUFSIZE 1024
+
+struct verity_state {
+ uint32_t header;
+ uint32_t version;
+ uint32_t size;
+ int32_t mode;
+};
+
extern struct fs_info info;
static RSAPublicKey *load_key(char *path)
@@ -294,10 +309,12 @@
return 0;
}
-static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table)
+static int load_verity_table(struct dm_ioctl *io, char *name, char *blockdev, int fd, char *table,
+ int mode)
{
char *verity_params;
char *buffer = (char*) io;
+ size_t bufsize;
uint64_t device_size = 0;
if (get_target_device_size(blockdev, &device_size) < 0) {
@@ -317,7 +334,17 @@
// build the verity params here
verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
- strcpy(verity_params, table);
+ bufsize = DM_BUF_SIZE - (verity_params - buffer);
+
+ if (mode == VERITY_MODE_EIO) {
+ // allow operation with older dm-verity drivers that are unaware
+ // of the mode parameter by omitting it; this also means that we
+ // cannot use logging mode with these drivers, they always cause
+ // an I/O error for corrupted blocks
+ strcpy(verity_params, table);
+ } else if (snprintf(verity_params, bufsize, "%s %d", table, mode) < 0) {
+ return -1;
+ }
// set next target boundary
verity_params += strlen(verity_params) + 1;
@@ -359,31 +386,316 @@
char *key;
ret = asprintf(&key, "partition.%s.verified", name);
if (ret < 0) {
- ERROR("Error formatting verified property");
+ ERROR("Error formatting verified property\n");
return ret;
}
ret = PROP_NAME_MAX - strlen(key);
if (ret < 0) {
- ERROR("Verified property name is too long");
+ ERROR("Verified property name is too long\n");
+ free(key);
return -1;
}
ret = property_set(key, "1");
if (ret < 0)
- ERROR("Error setting verified property %s: %d", key, ret);
+ ERROR("Error setting verified property %s: %d\n", key, ret);
free(key);
return ret;
}
+static int check_verity_restart(const char *fname)
+{
+ char buffer[VERITY_KMSG_BUFSIZE + 1];
+ int fd;
+ int rc = 0;
+ ssize_t size;
+ struct stat s;
+
+ fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
+
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+ }
+ goto out;
+ }
+
+ if (fstat(fd, &s) == -1) {
+ ERROR("Failed to fstat %s (%s)\n", fname, strerror(errno));
+ goto out;
+ }
+
+ size = VERITY_KMSG_BUFSIZE;
+
+ if (size > s.st_size) {
+ size = s.st_size;
+ }
+
+ if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
+ ERROR("Failed to lseek %jd %s (%s)\n", (intmax_t)(s.st_size - size), fname,
+ strerror(errno));
+ goto out;
+ }
+
+ if (TEMP_FAILURE_RETRY(read(fd, buffer, size)) != size) {
+ ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname,
+ strerror(errno));
+ goto out;
+ }
+
+ buffer[size] = '\0';
+
+ if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
+ rc = 1;
+ }
+
+out:
+ if (fd != -1) {
+ TEMP_FAILURE_RETRY(close(fd));
+ }
+
+ return rc;
+}
+
+static int was_verity_restart()
+{
+ static const char *files[] = {
+ "/sys/fs/pstore/console-ramoops",
+ "/proc/last_kmsg",
+ NULL
+ };
+ int i;
+
+ for (i = 0; files[i]; ++i) {
+ if (check_verity_restart(files[i])) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
+{
+ int fd;
+ int rc = -1;
+
+ struct verity_state s = {
+ VERITY_STATE_HEADER,
+ VERITY_STATE_VERSION,
+ sizeof(struct verity_state),
+ mode
+ };
+
+ fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
+
+ if (fd == -1) {
+ ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+ goto out;
+ }
+
+ if (TEMP_FAILURE_RETRY(lseek64(fd, offset, SEEK_SET)) < 0) {
+ ERROR("Failed to seek %s to %" PRIu64 " (%s)\n", fname, offset, strerror(errno));
+ goto out;
+ }
+
+ if (TEMP_FAILURE_RETRY(write(fd, &s, sizeof(s))) != sizeof(s)) {
+ ERROR("Failed to write %zu bytes to %s (%s)\n", sizeof(s), fname, strerror(errno));
+ goto out;
+ }
+
+ rc = 0;
+
+out:
+ if (fd != -1) {
+ TEMP_FAILURE_RETRY(close(fd));
+ }
+
+ return rc;
+}
+
+static int get_verity_state_location(char *location, off64_t *offset)
+{
+ char state_off[PROPERTY_VALUE_MAX];
+
+ if (property_get("ro.verity.state.location", location, NULL) <= 0) {
+ return -1;
+ }
+
+ if (*location != '/' || access(location, R_OK | W_OK) == -1) {
+ ERROR("Failed to access verity state %s (%s)\n", location, strerror(errno));
+ return -1;
+ }
+
+ *offset = 0;
+
+ if (property_get("ro.verity.state.offset", state_off, NULL) > 0) {
+ *offset = strtoll(state_off, NULL, 0);
+
+ if (errno == ERANGE || errno == EINVAL) {
+ ERROR("Invalid value in ro.verity.state.offset (%s)\n", state_off);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int fs_mgr_load_verity_state(int *mode)
+{
+ char fname[PROPERTY_VALUE_MAX];
+ int fd = -1;
+ int rc = -1;
+ off64_t offset = 0;
+ struct verity_state s;
+
+ if (get_verity_state_location(fname, &offset) < 0) {
+ /* location for dm-verity state is not specified, fall back to
+ * default behavior: return -EIO for corrupted blocks */
+ *mode = VERITY_MODE_EIO;
+ rc = 0;
+ goto out;
+ }
+
+ if (was_verity_restart()) {
+ /* device was restarted after dm-verity detected a corrupted
+ * block, so switch to logging mode */
+ *mode = VERITY_MODE_LOGGING;
+ rc = write_verity_state(fname, offset, *mode);
+ goto out;
+ }
+
+ fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
+
+ if (fd == -1) {
+ ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
+ goto out;
+ }
+
+ if (TEMP_FAILURE_RETRY(lseek64(fd, offset, SEEK_SET)) < 0) {
+ ERROR("Failed to seek %s to %" PRIu64 " (%s)\n", fname, offset, strerror(errno));
+ goto out;
+ }
+
+ if (TEMP_FAILURE_RETRY(read(fd, &s, sizeof(s))) != sizeof(s)) {
+ ERROR("Failed to read %zu bytes from %s (%s)\n", sizeof(s), fname, strerror(errno));
+ goto out;
+ }
+
+ if (s.header != VERITY_STATE_HEADER) {
+ goto out;
+ }
+
+ if (s.version != VERITY_STATE_VERSION) {
+ ERROR("Unsupported verity state version (%u)\n", s.version);
+ goto out;
+ }
+
+ if (s.size != sizeof(s)) {
+ ERROR("Unexpected verity state size (%u)\n", s.size);
+ goto out;
+ }
+
+ if (s.mode < VERITY_MODE_EIO ||
+ s.mode > VERITY_MODE_LAST) {
+ ERROR("Unsupported verity mode (%u)\n", s.mode);
+ goto out;
+ }
+
+ *mode = s.mode;
+ rc = 0;
+
+out:
+ if (fd != -1) {
+ TEMP_FAILURE_RETRY(close(fd));
+ }
+
+ return rc;
+}
+
+int fs_mgr_update_verity_state()
+{
+ _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
+ char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+ char *mount_point;
+ char propbuf[PROPERTY_VALUE_MAX];
+ char state_loc[PROPERTY_VALUE_MAX];
+ char *status;
+ int fd = -1;
+ int i;
+ int rc = -1;
+ off64_t offset = 0;
+ struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+ struct fstab *fstab = NULL;
+
+ if (get_verity_state_location(state_loc, &offset) < 0) {
+ goto out;
+ }
+
+ fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
+
+ if (fd == -1) {
+ ERROR("Error opening device mapper (%s)\n", strerror(errno));
+ goto out;
+ }
+
+ property_get("ro.hardware", propbuf, "");
+ snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+ fstab = fs_mgr_read_fstab(fstab_filename);
+
+ if (!fstab) {
+ ERROR("Failed to read %s\n", fstab_filename);
+ goto out;
+ }
+
+ for (i = 0; i < fstab->num_entries; i++) {
+ if (!fs_mgr_is_verified(&fstab->recs[i])) {
+ continue;
+ }
+
+ mount_point = basename(fstab->recs[i].mount_point);
+ verity_ioctl_init(io, mount_point, 0);
+
+ if (ioctl(fd, DM_TABLE_STATUS, io)) {
+ ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
+ strerror(errno));
+ goto out;
+ }
+
+ status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
+
+ if (*status == 'C') {
+ rc = write_verity_state(state_loc, offset, VERITY_MODE_LOGGING);
+ goto out;
+ }
+ }
+
+ /* Don't overwrite possible previous state if there's no corruption. */
+ rc = 0;
+
+out:
+ if (fstab) {
+ fs_mgr_free_fstab(fstab);
+ }
+
+ if (fd) {
+ TEMP_FAILURE_RETRY(close(fd));
+ }
+
+ return rc;
+}
+
int fs_mgr_setup_verity(struct fstab_rec *fstab) {
- int retval = -1;
+ int retval = FS_MGR_SETUP_VERITY_FAIL;
int fd = -1;
+ int mode;
char *verity_blk_name = 0;
char *verity_table = 0;
char *verity_table_signature = 0;
- char buffer[DM_BUF_SIZE];
+ _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
char *mount_point = basename(fstab->mount_point);
@@ -407,6 +719,8 @@
goto out;
}
+ retval = FS_MGR_SETUP_VERITY_FAIL;
+
// get the device mapper fd
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
ERROR("Error opening device mapper (%s)", strerror(errno));
@@ -432,8 +746,13 @@
goto out;
}
+ if (fs_mgr_load_verity_state(&mode) < 0) {
+ mode = VERITY_MODE_RESTART; /* default dm-verity mode */
+ }
+
// load the verity mapping table
- if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table) < 0) {
+ if (load_verity_table(io, mount_point, fstab->blk_device, fd, verity_table,
+ mode) < 0) {
goto out;
}
@@ -455,8 +774,12 @@
goto out;
}
- // set the property indicating that the partition is verified
- retval = set_verified_property(mount_point);
+ if (mode == VERITY_MODE_LOGGING) {
+ retval = FS_MGR_SETUP_VERITY_SUCCESS;
+ } else {
+ // set the property indicating that the partition is verified
+ retval = set_verified_property(mount_point);
+ }
out:
if (fd != -1) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 5ec3b99..57600ef 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -27,6 +27,14 @@
// turn verity off in userdebug builds.
#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
+// Verity modes
+enum verity_mode {
+ VERITY_MODE_EIO = 0,
+ VERITY_MODE_LOGGING = 1,
+ VERITY_MODE_RESTART = 2,
+ VERITY_MODE_LAST = VERITY_MODE_RESTART
+};
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -75,6 +83,8 @@
int fs_mgr_unmount_all(struct fstab *fstab);
int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
char *real_blk_device, int size);
+int fs_mgr_load_verity_state(int *mode);
+int fs_mgr_update_verity_state();
int fs_mgr_add_entry(struct fstab *fstab,
const char *mount_point, const char *fs_type,
const char *blk_device);
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index cc7ba30..724ca51 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -41,4 +41,46 @@
log_time realtime;
} android_log_header_t;
+/* Event Header Structure to logd */
+typedef struct __attribute__((__packed__)) {
+ int32_t tag; // Little Endian Order
+} android_event_header_t;
+
+/* Event payload EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+ int8_t type; // EVENT_TYPE_INT
+ int32_t data; // Little Endian Order
+} android_event_int_t;
+
+/* Event with single EVENT_TYPE_INT */
+typedef struct __attribute__((__packed__)) {
+ android_event_header_t header;
+ android_event_int_t payload;
+} android_log_event_int_t;
+
+/* Event payload EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+ int8_t type; // EVENT_TYPE_LONG
+ int64_t data; // Little Endian Order
+} android_event_long_t;
+
+/* Event with single EVENT_TYPE_LONG */
+typedef struct __attribute__((__packed__)) {
+ android_event_header_t header;
+ android_event_long_t payload;
+} android_log_event_long_t;
+
+/* Event payload EVENT_TYPE_STRING */
+typedef struct __attribute__((__packed__)) {
+ int8_t type; // EVENT_TYPE_STRING;
+ int32_t length; // Little Endian Order
+ char data[];
+} android_event_string_t;
+
+/* Event with single EVENT_TYPE_STRING */
+typedef struct __attribute__((__packed__)) {
+ android_event_header_t header;
+ android_event_string_t payload;
+} android_log_event_string_t;
+
#endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 9f3dcc1..b4204d8 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -712,6 +712,20 @@
return 0;
}
+int do_verity_load_state(int nargs, char **args) {
+ if (nargs == 1) {
+ int mode = -1;
+ int rc = fs_mgr_load_verity_state(&mode);
+
+ if (rc == 0 && mode == VERITY_MODE_LOGGING) {
+ action_for_each_trigger("verity-logging", action_add_queue_tail);
+ }
+
+ return rc;
+ }
+ return -1;
+}
+
int do_write(int nargs, char **args)
{
const char *path = args[1];
diff --git a/init/grab-bootchart.sh b/init/grab-bootchart.sh
index 5715862..d6082aa 100755
--- a/init/grab-bootchart.sh
+++ b/init/grab-bootchart.sh
@@ -1,12 +1,9 @@
#!/bin/sh
#
-# this script is used to retrieve the bootchart log generated
-# by init when compiled with INIT_BOOTCHART=true.
-#
+# This script is used to retrieve a bootchart log generated by init.
# All options are passed to adb, for better or for worse.
-#
-# for all details, see //device/system/init/README.BOOTCHART
-#
+# See the readme in this directory for more on bootcharting.
+
TMPDIR=/tmp/android-bootchart
rm -rf $TMPDIR
mkdir -p $TMPDIR
@@ -22,4 +19,4 @@
(cd $TMPDIR && tar -czf $TARBALL $FILES)
bootchart ${TMPDIR}/${TARBALL}
gnome-open ${TARBALL%.tgz}.png
-echo "Clean up ${TMPDIR}/ & ./${TARBALL%.tgz}.png when done"
+echo "Clean up ${TMPDIR}/ and ./${TARBALL%.tgz}.png when done"
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 61a5e0a..3932357 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -204,6 +204,9 @@
case 'u':
if (!strcmp(s, "ser")) return K_user;
break;
+ case 'v':
+ if (!strcmp(s, "erity_load_state")) return K_verity_load_state;
+ break;
case 'w':
if (!strcmp(s, "rite")) return K_write;
if (!strcmp(s, "ait")) return K_wait;
diff --git a/init/keywords.h b/init/keywords.h
index a8f29d1..60931f1 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -41,6 +41,7 @@
int do_loglevel(int nargs, char **args);
int do_load_persist_props(int nargs, char **args);
int do_load_all_props(int nargs, char **args);
+int do_verity_load_state(int nargs, char **args);
int do_wait(int nargs, char **args);
#define __MAKE_KEYWORD_ENUM__
#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
@@ -97,6 +98,7 @@
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
KEYWORD(user, OPTION, 0, 0)
+ KEYWORD(verity_load_state, COMMAND, 0, do_verity_load_state)
KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
KEYWORD(copy, COMMAND, 2, do_copy)
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 5756c54..4e6424a 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -16,6 +16,14 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
+# This is what we want to do:
+# liblog_cflags := $(shell \
+# sed -n \
+# 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
+# $(LOCAL_PATH)/event.logtags)
+# so make sure we do not regret hard-coding it as follows:
+liblog_cflags := -DLIBLOG_LOG_TAG=1005
+
ifneq ($(TARGET_USES_LOGD),false)
liblog_sources := logd_write.c
else
@@ -25,28 +33,20 @@
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
# which are also hard or even impossible to port to native Win32
-WITH_MINGW :=
-ifeq ($(HOST_OS),windows)
- ifeq ($(strip $(USE_CYGWIN)),)
- WITH_MINGW := true
- endif
-endif
-# USE_MINGW is defined when we build against Mingw on Linux
-ifneq ($(strip $(USE_MINGW)),)
- WITH_MINGW := true
-endif
-ifndef WITH_MINGW
+ifeq ($(strip $(USE_MINGW)),)
liblog_sources += \
- logprint.c \
event_tag_map.c
else
liblog_sources += \
uio.c
endif
-liblog_host_sources := $(liblog_sources) fake_log_device.c
+liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
liblog_target_sources := $(liblog_sources) log_time.cpp log_is_loggable.c
+ifeq ($(strip $(USE_MINGW)),)
+liblog_target_sources += logprint.c
+endif
ifneq ($(TARGET_USES_LOGD),false)
liblog_target_sources += log_read.c
else
@@ -57,7 +57,7 @@
# ========================================================
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror $(liblog_cflags)
LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -76,13 +76,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror $(liblog_cflags)
include $(BUILD_SHARED_LIBRARY)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/README b/liblog/README
index 461dfbe..f29ac04 100644
--- a/liblog/README
+++ b/liblog/README
@@ -131,6 +131,33 @@
when opening the sub-log. It is recommended to open the log
ANDROID_LOG_RDONLY in these cases.
+ERRORS
+ If messages fail, a negative error code will be returned to the caller.
+
+ The -ENOTCONN return code indicates that the logger daemon is stopped.
+
+ The -EBADF return code indicates that the log access point can not be
+ opened, or the log buffer id is out of range.
+
+ For the -EAGAIN return code, this means that the logging message was
+ temporarily backed-up either because of Denial Of Service (DOS) logging
+ pressure from some chatty application or service in the Android system,
+ or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen.
+ To aid in diagnosing the occurence of this, a binary event from liblog
+ will be sent to the log daemon once a new message can get through
+ indicating how many messages were dropped as a result. Please take
+ action to resolve the structural problems at the source.
+
+ It is generally not advised for the caller to retry the -EAGAIN return
+ code as this will only make the problem(s) worse and cause your
+ application to temporarily drop to the logger daemon priority, BATCH
+ scheduling policy and background task cgroup. If you require a group of
+ messages to be passed atomically, merge them into one message with
+ embedded newlines to the maximum length LOGGER_ENTRY_MAX_PAYLOAD.
+
+ Other return codes from writing operation can be returned. Since the
+ library retries on EINTR, -EINTR should never be returned.
+
SEE ALSO
syslogd(8)
diff --git a/liblog/event.logtags b/liblog/event.logtags
new file mode 100644
index 0000000..72ecab1
--- /dev/null
+++ b/liblog/event.logtags
@@ -0,0 +1,36 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace. Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+# (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1005 liblog (dropped|1)
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 0208c73..a865093 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -13,12 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#if (FAKE_LOG_DEVICE == 0)
+#include <endian.h>
+#endif
#include <errno.h>
#include <fcntl.h>
#if !defined(_WIN32)
#include <pthread.h>
#endif
#include <stdarg.h>
+#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -172,6 +176,7 @@
size_t i, payload_size;
static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
static pid_t last_pid = (pid_t) -1;
+ static atomic_int_fast32_t dropped;
if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
last_uid = getuid();
@@ -206,7 +211,6 @@
pmsg_header.uid = last_uid;
pmsg_header.pid = last_pid;
- header.id = log_id;
header.tid = gettid();
header.realtime.tv_sec = ts.tv_sec;
header.realtime.tv_nsec = ts.tv_nsec;
@@ -216,6 +220,28 @@
newVec[1].iov_base = (unsigned char *) &header;
newVec[1].iov_len = sizeof(header);
+ if (logd_fd > 0) {
+ int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+ if (snapshot) {
+ android_log_event_int_t buffer;
+
+ header.id = LOG_ID_EVENTS;
+ buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+ buffer.payload.type = EVENT_TYPE_INT;
+ buffer.payload.data = htole32(snapshot);
+
+ newVec[2].iov_base = &buffer;
+ newVec[2].iov_len = sizeof(buffer);
+
+ ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+ if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+ atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+ }
+ }
+ }
+
+ header.id = log_id;
+
for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
newVec[i].iov_base = vec[i - header_length].iov_base;
payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
@@ -281,6 +307,8 @@
if (ret > (ssize_t)sizeof(header)) {
ret -= sizeof(header);
+ } else if (ret == -EAGAIN) {
+ atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
}
#endif
@@ -463,7 +491,7 @@
}
__android_log_write(ANDROID_LOG_FATAL, tag, buf);
- __builtin_trap(); /* trap so we have a chance to debug the situation */
+ abort(); /* abort so we have a chance to debug the situation */
/* NOTREACHED */
}
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 2ca3c94..ca63067 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -266,7 +266,7 @@
}
__android_log_write(ANDROID_LOG_FATAL, tag, buf);
- __builtin_trap(); /* trap so we have a chance to debug the situation */
+ abort(); /* abort so we have a chance to debug the situation */
/* NOTREACHED */
}
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index ba7b74d..3937449 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -24,7 +24,8 @@
LOCAL_STATIC_LIBRARIES := libz
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_MODULE:= libziparchive
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CPPFLAGS := -Wold-style-cast
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index ebbab9f..59a1734 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -18,6 +18,8 @@
* Read-only access to Zip archives, with minimal heap allocation.
*/
+#include <memory>
+
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -293,7 +295,7 @@
/* mapped central directory area */
off64_t directory_offset;
- android::FileMap* directory_map;
+ android::FileMap directory_map;
/* number of entries in the Zip archive */
uint16_t num_entries;
@@ -311,7 +313,6 @@
fd(fd),
close_file(assume_ownership),
directory_offset(0),
- directory_map(NULL),
num_entries(0),
hash_table_size(0),
hash_table(NULL) {}
@@ -321,25 +322,10 @@
close(fd);
}
- delete directory_map;
free(hash_table);
}
};
-// Returns 0 on success and negative values on failure.
-static android::FileMap* MapFileSegment(const int fd, const off64_t start,
- const size_t length, const bool read_only,
- const char* debug_file_name) {
- android::FileMap* file_map = new android::FileMap;
- const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
- if (!success) {
- delete file_map;
- return NULL;
- }
-
- return file_map;
-}
-
static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
static const uint32_t kBufSize = 32768;
uint8_t buf[kBufSize];
@@ -521,16 +507,12 @@
* It all looks good. Create a mapping for the CD, and set the fields
* in archive.
*/
- android::FileMap* map = MapFileSegment(fd,
- static_cast<off64_t>(eocd->cd_start_offset),
- static_cast<size_t>(eocd->cd_size),
- true /* read only */, debug_file_name);
- if (map == NULL) {
- archive->directory_map = NULL;
+ if (!archive->directory_map.create(debug_file_name, fd,
+ static_cast<off64_t>(eocd->cd_start_offset),
+ static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
return kMmapFailed;
}
- archive->directory_map = map;
archive->num_entries = eocd->num_records;
archive->directory_offset = eocd->cd_start_offset;
@@ -557,7 +539,7 @@
return kInvalidFile;
}
- if (file_length > (off64_t) 0xffffffff) {
+ if (file_length > static_cast<off64_t>(0xffffffff)) {
ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
return kInvalidFile;
}
@@ -599,9 +581,9 @@
* Returns 0 on success.
*/
static int32_t ParseZipArchive(ZipArchive* archive) {
- int32_t result = -1;
- const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
- const size_t cd_length = archive->directory_map->getDataLength();
+ const uint8_t* const cd_ptr =
+ reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
+ const size_t cd_length = archive->directory_map.getDataLength();
const uint16_t num_entries = archive->num_entries;
/*
@@ -610,8 +592,8 @@
* least one unused entry to avoid an infinite loop during creation.
*/
archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
- archive->hash_table = (ZipEntryName*) calloc(archive->hash_table_size,
- sizeof(ZipEntryName));
+ archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
+ sizeof(ZipEntryName)));
/*
* Walk through the central directory, adding entries to the hash
@@ -624,18 +606,19 @@
reinterpret_cast<const CentralDirectoryRecord*>(ptr);
if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
- goto bail;
+ return -1;
}
if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
- goto bail;
+ return -1;
}
const off64_t local_header_offset = cdr->local_file_header_offset;
if (local_header_offset >= archive->directory_offset) {
- ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
- goto bail;
+ ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
+ static_cast<int64_t>(local_header_offset), i);
+ return -1;
}
const uint16_t file_name_length = cdr->file_name_length;
@@ -645,7 +628,7 @@
/* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
if (!IsValidEntryName(file_name, file_name_length)) {
- goto bail;
+ return -1;
}
/* add the CDE filename to the hash table */
@@ -654,25 +637,21 @@
entry_name.name_length = file_name_length;
const int add_result = AddToHash(archive->hash_table,
archive->hash_table_size, entry_name);
- if (add_result) {
+ if (add_result != 0) {
ALOGW("Zip: Error adding entry to hash table %d", add_result);
- result = add_result;
- goto bail;
+ return add_result;
}
ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
ptr - cd_ptr, cd_length, i);
- goto bail;
+ return -1;
}
}
ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
- result = 0;
-
-bail:
- return result;
+ return 0;
}
static int32_t OpenArchiveInternal(ZipArchive* archive,
@@ -713,7 +692,7 @@
* Close a ZipArchive, closing the file and freeing the contents.
*/
void CloseArchive(ZipArchiveHandle handle) {
- ZipArchive* archive = (ZipArchive*) handle;
+ ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
ALOGV("Closing archive %p", archive);
delete archive;
}
@@ -774,8 +753,8 @@
// the name that's in the hash table is a pointer to a location within
// this mapped region.
const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
- archive->directory_map->getDataPtr());
- if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
+ archive->directory_map.getDataPtr());
+ if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
ALOGW("Zip: Invalid entry pointer");
return kInvalidOffset;
}
@@ -810,7 +789,8 @@
ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
local_header_offset);
if (actual != sizeof(lfh_buf)) {
- ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64,
+ static_cast<int64_t>(local_header_offset));
return kIoError;
}
@@ -848,12 +828,12 @@
return kInvalidOffset;
}
- uint8_t* name_buf = (uint8_t*) malloc(nameLen);
+ uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
ssize_t actual = ReadAtOffset(archive->fd, name_buf, nameLen,
name_offset);
if (actual != nameLen) {
- ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
free(name_buf);
return kIoError;
}
@@ -872,20 +852,21 @@
const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
+ lfh->file_name_length + lfh->extra_field_length;
if (data_offset > cd_offset) {
- ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
+ ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
return kInvalidOffset;
}
- if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
+ if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
- (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
+ static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
return kInvalidOffset;
}
if (data->method == kCompressStored &&
- (off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
+ static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
- (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
+ static_cast<int64_t>(data_offset), data->uncompressed_length,
+ static_cast<int64_t>(cd_offset));
return kInvalidOffset;
}
@@ -917,7 +898,7 @@
int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
const ZipEntryName* optional_prefix) {
- ZipArchive* archive = (ZipArchive *) handle;
+ ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
if (archive == NULL || archive->hash_table == NULL) {
ALOGW("Zip: Invalid ZipArchiveHandle");
@@ -939,7 +920,7 @@
int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
ZipEntry* data) {
- const ZipArchive* archive = (ZipArchive*) handle;
+ const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
if (entryName.name_length == 0) {
ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
return kInvalidEntryName;
@@ -957,7 +938,7 @@
}
int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
- IterationHandle* handle = (IterationHandle *) cookie;
+ IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
if (handle == NULL) {
return kInvalidHandle;
}
@@ -991,10 +972,17 @@
return kIterationEnd;
}
+// This method is using libz macros with old-style-casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
+ return inflateInit2(stream, window_bits);
+}
+#pragma GCC diagnostic pop
+
static int32_t InflateToFile(int fd, const ZipEntry* entry,
uint8_t* begin, uint32_t length,
uint64_t* crc_out) {
- int32_t result = -1;
const uint32_t kBufSize = 32768;
uint8_t read_buf[kBufSize];
uint8_t write_buf[kBufSize];
@@ -1010,7 +998,7 @@
zstream.opaque = Z_NULL;
zstream.next_in = NULL;
zstream.avail_in = 0;
- zstream.next_out = (Bytef*) write_buf;
+ zstream.next_out = reinterpret_cast<Bytef*>(write_buf);
zstream.avail_out = kBufSize;
zstream.data_type = Z_UNKNOWN;
@@ -1018,7 +1006,7 @@
* Use the undocumented "negative window bits" feature to tell zlib
* that there's no zlib header waiting for it.
*/
- zerr = inflateInit2(&zstream, -MAX_WBITS);
+ zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
if (zerr != Z_OK) {
if (zerr == Z_VERSION_ERROR) {
ALOGE("Installed zlib is not compatible with linked version (%s)",
@@ -1030,6 +1018,12 @@
return kZlibError;
}
+ auto zstream_deleter = [](z_stream* stream) {
+ inflateEnd(stream); /* free up any allocated structures */
+ };
+
+ std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
+
const uint32_t uncompressed_length = entry->uncompressed_length;
uint32_t compressed_length = entry->compressed_length;
@@ -1041,8 +1035,7 @@
const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
if (actual != getSize) {
ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
- result = kIoError;
- goto z_bail;
+ return kIoError;
}
compressed_length -= getSize;
@@ -1057,8 +1050,7 @@
ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
zerr, zstream.next_in, zstream.avail_in,
zstream.next_out, zstream.avail_out);
- result = kZlibError;
- goto z_bail;
+ return kZlibError;
}
/* write when we're full or when we're done */
@@ -1067,7 +1059,7 @@
const size_t write_size = zstream.next_out - write_buf;
// The file might have declared a bogus length.
if (write_size + write_count > length) {
- goto z_bail;
+ return -1;
}
memcpy(begin + write_count, write_buf, write_size);
write_count += write_size;
@@ -1085,26 +1077,20 @@
if (zstream.total_out != uncompressed_length || compressed_length != 0) {
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
zstream.total_out, uncompressed_length);
- result = kInconsistentInformation;
- goto z_bail;
+ return kInconsistentInformation;
}
- result = 0;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
- return result;
+ return 0;
}
int32_t ExtractToMemory(ZipArchiveHandle handle,
ZipEntry* entry, uint8_t* begin, uint32_t size) {
- ZipArchive* archive = (ZipArchive*) handle;
+ ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
off64_t data_offset = entry->offset;
if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
- ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
+ ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
return kIoError;
}
@@ -1148,7 +1134,7 @@
int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
if (result == -1) {
ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
- (int64_t)(declared_length + current_offset), strerror(errno));
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
return kIoError;
}
@@ -1159,16 +1145,14 @@
return 0;
}
- android::FileMap* map = MapFileSegment(fd, current_offset, declared_length,
- false, kTempMappingFileName);
- if (map == NULL) {
+ android::FileMap map;
+ if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) {
return kMmapFailed;
}
const int32_t error = ExtractToMemory(handle, entry,
- reinterpret_cast<uint8_t*>(map->getDataPtr()),
- map->getDataLength());
- delete map;
+ reinterpret_cast<uint8_t*>(map.getDataPtr()),
+ map.getDataLength());
return error;
}
@@ -1181,6 +1165,6 @@
}
int GetFileDescriptor(const ZipArchiveHandle handle) {
- return ((ZipArchive*) handle)->fd;
+ return reinterpret_cast<ZipArchive*>(handle)->fd;
}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index cd5003e..7e4eadd 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -38,14 +38,12 @@
struct logger *logger;
struct logger_list *logger_list;
bool printed;
- char label;
log_device_t* next;
- log_device_t(const char* d, bool b, char l) {
+ log_device_t(const char* d, bool b) {
device = d;
binary = b;
- label = l;
next = NULL;
printed = false;
}
@@ -61,9 +59,7 @@
static int g_outFD = -1;
static off_t g_outByteCount = 0;
static int g_printBinary = 0;
-static int g_devCount = 0;
-
-static EventTagMap* g_eventTagMap = NULL;
+static int g_devCount = 0; // >1 means multiple
static int openLogFile (const char *pathname)
{
@@ -133,8 +129,15 @@
char binaryMsgBuf[1024];
if (dev->binary) {
+ static bool hasOpenedEventTagMap = false;
+ static EventTagMap *eventTagMap = NULL;
+
+ if (!eventTagMap && !hasOpenedEventTagMap) {
+ eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ hasOpenedEventTagMap = true;
+ }
err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
- g_eventTagMap,
+ eventTagMap,
binaryMsgBuf,
sizeof(binaryMsgBuf));
//printf(">>> pri=%d len=%d msg='%s'\n",
@@ -147,16 +150,6 @@
}
if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
- if (false && g_devCount > 1) {
- binaryMsgBuf[0] = dev->label;
- binaryMsgBuf[1] = ' ';
- bytesWritten = write(g_outFD, binaryMsgBuf, 2);
- if (bytesWritten < 0) {
- perror("output error");
- exit(-1);
- }
- }
-
bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
if (bytesWritten < 0) {
@@ -331,7 +324,6 @@
const char *forceFilters = NULL;
log_device_t* devices = NULL;
log_device_t* dev;
- bool needBinary = false;
bool printDividers = false;
struct logger_list *logger_list;
unsigned int tail_lines = 0;
@@ -469,7 +461,6 @@
devices = dev = NULL;
android::g_devCount = 0;
- needBinary = false;
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);
@@ -479,7 +470,7 @@
}
bool binary = strcmp(name, "events") == 0;
- log_device_t* d = new log_device_t(name, binary, *name);
+ log_device_t* d = new log_device_t(name, binary);
if (dev) {
dev->next = d;
@@ -488,26 +479,20 @@
devices = dev = d;
}
android::g_devCount++;
- if (binary) {
- needBinary = true;
- }
}
break;
}
bool binary = strcmp(optarg, "events") == 0;
- if (binary) {
- needBinary = true;
- }
if (devices) {
dev = devices;
while (dev->next) {
dev = dev->next;
}
- dev->next = new log_device_t(optarg, binary, optarg[0]);
+ dev->next = new log_device_t(optarg, binary);
} else {
- devices = new log_device_t(optarg, binary, optarg[0]);
+ devices = new log_device_t(optarg, binary);
}
android::g_devCount++;
}
@@ -641,14 +626,14 @@
}
if (!devices) {
- dev = devices = new log_device_t("main", false, 'm');
+ dev = devices = new log_device_t("main", false);
android::g_devCount = 1;
if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
- dev = dev->next = new log_device_t("system", false, 's');
+ dev = dev->next = new log_device_t("system", false);
android::g_devCount++;
}
if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
- dev = dev->next = new log_device_t("crash", false, 'c');
+ dev = dev->next = new log_device_t("crash", false);
android::g_devCount++;
}
}
@@ -848,17 +833,15 @@
//LOG_EVENT_LONG(11, 0x1122334455667788LL);
//LOG_EVENT_STRING(0, "whassup, doc?");
- if (needBinary)
- android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
-
dev = NULL;
+ log_device_t unexpected("unexpected", false);
while (1) {
struct log_msg log_msg;
log_device_t* d;
int ret = android_logger_list_read(logger_list, &log_msg);
if (ret == 0) {
- fprintf(stderr, "read: Unexpected EOF!\n");
+ fprintf(stderr, "read: unexpected EOF!\n");
exit(EXIT_FAILURE);
}
@@ -868,7 +851,7 @@
}
if (ret == -EIO) {
- fprintf(stderr, "read: Unexpected EOF!\n");
+ fprintf(stderr, "read: unexpected EOF!\n");
exit(EXIT_FAILURE);
}
if (ret == -EINVAL) {
@@ -885,8 +868,9 @@
}
}
if (!d) {
- fprintf(stderr, "read: Unexpected log ID!\n");
- exit(EXIT_FAILURE);
+ android::g_devCount = 2; // set to Multiple
+ d = &unexpected;
+ d->binary = log_msg.id() == LOG_ID_EVENTS;
}
if (dev != d) {
diff --git a/logd/Android.mk b/logd/Android.mk
index 188511f..127a66b 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -26,7 +26,16 @@
libcutils \
libutils
-LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags)
+# This is what we want to do:
+# event_logtags = $(shell \
+# sed -n \
+# "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \
+# $(LOCAL_PATH)/$2/event.logtags)
+# event_flag := $(call event_logtags,auditd)
+# so make sure we do not regret hard-coding it as follows:
+event_flag := -DAUDITD_LOG_TAG=1003
+
+LOCAL_CFLAGS := -Werror $(event_flag)
include $(BUILD_EXECUTABLE)
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index c7c0249..af0b775 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <endian.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
@@ -23,6 +24,8 @@
#include <sys/uio.h>
#include <syslog.h>
+#include <private/android_logger.h>
+
#include "libaudit.h"
#include "LogAudit.h"
@@ -138,29 +141,23 @@
// log to events
size_t l = strlen(str);
- size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+ size_t n = l + sizeof(android_log_event_string_t);
bool notify = false;
- char *newstr = reinterpret_cast<char *>(malloc(n));
- if (!newstr) {
+ android_log_event_string_t *event = static_cast<android_log_event_string_t *>(malloc(n));
+ if (!event) {
rc = -ENOMEM;
} else {
- cp = newstr;
- *cp++ = AUDITD_LOG_TAG & 0xFF;
- *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
- *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
- *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
- *cp++ = EVENT_TYPE_STRING;
- *cp++ = l & 0xFF;
- *cp++ = (l >> 8) & 0xFF;
- *cp++ = (l >> 16) & 0xFF;
- *cp++ = (l >> 24) & 0xFF;
- memcpy(cp, str, l);
+ event->header.tag = htole32(AUDITD_LOG_TAG);
+ event->payload.type = EVENT_TYPE_STRING;
+ event->payload.length = htole32(l);
+ memcpy(event->payload.data, str, l);
- logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
+ logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
+ reinterpret_cast<char *>(event),
(n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
- free(newstr);
+ free(event);
notify = true;
}
@@ -190,7 +187,7 @@
}
n = (estr - str) + strlen(ecomm) + l + 2;
- newstr = reinterpret_cast<char *>(malloc(n));
+ char *newstr = static_cast<char *>(malloc(n));
if (!newstr) {
rc = -ENOMEM;
} else {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 3d0b38f..edda6c4 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -93,8 +93,7 @@
}
LogBuffer::LogBuffer(LastLogTimes *times)
- : dgramQlenStatistics(false)
- , mTimes(*times) {
+ : mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
static const char global_tuneable[] = "persist.logd.size"; // Settings App
@@ -150,23 +149,6 @@
while (last != mLogElements.begin()) {
--it;
if ((*it)->getRealTime() <= realtime) {
- // halves the peak performance, use with caution
- if (dgramQlenStatistics) {
- LogBufferElementCollection::iterator ib = it;
- unsigned short buckets, num = 1;
- for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) {
- buckets -= num;
- num += buckets;
- while (buckets && (--ib != mLogElements.begin())) {
- --buckets;
- }
- if (buckets) {
- break;
- }
- stats.recordDiff(
- elem->getRealTime() - (*ib)->getRealTime(), i);
- }
- }
break;
}
last = it;
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 879baea..b0003de 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -37,7 +37,6 @@
pthread_mutex_t mLogElementsLock;
LogStatistics stats;
- bool dgramQlenStatistics;
PruneList mPrune;
@@ -63,11 +62,6 @@
// *strp uses malloc, use free to release.
void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
- void enableDgramQlenStatistics() {
- stats.enableDgramQlenStatistics();
- dgramQlenStatistics = true;
- }
-
void enableStatistics() {
stats.enableStatistics();
}
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 53036e6..5a70689 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -395,71 +395,11 @@
LogStatistics::LogStatistics()
: mStatistics(false)
- , dgramQlenStatistics(false)
, start(CLOCK_MONOTONIC) {
log_id_for_each(i) {
mSizes[i] = 0;
mElements[i] = 0;
}
-
- for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) {
- mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
- mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
- }
-}
-
-// Each bucket below represents a dgramQlen of log messages. By
-// finding the minimum period of time from start to finish
-// of each dgramQlen, we can get a performance expectation for
-// the user space logger. The net result is that the period
-// of time divided by the dgramQlen will give us the average time
-// between log messages; at the point where the average time
-// is greater than the throughput capability of the logger
-// we will not longer require the benefits of the FIFO formed
-// by max_dgram_qlen. We will also expect to see a very visible
-// knee in the average time between log messages at this point,
-// so we do not necessarily have to compare the rate against the
-// measured performance (BM_log_maximum_retry) of the logger.
-//
-// for example (reformatted):
-//
-// Minimum time between log events per dgramQlen:
-// 1 2 3 5 10 20 30 50 100 200 300 400 500 600
-// 5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5
-//
-// demonstrates a clear knee rising at 100, so this means that for this
-// case max_dgram_qlen = 100 would be more than sufficient to handle the
-// worst that the system could stuff into the logger. The
-// BM_log_maximum_retry performance (derated by the log collection) on the
-// same system was 33.2us so we would almost be fine with max_dgram_qlen = 50.
-// BM_log_maxumum_retry with statistics off is roughly 20us, so
-// max_dgram_qlen = 20 would work. We will be more than willing to have
-// a large engineering margin so the rule of thumb that lead us to 100 is
-// fine.
-//
-// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
-const unsigned short LogStatistics::mBuckets[] = {
- 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600
-};
-
-unsigned short LogStatistics::dgramQlen(unsigned short bucket) {
- if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
- return 0;
- }
- return mBuckets[bucket];
-}
-
-unsigned long long LogStatistics::minimum(unsigned short bucket) {
- if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
- return 0;
- }
- return mMinimum[bucket].nsec();
-}
-
-void LogStatistics::recordDiff(log_time diff, unsigned short bucket) {
- if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) {
- mMinimum[bucket] = diff;
- }
}
void LogStatistics::add(unsigned short size,
@@ -709,55 +649,6 @@
pids.clear();
}
- if (dgramQlenStatistics) {
- const unsigned short spaces_time = 6;
- const unsigned long long max_seconds = 100000;
- spaces = 0;
- string.append("\n\nMinimum time between log events per max_dgram_qlen:\n");
- for(unsigned short i = 0; dgramQlen(i); ++i) {
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%u", spaces, "", dgramQlen(i));
- spaces += spaces_time + oldLength - string.length();
- }
- string.append("\n");
- spaces = 0;
- unsigned short n;
- for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
- unsigned long long duration = minimum(i);
- if (duration) {
- duration /= n;
- if (duration >= (NS_PER_SEC * max_seconds)) {
- duration = NS_PER_SEC * (max_seconds - 1);
- }
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s", spaces, "");
- if (duration >= (NS_PER_SEC * 10)) {
- string.appendFormat("%llu",
- (duration + (NS_PER_SEC / 2))
- / NS_PER_SEC);
- } else if (duration >= (NS_PER_SEC / (1000 / 10))) {
- string.appendFormat("%llum",
- (duration + (NS_PER_SEC / 2 / 1000))
- / (NS_PER_SEC / 1000));
- } else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
- string.appendFormat("%lluu",
- (duration + (NS_PER_SEC / 2 / 1000000))
- / (NS_PER_SEC / 1000000));
- } else {
- string.appendFormat("%llun", duration);
- }
- spaces -= string.length() - oldLength;
- }
- spaces += spaces_time;
- }
- }
-
log_id_for_each(i) {
if (!(logMask & (1 << i))) {
continue;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f6c4329..f892cd0 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -145,7 +145,6 @@
size_t mElements[LOG_ID_MAX];
bool mStatistics;
- bool dgramQlenStatistics;
static const unsigned short mBuckets[14];
log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
@@ -157,11 +156,7 @@
LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
- void enableDgramQlenStatistics() { dgramQlenStatistics = true; }
void enableStatistics() { mStatistics = true; }
- static unsigned short dgramQlen(unsigned short bucket);
- unsigned long long minimum(unsigned short bucket);
- void recordDiff(log_time diff, unsigned short bucket);
void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
diff --git a/logd/README.property b/logd/README.property
index b7fcece..60542b2 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -7,12 +7,6 @@
logd.statistics bool depends Enable logcat -S statistics.
ro.config.low_ram bool false if true, logd.statistics default false
ro.build.type string if user, logd.statistics default false
-logd.statistics.dgram_qlen bool false Record dgram_qlen statistics. This
- represents a performance impact and
- is used to determine the platform's
- minimum domain socket network FIFO
- size (see source for details) based
- on typical load (logcat -S to view)
persist.logd.size number 256K default size of the buffer for all
log ids at initial startup, at runtime
use: logcat -b all -G <value>
diff --git a/logd/main.cpp b/logd/main.cpp
index 7a1ae54..243bee4 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -155,9 +155,6 @@
LogBuffer *logBuf = new LogBuffer(times);
- if (property_get_bool("logd.statistics.dgram_qlen", false)) {
- logBuf->enableDgramQlenStatistics();
- }
{
char property[PROPERTY_VALUE_MAX];
property_get("ro.build.type", property, "");
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 96877a9..46bd9c0 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -192,164 +192,6 @@
EXPECT_TRUE(NULL != events_logs);
#endif
- // Parse timing stats
-
- cp = strstr(cp, "Minimum time between log events per dgram_qlen:");
-
- if (cp) {
- while (*cp && (*cp != '\n')) {
- ++cp;
- }
- if (*cp == '\n') {
- ++cp;
- }
-
- char *list_of_spans = cp;
- EXPECT_NE('\0', *list_of_spans);
-
- unsigned short number_of_buckets = 0;
- unsigned short *dgram_qlen = NULL;
- unsigned short bucket = 0;
- while (*cp && (*cp != '\n')) {
- bucket = 0;
- while (isdigit(*cp)) {
- bucket = bucket * 10 + *cp - '0';
- ++cp;
- }
- while (*cp == ' ') {
- ++cp;
- }
- if (!bucket) {
- break;
- }
- unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1];
- EXPECT_TRUE(new_dgram_qlen != NULL);
- if (dgram_qlen) {
- memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets);
- delete [] dgram_qlen;
- }
-
- dgram_qlen = new_dgram_qlen;
- dgram_qlen[number_of_buckets++] = bucket;
- }
-
- char *end_of_spans = cp;
- EXPECT_NE('\0', *end_of_spans);
-
- EXPECT_LT(5, number_of_buckets);
-
- unsigned long long *times = new unsigned long long [number_of_buckets];
- ASSERT_TRUE(times != NULL);
-
- memset(times, 0, sizeof(*times) * number_of_buckets);
-
- while (*cp == '\n') {
- ++cp;
- }
-
- unsigned short number_of_values = 0;
- unsigned long long value;
- while (*cp && (*cp != '\n')) {
- EXPECT_GE(number_of_buckets, number_of_values);
-
- value = 0;
- while (isdigit(*cp)) {
- value = value * 10ULL + *cp - '0';
- ++cp;
- }
-
- switch(*cp) {
- case ' ':
- case '\n':
- value *= 1000ULL;
- /* FALLTHRU */
- case 'm':
- value *= 1000ULL;
- /* FALLTHRU */
- case 'u':
- value *= 1000ULL;
- /* FALLTHRU */
- case 'n':
- default:
- break;
- }
- while (*++cp == ' ');
-
- if (!value) {
- break;
- }
-
- times[number_of_values] = value;
- ++number_of_values;
- }
-
-#ifdef TARGET_USES_LOGD
- EXPECT_EQ(number_of_values, number_of_buckets);
-#endif
-
- FILE *fp;
- ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r")));
-
- unsigned max_dgram_qlen = 0;
- fscanf(fp, "%u", &max_dgram_qlen);
-
- fclose(fp);
-
- // Find launch point
- unsigned short launch = 0;
- unsigned long long total = 0;
- do {
- total += times[launch];
- } while (((++launch < number_of_buckets)
- && ((total / launch) >= (times[launch] / 8ULL)))
- || (launch == 1)); // too soon
-
- bool failure = number_of_buckets <= launch;
- if (!failure) {
- unsigned short l = launch;
- if (l >= number_of_buckets) {
- l = number_of_buckets - 1;
- }
- failure = max_dgram_qlen < dgram_qlen[l];
- }
-
- // We can get failure if at any time liblog_benchmarks has been run
- // because designed to overload /proc/sys/net/unix/max_dgram_qlen even
- // at excessive values like 20000. It does so to measure the raw processing
- // performance of logd.
- if (failure) {
- cp = find_benchmark_spam(cp);
- }
-
- if (cp) {
- // Fake a failure, but without the failure code
- if (number_of_buckets <= launch) {
- printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n",
- number_of_buckets, launch);
- }
- if (launch >= number_of_buckets) {
- launch = number_of_buckets - 1;
- }
- if (max_dgram_qlen < dgram_qlen[launch]) {
- printf ("Expected: max_dgram_qlen >= dgram_qlen[%d],"
- " actual: %u vs %u\n",
- launch, max_dgram_qlen, dgram_qlen[launch]);
- }
- } else
-#ifndef TARGET_USES_LOGD
- if (total)
-#endif
- {
- EXPECT_GT(number_of_buckets, launch);
- if (launch >= number_of_buckets) {
- launch = number_of_buckets - 1;
- }
- EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]);
- }
-
- delete [] dgram_qlen;
- delete [] times;
- }
delete [] buf;
}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 05b83a2..d60dab4 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -71,7 +71,6 @@
umount \
uptime \
watchprops \
- wipe \
ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
diff --git a/toolbox/wipe.c b/toolbox/wipe.c
deleted file mode 100644
index 650a0d6..0000000
--- a/toolbox/wipe.c
+++ /dev/null
@@ -1,176 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <cutils/android_reboot.h>
-#include <sys/stat.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-
-/* Directories created by init defined in system/rootdir/init.rc */
-static char *INIT_DIRS[] = {
- "/system/etc/ppp",
- "/data/misc",
- "/data/local",
- "/data/local/tmp",
- "/data/data",
- "/data/app_private",
- "/data/app",
- NULL
-};
-
-static void wipe (const char *path);
-
-static int usage()
-{
- fprintf(stderr, "wipe <system|data|all>\n\n"
- "system means '/system'\n"
- "data means '/data'\n");
-
- return -1;
-}
-
-int wipe_main (int argc, char *argv[])
-{
- char *whatToWipe;
-
- if (argc != 2) return usage();
-
- whatToWipe = argv[1];
-
- if (0 == strcmp (whatToWipe, "system")) {
- fprintf(stdout, "Wiping /system\n");
- wipe ("/system");
- fprintf(stdout, "Done wiping /android\n");
- } else if (0 == strcmp (whatToWipe, "data")) {
- fprintf(stdout, "Wiping /data\n");
- wipe ("/data");
- fprintf(stdout, "Done wiping /data\n");
- } else if (0 == strcmp (whatToWipe, "all")) {
- fprintf(stdout, "Wiping /system and /data\n");
- wipe ("/system");
- wipe ("/data");
- fprintf(stdout, "Done wiping /system and /data\n");
- } else if (0 == strcmp(whatToWipe, "nuke")) {
- int ret;
- fprintf(stdout, "Nuking the device...\n");
- wipe ("/system");
- wipe ("/data");
- fprintf(stdout, "Device nuked! Rebooting...\n");
- ret = android_reboot(ANDROID_RB_RESTART, 0, 0);
- if (ret < 0) {
- fprintf(stderr, "Reboot failed, %s\n", strerror(errno));
- return 1;
- }
- } else {
- return usage();
- }
-
- return 0;
-}
-
-static char nameBuffer[PATH_MAX];
-static struct stat statBuffer;
-
-static void wipe (const char *path)
-{
- DIR *dir;
- struct dirent *de;
- int ret;
-
- dir = opendir(path);
-
- if (dir == NULL) {
- fprintf (stderr, "Error opendir'ing %s '%s'\n",
- path, strerror(errno));
- return;
- }
-
- char *filenameOffset;
-
- strcpy(nameBuffer, path);
- strcat(nameBuffer, "/");
-
- filenameOffset = nameBuffer + strlen(nameBuffer);
-
- for (;;) {
- de = readdir(dir);
-
- if (de == NULL) {
- break;
- }
-
- if (0 == strcmp(de->d_name, ".")
- || 0 == strcmp(de->d_name, "..")
- || 0 == strcmp(de->d_name, "lost+found")
- ) {
- continue;
- }
-
- strcpy(filenameOffset, de->d_name);
-
- ret = lstat (nameBuffer, &statBuffer);
-
- if (ret != 0) {
- fprintf(stderr, "stat() error on '%s' '%s'\n",
- nameBuffer, strerror(errno));
- }
-
- if(S_ISDIR(statBuffer.st_mode)) {
- int i;
- char *newpath;
-
-#if 0
- closedir(dir);
-#endif
-
- newpath = strdup(nameBuffer);
- wipe(newpath);
-
- /* Leave directories created by init, they have special permissions. */
- for (i = 0; INIT_DIRS[i]; i++) {
- if (strcmp(INIT_DIRS[i], newpath) == 0) {
- break;
- }
- }
- if (INIT_DIRS[i] == NULL) {
- ret = rmdir(newpath);
- if (ret != 0) {
- fprintf(stderr, "rmdir() error on '%s' '%s'\n",
- newpath, strerror(errno));
- }
- }
-
- free(newpath);
-
-#if 0
- dir = opendir(path);
- if (dir == NULL) {
- fprintf (stderr, "Error opendir'ing %s '%s'\n",
- path, strerror(errno));
- return;
- }
-#endif
-
- strcpy(nameBuffer, path);
- strcat(nameBuffer, "/");
-
- } else {
- ret = unlink(nameBuffer);
-
- if (ret != 0) {
- fprintf(stderr, "unlink() error on '%s' '%s'\n",
- nameBuffer, strerror(errno));
- }
- }
- }
-
- closedir(dir);
-
-}