Merge "Adding documentation on the sync part of the adb protocol previously missing."
diff --git a/adb/transport_local.c b/adb/transport_local.c
index d2dbca6..948cc15 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -48,7 +48,7 @@
* local transport it is connected. The list is used to detect when we're
* trying to connect twice to a given local transport.
*/
-#define ADB_LOCAL_TRANSPORT_MAX 16
+#define ADB_LOCAL_TRANSPORT_MAX 64
ADB_MUTEX_DEFINE( local_transports_lock );
diff --git a/charger/charger.c b/charger/charger.c
index 402d0e8..e3cadb1 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -973,7 +973,7 @@
charger->uevent_fd = fd;
coldboot(charger, "/sys/class/power_supply", "add");
- ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
+ ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < 0) {
LOGE("Cannot load battery_fail image\n");
charger->surf_unknown = NULL;
@@ -983,7 +983,7 @@
gr_surface* scale_frames;
int scale_count;
- ret = res_create_multi_surface("charger/battery_scale", &scale_count, &scale_frames);
+ ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
if (ret < 0) {
LOGE("Cannot load battery_scale image\n");
charger->batt_anim->num_frames = 0;
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
index 0f32dbf..6aa7400 100644
--- a/fastbootd/Android.mk
+++ b/fastbootd/Android.mk
@@ -45,19 +45,17 @@
LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter -DFLASH_CERT
LOCAL_LDFLAGS := -ldl
-LOCAL_SHARED_LIBRARIES := \
- libhardware \
- libcrypto \
- libhardware_legacy \
- libmdnssd
-
LOCAL_STATIC_LIBRARIES := \
- libsparse_static \
libc \
+ libcrypto_static \
libcutils \
+ libmdnssd \
+ libsparse_static \
libz
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_HAL_STATIC_LIBRARIES := libvendortrigger
+
+LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
@@ -84,21 +82,11 @@
include $(BUILD_EXECUTABLE)
+# vendor trigger HAL
include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include \
-
-LOCAL_STATIC_LIBRARIES := \
- $(EXTRA_STATIC_LIBS) \
- libcutils
-
-LOCAL_SRC_FILES := \
- other/vendor_trigger.c
-
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE := libvendortrigger.default
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
-
-
-include $(BUILD_SHARED_LIBRARY)
+LOCAL_SRC_FILES := vendor_trigger_default.c
+LOCAL_STATIC_LIBRARIES := libcutils
+include $(BUILD_STATIC_LIBRARY)
diff --git a/fastbootd/other/vendor_trigger.c b/fastbootd/other/vendor_trigger.c
deleted file mode 100644
index 101959b..0000000
--- a/fastbootd/other/vendor_trigger.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2009-2013, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-
-#include "vendor_trigger.h"
-#include "debug.h"
-
-unsigned int debug_level = DEBUG;
-
-static const int version = 1;
-
-int check_version(const int fastboot_version, int *libversion) {
- *libversion = version;
- return !(fastboot_version == version);
-}
-
-int gpt_layout(struct GPT_content *table) {
- D(DEBUG, "message from libvendor");
- return 0;
-}
-
-int oem_cmd(const char *arg, const char **response) {
- D(DEBUG, "message from libvendor, oem catched request %s", arg);
- return 0;
-}
-
-static int close_triggers(struct vendor_trigger_t *dev)
-{
- if (dev)
- free(dev);
-
- return 0;
-}
-
-static int open_triggers(const struct hw_module_t *module, char const *name,
- struct hw_device_t **device) {
- struct vendor_trigger_t *dev = malloc(sizeof(struct vendor_trigger_t));
- klog_init();
- klog_set_level(6);
-
- memset(dev, 0, sizeof(*dev));
- dev->common.module = (struct hw_module_t *) module;
- dev->common.close = (int (*)(struct hw_device_t *)) close_triggers;
-
- dev->gpt_layout = gpt_layout;
- dev->oem_cmd = oem_cmd;
-
- *device = (struct hw_device_t *) dev;
-
- return 0;
-}
-
-
-static struct hw_module_methods_t trigger_module_methods = {
- .open = open_triggers,
-};
-
-struct hw_module_t HAL_MODULE_INFO_SYM = {
- .tag = HARDWARE_MODULE_TAG,
- .version_major = 1,
- .version_minor = 0,
- .id = TRIGGER_MODULE_ID,
- .name = "vendor trigger library for fastbootd",
- .author = "Google, Inc.",
- .methods = &trigger_module_methods,
-};
-
diff --git a/fastbootd/trigger.c b/fastbootd/trigger.c
index e63e64d..df0f895 100644
--- a/fastbootd/trigger.c
+++ b/fastbootd/trigger.c
@@ -39,52 +39,19 @@
static const int version = 1;
-static struct vendor_trigger_t *triggers = NULL;
-
int load_trigger() {
- int err;
- hw_module_t* module;
- hw_device_t* device;
int libversion;
- err = hw_get_module(TRIGGER_MODULE_ID, (hw_module_t const**)&module);
-
- if (err == 0) {
- err = module->methods->open(module, NULL, &device);
-
- if (err == 0) {
- triggers = (struct vendor_trigger_t *) device;
- } else {
- D(WARN, "Libvendor load error");
- return 1;
- }
- }
- else {
- D(WARN, "Libvendor not load: %s", strerror(-err));
- return 0;
+ if (trigger_init() != 0) {
+ D(ERR, "libvendortrigger failed to initialize");
+ return 1;
}
- if (triggers->check_version != NULL &&
- triggers->check_version(version, &libversion)) {
-
- triggers = NULL;
+ if (trigger_check_version(version, &libversion)) {
D(ERR, "Library report incompability");
return 1;
}
+
D(INFO, "libvendortrigger loaded");
-
return 0;
}
-
-int trigger_oem_cmd(const char *arg, const char **response) {
- if (triggers != NULL && triggers->oem_cmd != NULL)
- return triggers->oem_cmd(arg, response);
- return 0;
-}
-
-int trigger_gpt_layout(struct GPT_content *table) {
- if (triggers != NULL && triggers->gpt_layout != NULL)
- return triggers->gpt_layout(table);
- return 0;
-}
-
diff --git a/fastbootd/trigger.h b/fastbootd/trigger.h
index 404acb4..d2d9573 100644
--- a/fastbootd/trigger.h
+++ b/fastbootd/trigger.h
@@ -37,9 +37,4 @@
int load_trigger();
-/* same as in struct triggers */
-
-int trigger_gpt_layout(struct GPT_content *table);
-int trigger_oem_cmd(const char *arg, const char **response);
-
#endif
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/vendor_trigger.h
similarity index 68%
rename from fastbootd/include/vendor_trigger.h
rename to fastbootd/vendor_trigger.h
index 51204fa..0c83be6 100644
--- a/fastbootd/include/vendor_trigger.h
+++ b/fastbootd/vendor_trigger.h
@@ -32,38 +32,37 @@
#ifndef __VENDOR_TRIGGER_H_
#define __VENDOR_TRIGGER_H_
-#define TRIGGER_MODULE_ID "fastbootd"
-#include <hardware/hardware.h>
-
__BEGIN_DECLS
struct GPT_entry_raw;
struct GPT_content;
/*
- * Structer with function pointers may become longer in the future
+ * Implemented in libvendortrigger to handle platform-specific behavior.
*/
-struct vendor_trigger_t {
- struct hw_device_t common;
+/*
+ * trigger_init() is called once at startup time before calling any other method
+ *
+ * returns 0 on success and nonzero on error
+ */
+int trigger_init(void);
- /*
- * This function runs at the beggining and shoud never be changed
- *
- * version is number parameter indicating version on the fastbootd side
- * libversion is version indicateing version of the library version
- *
- * returns 0 if it can cooperate with the current version and 1 in opposite
- */
- int (*check_version)(const int version, int *libversion);
+/*
+ * This function runs once after trigger_init completes.
+ *
+ * version is number parameter indicating version on the fastbootd side
+ * libversion is version indicateing version of the library version
+ *
+ * returns 0 if it can cooperate with the current version and 1 in opposite
+ */
+int trigger_check_version(const int version, int *libversion);
-
- /*
- * Return value -1 forbid the action from the vendor site and sets errno
- */
- int (* gpt_layout)(struct GPT_content *);
- int (* oem_cmd)(const char *arg, const char **response);
-};
+/*
+ * Return value -1 forbid the action from the vendor site and sets errno
+ */
+int trigger_gpt_layout(struct GPT_content *);
+int trigger_oem_cmd(const char *arg, const char **response);
__END_DECLS
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/vendor_trigger_default.c
similarity index 62%
copy from fastbootd/include/vendor_trigger.h
copy to fastbootd/vendor_trigger_default.c
index 51204fa..3627024 100644
--- a/fastbootd/include/vendor_trigger.h
+++ b/fastbootd/vendor_trigger_default.c
@@ -29,42 +29,30 @@
* SUCH DAMAGE.
*/
-#ifndef __VENDOR_TRIGGER_H_
-#define __VENDOR_TRIGGER_H_
+#include <stdlib.h>
+#include <cutils/klog.h>
+#include <vendor_trigger.h>
-#define TRIGGER_MODULE_ID "fastbootd"
-#include <hardware/hardware.h>
+static const int version = 1;
-__BEGIN_DECLS
+int trigger_init(void) {
+ klog_init();
+ klog_set_level(7);
+ return 0;
+}
-struct GPT_entry_raw;
-struct GPT_content;
+int trigger_check_version(const int fastboot_version, int *libversion) {
+ KLOG_DEBUG("fastbootd", "%s: %d (%d)", __func__, fastboot_version, version);
+ *libversion = version;
+ return !(fastboot_version == version);
+}
-/*
- * Structer with function pointers may become longer in the future
- */
+int trigger_gpt_layout(struct GPT_content *table) {
+ KLOG_DEBUG("fastbootd", "%s: %p", __func__, table);
+ return 0;
+}
-struct vendor_trigger_t {
- struct hw_device_t common;
-
- /*
- * This function runs at the beggining and shoud never be changed
- *
- * version is number parameter indicating version on the fastbootd side
- * libversion is version indicateing version of the library version
- *
- * returns 0 if it can cooperate with the current version and 1 in opposite
- */
- int (*check_version)(const int version, int *libversion);
-
-
- /*
- * Return value -1 forbid the action from the vendor site and sets errno
- */
- int (* gpt_layout)(struct GPT_content *);
- int (* oem_cmd)(const char *arg, const char **response);
-};
-
-__END_DECLS
-
-#endif
+int trigger_oem_cmd(const char *arg, const char **response) {
+ KLOG_DEBUG("fastbootd", "%s: %s", __func__, arg);
+ return 0;
+}
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 1c8f107..dbd5e25 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -17,13 +17,14 @@
#ifndef _LIBS_CUTILS_TRACE_H
#define _LIBS_CUTILS_TRACE_H
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/types.h>
-#include <stdint.h>
-#include <stdbool.h>
#include <unistd.h>
-#include <cutils/compiler.h>
+#include <cutils/compiler.h>
#ifdef ANDROID_SMP
#include <cutils/atomic-inline.h>
#else
@@ -217,8 +218,8 @@
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
- len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%d", getpid(),
- name, cookie);
+ len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%" PRId32,
+ getpid(), name, cookie);
write(atrace_marker_fd, buf, len);
}
}
@@ -235,8 +236,8 @@
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
- len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%d", getpid(),
- name, cookie);
+ len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%" PRId32,
+ getpid(), name, cookie);
write(atrace_marker_fd, buf, len);
}
}
@@ -253,7 +254,7 @@
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
- len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%d",
+ len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId32,
getpid(), name, value);
write(atrace_marker_fd, buf, len);
}
@@ -270,7 +271,7 @@
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
- len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%lld",
+ len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%" PRId64,
getpid(), name, value);
write(atrace_marker_fd, buf, len);
}
diff --git a/include/log/log_read.h b/include/log/log_read.h
index 7edfe3c..bd9de12 100644
--- a/include/log/log_read.h
+++ b/include/log/log_read.h
@@ -17,11 +17,17 @@
#ifndef _LIBS_LOG_LOG_READ_H
#define _LIBS_LOG_LOG_READ_H
+#include <stdint.h>
#include <time.h>
/* struct log_time is a wire-format variant of struct timespec */
#define NS_PER_SEC 1000000000ULL
+
#ifdef __cplusplus
+
+// NB: do NOT define a copy constructor. This will result in structure
+// no longer being compatible with pass-by-value which is desired
+// efficient behavior. Also, pass-by-reference breaks C/C++ ABI.
struct log_time {
public:
uint32_t tv_sec; // good to Feb 5 2106
@@ -32,16 +38,12 @@
tv_sec = T.tv_sec;
tv_nsec = T.tv_nsec;
}
- log_time(const log_time &T)
- {
- tv_sec = T.tv_sec;
- tv_nsec = T.tv_nsec;
- }
log_time(uint32_t sec, uint32_t nsec)
{
tv_sec = sec;
tv_nsec = nsec;
}
+ static const timespec EPOCH;
log_time()
{
}
@@ -86,6 +88,12 @@
{
return !(*this > T);
}
+ log_time operator-= (const timespec &T);
+ log_time operator- (const timespec &T) const
+ {
+ log_time local(*this);
+ return local -= T;
+ }
// log_time
bool operator== (const log_time &T) const
@@ -114,17 +122,31 @@
{
return !(*this > T);
}
+ log_time operator-= (const log_time &T);
+ log_time operator- (const log_time &T) const
+ {
+ log_time local(*this);
+ return local -= T;
+ }
uint64_t nsec() const
{
return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
}
+
+ static const char default_format[];
+
+ // Add %#q for the fraction of a second to the standard library functions
+ char *strptime(const char *s, const char *format = default_format);
} __attribute__((__packed__));
+
#else
+
typedef struct log_time {
uint32_t tv_sec;
uint32_t tv_nsec;
} __attribute__((__packed__)) log_time;
+
#endif
#endif /* define _LIBS_LOG_LOG_READ_H */
diff --git a/include/log/logger.h b/include/log/logger.h
index 8dab234..3c6ea30 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -12,6 +12,7 @@
#include <stdint.h>
#include <log/log.h>
+#include <log/log_read.h>
#ifdef __cplusplus
extern "C" {
@@ -161,6 +162,9 @@
struct logger_list *android_logger_list_alloc(int mode,
unsigned int tail,
pid_t pid);
+struct logger_list *android_logger_list_alloc_time(int mode,
+ log_time start,
+ pid_t pid);
void android_logger_list_free(struct logger_list *logger_list);
/* In the purest sense, the following two are orthogonal interfaces */
int android_logger_list_read(struct logger_list *logger_list,
diff --git a/init/property_service.c b/init/property_service.c
index ac63377e..fe7cbb5 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -439,40 +439,73 @@
*sz = pa_workspace.size;
}
-static void load_properties(char *data, char *prefix)
-{
- char *key, *value, *eol, *sol, *tmp;
- size_t plen;
+static void load_properties_from_file(const char *, const char *);
- if (prefix)
- plen = strlen(prefix);
+/*
+ * Filter is used to decide which properties to load: NULL loads all keys,
+ * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
+ */
+static void load_properties(char *data, const char *filter)
+{
+ char *key, *value, *eol, *sol, *tmp, *fn;
+ size_t flen = 0;
+
+ if (filter) {
+ flen = strlen(filter);
+ }
+
sol = data;
- while((eol = strchr(sol, '\n'))) {
+ while ((eol = strchr(sol, '\n'))) {
key = sol;
*eol++ = 0;
sol = eol;
- value = strchr(key, '=');
- if(value == 0) continue;
- *value++ = 0;
+ while (isspace(*key)) key++;
+ if (*key == '#') continue;
- while(isspace(*key)) key++;
- if(*key == '#') continue;
- tmp = value - 2;
- while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
-
- if (prefix && strncmp(key, prefix, plen))
- continue;
-
- while(isspace(*value)) value++;
tmp = eol - 2;
- while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
+ while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
- property_set(key, value);
+ if (!strncmp(key, "import ", 7) && flen == 0) {
+ fn = key + 7;
+ while (isspace(*fn)) fn++;
+
+ key = strchr(fn, ' ');
+ if (key) {
+ *key++ = 0;
+ while (isspace(*key)) key++;
+ }
+
+ load_properties_from_file(fn, key);
+
+ } else {
+ value = strchr(key, '=');
+ if (!value) continue;
+ *value++ = 0;
+
+ tmp = value - 2;
+ while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;
+
+ while (isspace(*value)) value++;
+
+ if (flen > 0) {
+ if (filter[flen - 1] == '*') {
+ if (strncmp(key, filter, flen - 1)) continue;
+ } else {
+ if (strcmp(key, filter)) continue;
+ }
+ }
+
+ property_set(key, value);
+ }
}
}
-static void load_properties_from_file(const char *fn, char *prefix)
+/*
+ * Filter is used to decide which properties to load: NULL loads all keys,
+ * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
+ */
+static void load_properties_from_file(const char *fn, const char *filter)
{
char *data;
unsigned sz;
@@ -480,7 +513,7 @@
data = read_file(fn, &sz);
if(data != 0) {
- load_properties(data, prefix);
+ load_properties(data, filter);
free(data);
}
}
@@ -592,8 +625,10 @@
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
- load_properties_from_file(PROP_PATH_FACTORY, "ro.");
+ load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
+
load_override_properties();
+
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
diff --git a/init/ueventd.c b/init/ueventd.c
index 5517448..662196d 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -71,8 +71,8 @@
klog_init();
#if LOG_UEVENTS
/* Ensure we're at a logging level that will show the events */
- if (klog_get_level() < KLOG_LEVEL_INFO) {
- klog_set_level(KLOG_LEVEL_INFO);
+ if (klog_get_level() < KLOG_INFO_LEVEL) {
+ klog_set_level(KLOG_INFO_LEVEL);
}
#endif
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 4fe20db..a23de2d 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -50,10 +50,11 @@
endif
liblog_host_sources := $(liblog_sources) fake_log_device.c
+liblog_target_sources := $(liblog_sources) log_time.cpp
ifneq ($(TARGET_USES_LOGD),false)
-liblog_target_sources = $(liblog_sources) log_read.c
+liblog_target_sources += log_read.c
else
-liblog_target_sources = $(liblog_sources) log_read_kern.c
+liblog_target_sources += log_read_kern.c
endif
# Shared and static library for host
@@ -61,12 +62,18 @@
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_host_sources)
LOCAL_LDLIBS := -lpthread
+ifeq ($(strip $(HOST_OS)),linux)
+LOCAL_LDLIBS += -lrt
+endif
LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_WHOLE_STATIC_LIBRARIES := liblog
+ifeq ($(strip $(HOST_OS)),linux)
+LOCAL_LDLIBS := -lrt
+endif
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -76,6 +83,9 @@
LOCAL_MODULE := lib64log
LOCAL_SRC_FILES := $(liblog_host_sources)
LOCAL_LDLIBS := -lpthread
+ifeq ($(strip $(HOST_OS)),linux)
+LOCAL_LDLIBS += -lrt
+endif
LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64
include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/liblog/log_read.c b/liblog/log_read.c
index e4acac2..2dd07e6 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <signal.h>
#include <stddef.h>
#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
@@ -234,6 +235,7 @@
struct listnode node;
int mode;
unsigned int tail;
+ log_time start;
pid_t pid;
int sock;
};
@@ -270,11 +272,11 @@
const char *msg, char *buf, size_t buf_size)
{
ssize_t ret;
+ int errno_save = 0;
int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
if (sock < 0) {
- ret = sock;
- goto done;
+ return sock;
}
if (msg) {
@@ -290,9 +292,12 @@
done:
if ((ret == -1) && errno) {
- ret = -errno;
+ errno_save = errno;
}
close(sock);
+ if (errno_save) {
+ errno = errno_save;
+ }
return ret;
}
@@ -303,6 +308,7 @@
}
if (strncmp(buf, "success", 7)) {
+ errno = EINVAL;
return -1;
}
@@ -441,6 +447,8 @@
list_init(&logger_list->node);
logger_list->mode = mode;
+ logger_list->start.tv_sec = 0;
+ logger_list->start.tv_nsec = 0;
logger_list->tail = tail;
logger_list->pid = pid;
logger_list->sock = -1;
@@ -448,6 +456,27 @@
return logger_list;
}
+struct logger_list *android_logger_list_alloc_time(int mode,
+ log_time start,
+ pid_t pid)
+{
+ struct logger_list *logger_list;
+
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
+
+ list_init(&logger_list->node);
+ logger_list->mode = mode;
+ logger_list->start = start;
+ logger_list->tail = 0;
+ logger_list->pid = pid;
+ logger_list->sock = -1;
+
+ return logger_list;
+}
+
/* android_logger_list_register unimplemented, no use case */
/* android_logger_list_unregister unimplemented, no use case */
@@ -564,6 +593,15 @@
cp += ret;
}
+ if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
+ ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32,
+ logger_list->start.tv_sec,
+ logger_list->start.tv_nsec);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+
if (logger_list->pid) {
ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
ret = min(ret, remaining);
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index 483b6b6..9cccb1d 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -308,6 +308,13 @@
return logger_list;
}
+struct logger_list *android_logger_list_alloc_time(int mode,
+ log_time start UNUSED,
+ pid_t pid)
+{
+ return android_logger_list_alloc(mode, 0, pid);
+}
+
/* android_logger_list_register unimplemented, no use case */
/* android_logger_list_unregister unimplemented, no use case */
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
new file mode 100644
index 0000000..755c2d9
--- /dev/null
+++ b/liblog/log_time.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/cdefs.h>
+
+#include <log/log_read.h>
+
+const char log_time::default_format[] = "%m-%d %H:%M:%S.%3q";
+const timespec log_time::EPOCH = { 0, 0 };
+
+// Add %#q for fractional seconds to standard strptime function
+
+char *log_time::strptime(const char *s, const char *format) {
+ time_t now;
+#ifdef __linux__
+ *this = log_time(CLOCK_REALTIME);
+ now = tv_sec;
+#else
+ time(&now);
+ tv_sec = now;
+ tv_nsec = 0;
+#endif
+
+ struct tm *ptm;
+#if (defined(HAVE_LOCALTIME_R))
+ struct tm tmBuf;
+ ptm = localtime_r(&now, &tmBuf);
+#else
+ ptm = localtime(&now);
+#endif
+
+ char fmt[strlen(format) + 1];
+ strcpy(fmt, format);
+
+ char *ret = const_cast<char *> (s);
+ char *cp;
+ for (char *f = cp = fmt; ; ++cp) {
+ if (!*cp) {
+ if (f != cp) {
+ ret = ::strptime(ret, f, ptm);
+ }
+ break;
+ }
+ if (*cp != '%') {
+ continue;
+ }
+ char *e = cp;
+ ++e;
+#if (defined(__BIONIC__))
+ if (*e == 's') {
+ *cp = '\0';
+ if (*f) {
+ ret = ::strptime(ret, f, ptm);
+ if (!ret) {
+ break;
+ }
+ }
+ tv_sec = 0;
+ while (isdigit(*ret)) {
+ tv_sec = tv_sec * 10 + *ret - '0';
+ ++ret;
+ }
+ now = tv_sec;
+#if (defined(HAVE_LOCALTIME_R))
+ ptm = localtime_r(&now, &tmBuf);
+#else
+ ptm = localtime(&now);
+#endif
+ } else
+#endif
+ {
+ unsigned num = 0;
+ while (isdigit(*e)) {
+ num = num * 10 + *e - '0';
+ ++e;
+ }
+ if (*e != 'q') {
+ continue;
+ }
+ *cp = '\0';
+ if (*f) {
+ ret = ::strptime(ret, f, ptm);
+ if (!ret) {
+ break;
+ }
+ }
+ unsigned long mul = NS_PER_SEC;
+ if (num == 0) {
+ num = INT_MAX;
+ }
+ tv_nsec = 0;
+ while (isdigit(*ret) && num && (mul > 1)) {
+ --num;
+ mul /= 10;
+ tv_nsec = tv_nsec + (*ret - '0') * mul;
+ ++ret;
+ }
+ }
+ f = cp = e;
+ ++f;
+ }
+
+ if (ret) {
+ tv_sec = mktime(ptm);
+ return ret;
+ }
+
+ // Upon error, place a known value into the class, the current time.
+#ifdef __linux__
+ *this = log_time(CLOCK_REALTIME);
+#else
+ time(&now);
+ tv_sec = now;
+ tv_nsec = 0;
+#endif
+ return ret;
+}
+
+log_time log_time::operator-= (const timespec &T) {
+ // No concept of negative time, clamp to EPOCH
+ if (*this <= T) {
+ return *this = EPOCH;
+ }
+
+ if (this->tv_nsec < (unsigned long int)T.tv_nsec) {
+ --this->tv_sec;
+ this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
+ } else {
+ this->tv_nsec -= T.tv_nsec;
+ }
+ this->tv_sec -= T.tv_sec;
+
+ return *this;
+}
+
+log_time log_time::operator-= (const log_time &T) {
+ // No concept of negative time, clamp to EPOCH
+ if (*this <= T) {
+ return *this = EPOCH;
+ }
+
+ if (this->tv_nsec < T.tv_nsec) {
+ --this->tv_sec;
+ this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
+ } else {
+ this->tv_nsec -= T.tv_nsec;
+ }
+ this->tv_sec -= T.tv_sec;
+
+ return *this;
+}
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 01f9249..aebddc8 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -17,22 +17,23 @@
/*
* Read-only access to Zip archives, with minimal heap allocation.
*/
-#include "ziparchive/zip_archive.h"
-
-#include <zlib.h>
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
#include <limits.h>
#include <log/log.h>
-#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utils/FileMap.h>
+#include <zlib.h>
#include <JNIHelp.h> // TEMP_FAILURE_RETRY may or may not be in unistd
+#include "ziparchive/zip_archive.h"
+
// This is for windows. If we don't open a file in binary mode, weirds
// things will happen.
#ifndef O_BINARY
@@ -217,8 +218,7 @@
ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
if (actual != get_size) {
- ALOGW("CopyFileToFile: copy read failed (%d vs %zd)",
- (int) actual, get_size);
+ ALOGW("CopyFileToFile: copy read failed (%zd vs %zd)", actual, get_size);
return kIoError;
}
@@ -337,12 +337,12 @@
const off64_t search_start = file_length - read_amount;
if (lseek64(fd, search_start, SEEK_SET) != search_start) {
- ALOGW("Zip: seek %lld failed: %s", search_start, strerror(errno));
+ ALOGW("Zip: seek %" PRId64 " failed: %s", search_start, strerror(errno));
return kIoError;
}
ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scan_buffer, read_amount));
if (actual != (ssize_t) read_amount) {
- ALOGW("Zip: read %zd failed: %s", read_amount, strerror(errno));
+ ALOGW("Zip: read %u failed: %s", read_amount, strerror(errno));
return kIoError;
}
@@ -379,7 +379,7 @@
const off64_t dir_offset = get4LE(eocd_ptr + kEOCDFileOffset);
if (dir_offset + dir_size > eocd_offset) {
- ALOGW("Zip: bad offsets (dir %lld, size %lld, eocd %lld)",
+ ALOGW("Zip: bad offsets (dir %" PRId64 ", size %" PRId64 ", eocd %" PRId64 ")",
dir_offset, dir_size, eocd_offset);
return kInvalidOffset;
}
@@ -388,8 +388,8 @@
return kEmptyArchive;
}
- ALOGV("+++ num_entries=%d dir_size=%d dir_offset=%d", num_entries, dir_size,
- dir_offset);
+ ALOGV("+++ num_entries=%d dir_size=%" PRId64 " dir_offset=%" PRId64,
+ num_entries, dir_size, dir_offset);
/*
* It all looks good. Create a mapping for the CD, and set the fields
@@ -430,12 +430,12 @@
}
if (file_length > (off64_t) 0xffffffff) {
- ALOGV("Zip: zip file too long %d", file_length);
+ ALOGV("Zip: zip file too long %" PRId64, file_length);
return kInvalidFile;
}
if (file_length < (int64_t) kEOCDLen) {
- ALOGV("Zip: length %ld is too small to be zip", file_length);
+ ALOGV("Zip: length %" PRId64 " is too small to be zip", file_length);
return kInvalidFile;
}
@@ -503,7 +503,7 @@
const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
if (local_header_offset >= archive->directory_offset) {
- ALOGW("Zip: bad LFH offset %lld at entry %d", local_header_offset, i);
+ ALOGW("Zip: bad LFH offset %" PRId64 " at entry %d", local_header_offset, i);
goto bail;
}
@@ -522,8 +522,8 @@
ptr += kCDELen + file_name_length + extra_length + comment_length;
if ((size_t)(ptr - cd_ptr) > cd_length) {
- ALOGW("Zip: bad CD advance (%d vs %zd) at entry %d",
- (int) (ptr - cd_ptr), cd_length, i);
+ ALOGW("Zip: bad CD advance (%zu vs %zu) at entry %d",
+ (size_t) (ptr - cd_ptr), cd_length, i);
goto bail;
}
}
@@ -630,7 +630,7 @@
// is Windows. Only recent versions of windows support unix like forks,
// and even there the semantics are quite different.
if (lseek64(fd, off, SEEK_SET) != off) {
- ALOGW("Zip: failed seek to offset %lld", off);
+ ALOGW("Zip: failed seek to offset %" PRId64, off);
return kIoError;
}
@@ -686,12 +686,12 @@
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 %lld", local_header_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64, local_header_offset);
return kIoError;
}
if (get4LE(lfh_buf) != kLFHSignature) {
- ALOGW("Zip: didn't find signature at start of lfh, offset=%lld",
+ ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
local_header_offset);
return kInvalidOffset;
}
@@ -733,7 +733,7 @@
name_offset);
if (actual != nameLen) {
- ALOGW("Zip: failed reading lfh name from offset %lld", name_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64, name_offset);
free(name_buf);
return kIoError;
}
@@ -751,19 +751,19 @@
const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen;
if (data_offset > cd_offset) {
- ALOGW("Zip: bad data offset %lld in zip", (off64_t) data_offset);
+ ALOGW("Zip: bad data offset %" PRId64 " in zip", data_offset);
return kInvalidOffset;
}
if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
- ALOGW("Zip: bad compressed length in zip (%lld + %zd > %lld)",
+ ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %zd > %" PRId64 ")",
data_offset, data->compressed_length, cd_offset);
return kInvalidOffset;
}
if (data->method == kCompressStored &&
(off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
- ALOGW("Zip: bad uncompressed length in zip (%lld + %zd > %lld)",
+ ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %d > %" PRId64 ")",
data_offset, data->uncompressed_length, cd_offset);
return kInvalidOffset;
}
@@ -903,7 +903,7 @@
const ssize_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
if (actual != getSize) {
- ALOGW("Zip: inflate read failed (%d vs %zd)", actual, getSize);
+ ALOGW("Zip: inflate read failed (%zd vs %zd)", actual, getSize);
result = kIoError;
goto z_bail;
}
@@ -946,7 +946,7 @@
*crc_out = zstream.adler;
if (zstream.total_out != uncompressed_length || compressed_length != 0) {
- ALOGW("Zip: size mismatch on inflated file (%ld vs %zd)",
+ ALOGW("Zip: size mismatch on inflated file (%ld vs %u)",
zstream.total_out, uncompressed_length);
result = kInconsistentInformation;
goto z_bail;
@@ -967,7 +967,7 @@
off64_t data_offset = entry->offset;
if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
- ALOGW("Zip: lseek to data at %lld failed", (off64_t) data_offset);
+ ALOGW("Zip: lseek to data at %" PRId64 " failed", data_offset);
return kIoError;
}
@@ -990,7 +990,7 @@
// TODO: Fix this check by passing the right flags to inflate2 so that
// it calculates the CRC for us.
if (entry->crc32 != crc && false) {
- ALOGW("Zip: crc mismatch: expected %u, was %llu", entry->crc32, crc);
+ ALOGW("Zip: crc mismatch: expected %u, was %" PRIu64, entry->crc32, crc);
return kInconsistentInformation;
}
@@ -1010,8 +1010,8 @@
int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
if (result == -1) {
- ALOGW("Zip: unable to truncate file to %lld: %s", declared_length + current_offset,
- strerror(errno));
+ ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+ declared_length + current_offset, strerror(errno));
return kIoError;
}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 00b5ba9..5960609 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -17,6 +17,7 @@
#include <cutils/sockets.h>
#include <log/log.h>
+#include <log/log_read.h>
#include <log/logger.h>
#include <log/logd.h>
#include <log/logprint.h>
@@ -302,7 +303,8 @@
log_device_t* dev;
bool needBinary = false;
struct logger_list *logger_list;
- int tail_lines = 0;
+ unsigned int tail_lines = 0;
+ log_time tail_time(log_time::EPOCH);
signal(SIGPIPE, exit);
@@ -352,7 +354,32 @@
mode = O_RDONLY | O_NDELAY;
/* FALLTHRU */
case 'T':
- tail_lines = atoi(optarg);
+ if (strspn(optarg, "0123456789") != strlen(optarg)) {
+ char *cp = tail_time.strptime(optarg,
+ log_time::default_format);
+ if (!cp) {
+ fprintf(stderr,
+ "ERROR: -%c \"%s\" not in \"%s\" time format\n",
+ ret, optarg, log_time::default_format);
+ exit(1);
+ }
+ if (*cp) {
+ char c = *cp;
+ *cp = '\0';
+ fprintf(stderr,
+ "WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
+ ret, optarg, c, cp + 1);
+ *cp = c;
+ }
+ } else {
+ tail_lines = atoi(optarg);
+ if (!tail_lines) {
+ fprintf(stderr,
+ "WARNING: -%c %s invalid, setting to 1\n",
+ ret, optarg);
+ tail_lines = 1;
+ }
+ }
break;
case 'g':
@@ -654,7 +681,11 @@
}
dev = devices;
- logger_list = android_logger_list_alloc(mode, tail_lines, 0);
+ if (tail_time != log_time::EPOCH) {
+ logger_list = android_logger_list_alloc_time(mode, tail_time, 0);
+ } else {
+ logger_list = android_logger_list_alloc(mode, tail_lines, 0);
+ }
while (dev) {
dev->logger_list = logger_list;
dev->logger = android_logger_open(logger_list,
@@ -668,7 +699,7 @@
int ret;
ret = android_logger_clear(dev->logger);
if (ret) {
- perror("clearLog");
+ perror("failed to clear the log");
exit(EXIT_FAILURE);
}
}
@@ -676,7 +707,7 @@
#ifdef USERDEBUG_BUILD
if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
- perror("setLogSize");
+ perror("failed to set the log size");
exit(EXIT_FAILURE);
}
@@ -687,13 +718,13 @@
size = android_logger_get_log_size(dev->logger);
if (size < 0) {
- perror("getLogSize");
+ perror("failed to get the log size");
exit(EXIT_FAILURE);
}
readable = android_logger_get_log_readable_size(dev->logger);
if (readable < 0) {
- perror("getLogReadableSize");
+ perror("failed to get the readable log size");
exit(EXIT_FAILURE);
}
@@ -717,7 +748,7 @@
free(buf);
if (ret) {
- perror("setPruneList");
+ perror("failed to set the prune list");
exit(EXIT_FAILURE);
}
}
@@ -761,7 +792,7 @@
}
if (!buf) {
- perror("response read");
+ perror("failed to read data");
exit(EXIT_FAILURE);
}
@@ -828,7 +859,7 @@
fprintf(stderr, "read: unexpected length.\n");
exit(EXIT_FAILURE);
}
- perror("logcat read");
+ perror("logcat read failure");
exit(EXIT_FAILURE);
}
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index bdaec14..733af31 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -28,7 +28,11 @@
-g \
-Wall -Wextra \
-Werror \
- -fno-builtin \
+ -fno-builtin
+
+ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
+test_c_flags += -DUSERDEBUG_BUILD=1
+endif
test_src_files := \
logcat_test.cpp \
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index fc696bb..818a978 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -527,3 +527,100 @@
ASSERT_EQ(1, signals);
}
+
+#ifdef USERDEBUG_BUILD
+static bool get_white_black(char **list) {
+ FILE *fp;
+
+ fp = popen("logcat -p 2>/dev/null", "r");
+ if (fp == NULL) {
+ fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
+ return false;
+ }
+
+ char buffer[5120];
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ char *hold = *list;
+ char *buf = buffer;
+ while (isspace(*buf)) {
+ ++buf;
+ }
+ char *end = buf + strlen(buf);
+ while (isspace(*--end) && (end >= buf)) {
+ *end = '\0';
+ }
+ if (end < buf) {
+ continue;
+ }
+ if (hold) {
+ asprintf(list, "%s %s", hold, buf);
+ free(hold);
+ } else {
+ asprintf(list, "%s", buf);
+ }
+ }
+ pclose(fp);
+ return *list != NULL;
+}
+
+static bool set_white_black(const char *list) {
+ FILE *fp;
+
+ char buffer[5120];
+
+ snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list);
+ fp = popen(buffer, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "ERROR: %s\n", buffer);
+ return false;
+ }
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ char *buf = buffer;
+ while (isspace(*buf)) {
+ ++buf;
+ }
+ char *end = buf + strlen(buf);
+ while (isspace(*--end) && (end >= buf)) {
+ *end = '\0';
+ }
+ if (end < buf) {
+ continue;
+ }
+ fprintf(stderr, "%s\n", buf);
+ pclose(fp);
+ return false;
+ }
+ return pclose(fp) == 0;
+}
+
+TEST(logcat, white_black_adjust) {
+ char *list = NULL;
+ char *adjust = NULL;
+
+ ASSERT_EQ(true, get_white_black(&list));
+
+ static const char adjustment[] = "~! ~1000";
+ ASSERT_EQ(true, set_white_black(adjustment));
+ ASSERT_EQ(true, get_white_black(&adjust));
+ if (strcmp(adjustment, adjust)) {
+ fprintf(stderr, "ERROR: '%s' != '%s'\n", adjustment, adjust);
+ }
+ ASSERT_STREQ(adjustment, adjust);
+ free(adjust);
+ adjust = NULL;
+
+ ASSERT_EQ(true, set_white_black(list));
+ ASSERT_EQ(true, get_white_black(&adjust));
+ if (strcmp(list, adjust)) {
+ fprintf(stderr, "ERROR: '%s' != '%s'\n", list, adjust);
+ }
+ ASSERT_STREQ(list, adjust);
+ free(adjust);
+ adjust = NULL;
+
+ free(list);
+ list = NULL;
+}
+#endif // USERDEBUG_BUILD
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 0b8c31b..3be07c0 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -26,12 +26,14 @@
bool nonBlock,
unsigned long tail,
unsigned int logMask,
- pid_t pid)
+ pid_t pid,
+ log_time start)
: mReader(reader)
, mNonBlock(nonBlock)
, mTail(tail)
, mLogMask(logMask)
, mPid(pid)
+ , mStart(start)
{ }
// runSocketCommand is called once for every open client on the
@@ -69,7 +71,7 @@
LogTimeEntry::unlock();
return;
}
- entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid);
+ entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);
times.push_back(entry);
}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 715daac..f34c06a 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -16,8 +16,13 @@
#ifndef _FLUSH_COMMAND_H
#define _FLUSH_COMMAND_H
+#include <log/log_read.h>
#include <sysutils/SocketClientCommand.h>
+class LogBufferElement;
+
+#include "LogTimes.h"
+
class LogReader;
class FlushCommand : public SocketClientCommand {
@@ -26,13 +31,15 @@
unsigned long mTail;
unsigned int mLogMask;
pid_t mPid;
+ log_time mStart;
public:
FlushCommand(LogReader &mReader,
bool nonBlock = false,
unsigned long tail = -1,
unsigned int logMask = -1,
- pid_t pid = 0);
+ pid_t pid = 0,
+ log_time start = LogTimeEntry::EPOCH);
virtual void runSocketCommand(SocketClient *client);
static bool hasReadLogs(SocketClient *client);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 01cc9de..8d45f34 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -24,7 +24,7 @@
#include "LogBufferElement.h"
#include "LogReader.h"
-const log_time LogBufferElement::FLUSH_ERROR(0, 0);
+const log_time LogBufferElement::FLUSH_ERROR((uint32_t)0, (uint32_t)0);
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, const char *msg,
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index c6b248b..2aa2ebb 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -31,7 +31,8 @@
{ }
bool LogListener::onDataAvailable(SocketClient *cli) {
- char buffer[1024];
+ char buffer[sizeof_log_id_t + sizeof(log_time) + sizeof(char)
+ + LOGGER_ENTRY_MAX_PAYLOAD];
struct iovec iov = { buffer, sizeof(buffer) };
memset(buffer, 0, sizeof(buffer));
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 5b540bf..60a3507 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <ctype.h>
#include <poll.h>
#include <sys/socket.h>
#include <cutils/sockets.h>
@@ -50,6 +51,14 @@
tail = atol(cp + sizeof(_tail) - 1);
}
+ log_time start(log_time::EPOCH);
+ static const char _start[] = " start=";
+ cp = strstr(buffer, _start);
+ if (cp) {
+ // Parse errors will result in current time
+ start.strptime(cp + sizeof(_start) - 1, "%s.%q");
+ }
+
unsigned int logMask = -1;
static const char _logIds[] = " lids=";
cp = strstr(buffer, _logIds);
@@ -58,9 +67,8 @@
cp += sizeof(_logIds) - 1;
while (*cp && *cp != '\0') {
int val = 0;
- while (('0' <= *cp) && (*cp <= '9')) {
- val *= 10;
- val += *cp - '0';
+ while (isdigit(*cp)) {
+ val = val * 10 + *cp - '0';
++cp;
}
logMask |= 1 << val;
@@ -83,7 +91,63 @@
nonBlock = true;
}
- FlushCommand command(*this, nonBlock, tail, logMask, pid);
+ // Convert realtime to monotonic time
+ if (start == log_time::EPOCH) {
+ start = LogTimeEntry::EPOCH;
+ } else {
+ class LogFindStart {
+ const pid_t mPid;
+ const unsigned mLogMask;
+ bool startTimeSet;
+ log_time &start;
+ log_time last;
+
+ public:
+ LogFindStart(unsigned logMask, pid_t pid, log_time &start)
+ : mPid(pid)
+ , mLogMask(logMask)
+ , startTimeSet(false)
+ , start(start)
+ , last(LogTimeEntry::EPOCH)
+ { }
+
+ static bool callback(const LogBufferElement *element, void *obj) {
+ LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
+ if (!me->startTimeSet
+ && (!me->mPid || (me->mPid == element->getPid()))
+ && (me->mLogMask & (1 << element->getLogId()))) {
+ if (me->start == element->getRealTime()) {
+ me->start = element->getMonotonicTime();
+ me->startTimeSet = true;
+ } else {
+ if (me->start < element->getRealTime()) {
+ me->start = me->last;
+ me->startTimeSet = true;
+ }
+ me->last = element->getMonotonicTime();
+ }
+ }
+ return false;
+ }
+
+ bool found() { return startTimeSet; }
+ } logFindStart(logMask, pid, start);
+
+ logbuf().flushTo(cli, LogTimeEntry::EPOCH,
+ FlushCommand::hasReadLogs(cli),
+ logFindStart.callback, &logFindStart);
+
+ if (!logFindStart.found()) {
+ if (nonBlock) {
+ doSocketDelete(cli);
+ return false;
+ }
+ log_time now(CLOCK_MONOTONIC);
+ start = now;
+ }
+ }
+
+ FlushCommand command(*this, nonBlock, tail, logMask, pid, start);
command.runSocketCommand(cli);
return true;
}
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 67cc65e..8cb015c 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -25,7 +25,8 @@
LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
bool nonBlock, unsigned long tail,
- unsigned int logMask, pid_t pid)
+ unsigned int logMask, pid_t pid,
+ log_time start)
: mRefCount(1)
, mRelease(false)
, mError(false)
@@ -39,7 +40,7 @@
, mTail(tail)
, mIndex(0)
, mClient(client)
- , mStart(EPOCH)
+ , mStart(start)
, mNonBlock(nonBlock)
, mEnd(CLOCK_MONOTONIC)
{ }
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index cb6f566..beaf646 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -45,7 +45,8 @@
public:
LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
- unsigned long tail, unsigned int logMask, pid_t pid);
+ unsigned long tail, unsigned int logMask, pid_t pid,
+ log_time start);
SocketClient *mClient;
static const struct timespec EPOCH;
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 3cc5bb2..06910ee 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -137,7 +137,7 @@
/* blocks are 512 bytes, we want output to be KB */
if ((flags & LIST_SIZE) != 0) {
- printf("%lld ", s->st_blocks / 2);
+ printf("%lld ", (long long)s->st_blocks / 2);
}
if ((flags & LIST_CLASSIFY) != 0) {
@@ -205,7 +205,7 @@
break;
case S_IFREG:
printf("%s %-8s %-8s %8lld %s %s\n",
- mode, user, group, s->st_size, date, name);
+ mode, user, group, (long long)s->st_size, date, name);
break;
case S_IFLNK: {
char linkto[256];
@@ -321,7 +321,7 @@
}
if(flags & LIST_INODE) {
- printf("%8llu ", s.st_ino);
+ printf("%8llu ", (unsigned long long)s.st_ino);
}
if ((flags & LIST_MACLABEL) != 0) {