Merge "crasher: add option to wait for input before crashing."
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index d570255..b1511fe 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -241,7 +241,7 @@
return ret;
}
-static int fs_match(char *in1, char *in2)
+static int fs_match(const char *in1, const char *in2)
{
char *n1;
char *n2;
@@ -651,7 +651,7 @@
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
* in turn, and stop on 1st success, or no more match.
*/
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point)
{
int i = 0;
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 33a7496..4bfe202 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -14,12 +14,17 @@
* limitations under the License.
*/
+#define _GNU_SOURCE
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#include <libgen.h>
#include "fs_mgr_priv.h"
+#ifdef _LIBGEN_H
+#warning "libgen.h must not be included"
+#endif
+
char *me = "";
static void usage(void)
@@ -32,10 +37,10 @@
* and exit the program, do not return to the caller.
* Return the number of argv[] entries consumed.
*/
-static void parse_options(int argc, char *argv[], int *a_flag, int *u_flag, int *n_flag,
- char **n_name, char **n_blk_dev)
+static void parse_options(int argc, char * const argv[], int *a_flag, int *u_flag, int *n_flag,
+ const char **n_name, const char **n_blk_dev)
{
- me = basename(strdup(argv[0]));
+ me = basename(argv[0]);
if (argc <= 1) {
usage();
@@ -75,14 +80,14 @@
return;
}
-int main(int argc, char *argv[])
+int main(int argc, char * const argv[])
{
int a_flag=0;
int u_flag=0;
int n_flag=0;
- char *n_name=NULL;
- char *n_blk_dev=NULL;
- char *fstab_file=NULL;
+ const char *n_name=NULL;
+ const char *n_blk_dev=NULL;
+ const char *fstab_file=NULL;
struct fstab *fstab=NULL;
klog_set_level(6);
@@ -97,7 +102,7 @@
if (a_flag) {
return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
} else if (n_flag) {
- return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
+ return fs_mgr_do_mount(fstab, n_name, (char *)n_blk_dev, 0);
} else if (u_flag) {
return fs_mgr_unmount_all(fstab);
} else {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c0116ef..b120f7c 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -95,7 +95,7 @@
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
-int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);
int fs_mgr_unmount_all(struct fstab *fstab);
diff --git a/include/log/event_tag_map.h b/include/log/event_tag_map.h
index 69774ba..22e62ec 100644
--- a/include/log/event_tag_map.h
+++ b/include/log/event_tag_map.h
@@ -48,7 +48,15 @@
* Look up a tag by index. Returns the tag string & string length, or NULL if
* not found. Returned string is not guaranteed to be nul terminated.
*/
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag);
+const char* android_lookupEventTag_len(const EventTagMap* map,
+ size_t* len, unsigned int tag);
+
+/*
+ * Look up a format by index. Returns the format string & string length,
+ * or NULL if not found. Returned string is not guaranteed to be nul terminated.
+ */
+const char* android_lookupEventFormat_len(const EventTagMap* map,
+ size_t* len, unsigned int tag);
#ifdef __cplusplus
}
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 493f9f8..3509e7f 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -46,6 +46,7 @@
FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
FORMAT_MODIFIER_UID, /* Adds uid */
+ FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 26556f0..45266de 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -104,7 +104,7 @@
// Get last error message of native bridge when fail to load library or search symbol.
// This is reflection of dlerror() for native bridge.
-char* NativeBridgeGetError();
+const char* NativeBridgeGetError();
struct native_bridge_namespace_t;
@@ -244,7 +244,7 @@
// Returns:
// A string describing the most recent error that occurred when load library
// or lookup symbol via native bridge.
- char* (*getError)();
+ const char* (*getError)();
// Check whether library paths are supported by native bridge.
//
diff --git a/init/action.cpp b/init/action.cpp
index ed88f6d..a12f225 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -118,14 +118,16 @@
Timer t;
int result = command.InvokeFunc();
- // TODO: this should probably be changed to "if (failed || took a long time)"...
- if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
+ double duration_ms = t.duration() * 1000;
+ // Any action longer than 50ms will be warned to user as slow operation
+ if (duration_ms > 50.0 ||
+ android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
std::string source = command.BuildSourceString();
LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
- << " returned " << result << " took " << t.duration() << "s";
+ << " returned " << result << " took " << duration_ms << "ms.";
}
}
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f37ccc2..3e50f4d 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -703,6 +703,15 @@
callback_on_ro_remount = unmount_and_fsck;
} else if (cmd == ANDROID_RB_RESTART2) {
reboot_target = &command[len + 1];
+ // When rebooting to the bootloader notify the bootloader writing
+ // also the BCB.
+ if (strcmp(reboot_target, "bootloader") == 0) {
+ std::string err;
+ if (!write_reboot_bootloader(&err)) {
+ LOG(ERROR) << "reboot-bootloader: Error writing "
+ "bootloader_message: " << err;
+ }
+ }
}
} else if (command[len] != '\0') {
LOG(ERROR) << "powerctl: unrecognized reboot target '" << &command[len] << "'";
diff --git a/init/util.cpp b/init/util.cpp
index ab6837d..ff46e4f 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -38,6 +38,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
@@ -89,10 +90,6 @@
int create_socket(const char *name, int type, mode_t perm, uid_t uid,
gid_t gid, const char *socketcon)
{
- struct sockaddr_un addr;
- int fd, ret, savederrno;
- char *filecon;
-
if (socketcon) {
if (setsockcreatecon(socketcon) == -1) {
PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -100,52 +97,49 @@
}
}
- fd = socket(PF_UNIX, type, 0);
+ android::base::unique_fd fd(socket(PF_UNIX, type, 0));
if (fd < 0) {
PLOG(ERROR) << "Failed to open socket '" << name << "'";
return -1;
}
- if (socketcon)
- setsockcreatecon(NULL);
+ if (socketcon) setsockcreatecon(NULL);
+ struct sockaddr_un addr;
memset(&addr, 0 , sizeof(addr));
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
name);
- ret = unlink(addr.sun_path);
- if (ret != 0 && errno != ENOENT) {
+ if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
- goto out_close;
+ return -1;
}
- filecon = NULL;
+ char *filecon = NULL;
if (sehandle) {
- ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
- if (ret == 0)
+ if (selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK) == 0) {
setfscreatecon(filecon);
+ }
}
- ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
- savederrno = errno;
+ int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
+ int savederrno = errno;
setfscreatecon(NULL);
freecon(filecon);
if (ret) {
- errno = savederrno;
+ errno = savederrno;
PLOG(ERROR) << "Failed to bind socket '" << name << "'";
goto out_unlink;
}
- ret = lchown(addr.sun_path, uid, gid);
- if (ret) {
+ if (lchown(addr.sun_path, uid, gid)) {
PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
goto out_unlink;
}
- ret = fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW);
- if (ret) {
+ if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
goto out_unlink;
}
@@ -155,12 +149,10 @@
<< ", user " << uid
<< ", group " << gid;
- return fd;
+ return fd.release();
out_unlink:
unlink(addr.sun_path);
-out_close:
- close(fd);
return -1;
}
@@ -173,7 +165,6 @@
gid_t gid, const char *filecon)
{
char *secontext = NULL;
- int ret;
if (filecon) {
if (setsockcreatecon(filecon) == -1) {
@@ -181,18 +172,17 @@
return -1;
}
} else if (sehandle) {
- ret = selabel_lookup(sehandle, &secontext, path, perm);
- if (ret != -1) {
- ret = setfscreatecon(secontext);
- if (ret == -1) {
- freecon(secontext);
+ if (selabel_lookup(sehandle, &secontext, path, perm) != -1) {
+ if (setfscreatecon(secontext) == -1) {
+ freecon(secontext); // does not upset errno value
PLOG(ERROR) << "setfscreatecon(\"" << secontext << "\") failed";
return -1;
}
}
}
- int fd = TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm));
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, flags | O_NDELAY, perm)));
+ int savederrno = errno;
if (filecon) {
setsockcreatecon(NULL);
@@ -202,23 +192,22 @@
freecon(secontext);
}
- if (fd == -1) {
+ if (fd < 0) {
+ errno = savederrno;
PLOG(ERROR) << "Failed to open/create file '" << path << "'";
- goto out_close;
+ return -1;
}
if (!(flags & O_NDELAY)) fcntl(fd, F_SETFD, flags);
- ret = lchown(path, uid, gid);
- if (ret) {
+ if (lchown(path, uid, gid)) {
PLOG(ERROR) << "Failed to lchown file '" << path << "'";
- goto out_close;
+ return -1;
}
if (perm != static_cast<mode_t>(-1)) {
- ret = fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW);
- if (ret) {
+ if (fchmodat(AT_FDCWD, path, perm, AT_SYMLINK_NOFOLLOW)) {
PLOG(ERROR) << "Failed to fchmodat file '" << path << "'";
- goto out_close;
+ return -1;
}
}
@@ -227,11 +216,7 @@
<< ", user " << uid
<< ", group " << gid;
- return fd;
-
-out_close:
- if (fd >= 0) close(fd);
- return -1;
+ return fd.release();
}
bool read_file(const char* path, std::string* content) {
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 0e5a281..f9cad99 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -38,6 +38,8 @@
uint32_t tagIndex;
char* tagStr;
size_t tagLen;
+ char* fmtStr;
+ size_t fmtLen;
} EventTag;
/*
@@ -176,6 +178,39 @@
return NULL;
}
+/*
+ * Look up an entry in the map.
+ *
+ * The entries are sorted by tag number, so we can do a binary search.
+ */
+LIBLOG_ABI_PUBLIC const char* android_lookupEventFormat_len(
+ const EventTagMap* map, size_t *len, unsigned int tag)
+{
+ int lo = 0;
+ int hi = map->numTags - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) / 2;
+ int cmp = map->tagArray[mid].tagIndex - tag;
+
+ if (cmp < 0) {
+ /* tag is bigger */
+ lo = mid + 1;
+ } else if (cmp > 0) {
+ /* tag is smaller */
+ hi = mid - 1;
+ } else {
+ /* found */
+ if (len) *len = map->tagArray[mid].fmtLen;
+ return map->tagArray[mid].fmtStr;
+ }
+ }
+
+ errno = ENOENT;
+ if (len) *len = 0;
+ return NULL;
+}
+
LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
unsigned int tag)
{
@@ -364,17 +399,21 @@
}
tag->tagLen = cp - tag->tagStr;
- if (isspace(*cp)) {
- /* just ignore the rest of the line till \n
- TODO: read the tag description that follows the tag name
- */
- while (*cp != '\n') ++cp;
- } else {
+ if (!isspace(*cp)) {
fprintf(stderr, "%s: invalid tag chars on line %d\n", OUT_TAG, lineNum);
errno = EINVAL;
return -1;
}
+ while (isspace(*cp) && (*cp != '\n')) ++cp;
+ if (*cp != '#') {
+ tag->fmtStr = cp;
+ while ((*cp != '\n') && (*cp != '#')) ++cp;
+ while ((cp > tag->fmtStr) && isspace(*(cp - 1))) --cp;
+ tag->fmtLen = cp - tag->fmtStr;
+ }
+
+ while (*cp != '\n') ++cp;
*pData = cp;
return 0;
@@ -406,12 +445,14 @@
for (i = 1; i < map->numTags; i++) {
if (map->tagArray[i].tagIndex == map->tagArray[i - 1].tagIndex) {
fprintf(stderr,
- "%s: duplicate tag entries (%" PRIu32 ":%.*s and %" PRIu32 ":%.*s)\n",
+ "%s: duplicate tag entries (%" PRIu32 ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
OUT_TAG,
- map->tagArray[i].tagIndex, (int)map->tagArray[i].tagLen,
- map->tagArray[i].tagStr,
- map->tagArray[i - 1].tagIndex, (int)map->tagArray[i - 1].tagLen,
- map->tagArray[i - 1].tagStr);
+ map->tagArray[i].tagIndex,
+ (int)map->tagArray[i].tagLen, map->tagArray[i].tagStr,
+ (int)map->tagArray[i].fmtLen, map->tagArray[i].fmtStr,
+ map->tagArray[i - 1].tagIndex,
+ (int)map->tagArray[i - 1].tagLen, map->tagArray[i - 1].fmtStr,
+ (int)map->tagArray[i - 1].fmtLen, map->tagArray[i - 1].fmtStr);
errno = EMLINK;
return -1;
}
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index c481e36..157bd88 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -189,7 +189,7 @@
__android_log_unlock();
#if defined(__BIONIC__)
- android_closeEventTagMap(m);
+ if (m != (EventTagMap *)(uintptr_t)-1LL) android_closeEventTagMap(m);
#endif
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 1ff7136..fb942a1 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,13 +21,13 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <inttypes.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <inttypes.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -58,9 +58,16 @@
bool epoch_output;
bool monotonic_output;
bool uid_output;
+ bool descriptive_output;
};
/*
+ * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
+ * during android_log_processBinaryLogBuffer(), so we break layering.
+ */
+static bool descriptive_output = false;
+
+/*
* gnome-terminal color tags
* See http://misc.flogisoft.com/bash/tip_colors_and_formatting
* for ideas on how to set the forground color of the text for xterm.
@@ -209,6 +216,8 @@
p_ret->epoch_output = false;
p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
p_ret->uid_output = false;
+ p_ret->descriptive_output = false;
+ descriptive_output = false;
return p_ret;
}
@@ -267,6 +276,10 @@
case FORMAT_MODIFIER_UID:
p_format->uid_output = true;
return 0;
+ case FORMAT_MODIFIER_DESCRIPT:
+ p_format->descriptive_output = true;
+ descriptive_output = true;
+ return 0;
default:
break;
}
@@ -294,6 +307,7 @@
else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+ else if (strcmp(formatString, "colour") == 0) format = FORMAT_MODIFIER_COLOR;
else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
else if (strcmp(formatString, "year") == 0) format = FORMAT_MODIFIER_YEAR;
@@ -301,6 +315,7 @@
else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
+ else if (strcmp(formatString, "descriptive") == 0) format = FORMAT_MODIFIER_DESCRIPT;
else {
extern char *tzname[2];
static const char gmt[] = "GMT";
@@ -566,6 +581,19 @@
return ((uint64_t) high << 32) | (uint64_t) low;
}
+static bool findChar(const char** cp, size_t* len, int c) {
+ while (*len && isspace(**cp)) {
+ ++*cp;
+ --*len;
+ }
+ if (c == INT_MAX) return *len;
+ if (*len && (**cp == c)) {
+ ++*cp;
+ --*len;
+ return true;
+ }
+ return false;
+}
/*
* Recursively convert binary log data to printable form.
@@ -578,27 +606,128 @@
*
* Returns 0 on success, 1 on buffer full, -1 on failure.
*/
+enum objectType {
+ TYPE_OBJECTS = '1',
+ TYPE_BYTES = '2',
+ TYPE_MILLISECONDS = '3',
+ TYPE_ALLOCATIONS = '4',
+ TYPE_ID = '5',
+ TYPE_PERCENT = '6'
+};
+
static int android_log_printBinaryEvent(const unsigned char** pEventData,
- size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen)
+ size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen,
+ const char** fmtStr, size_t* fmtLen)
{
const unsigned char* eventData = *pEventData;
size_t eventDataLen = *pEventDataLen;
char* outBuf = *pOutBuf;
+ char* outBufSave = outBuf;
size_t outBufLen = *pOutBufLen;
+ size_t outBufLenSave = outBufLen;
unsigned char type;
size_t outCount;
int result = 0;
+ const char* cp;
+ size_t len;
+ int64_t lval;
if (eventDataLen < 1)
return -1;
type = *eventData++;
eventDataLen--;
+ cp = NULL;
+ len = 0;
+ if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
+ cp = *fmtStr;
+ len = *fmtLen;
+ }
+ /*
+ * event.logtag format specification:
+ *
+ * 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
+ * 5: float
+ *
+ * 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).
+ */
+ if (!cp || !findChar(&cp, &len, '(')) {
+ len = 0;
+ } else {
+ char* outBufLastSpace = NULL;
+
+ findChar(&cp, &len, INT_MAX);
+ while (len && *cp && (*cp != '|') && (*cp != ')')) {
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ outBufLastSpace = isspace(*cp) ? outBuf : NULL;
+ *outBuf = *cp;
+ ++outBuf;
+ ++cp;
+ --outBufLen;
+ --len;
+ }
+ if (outBufLastSpace) {
+ outBufLen += outBuf - outBufLastSpace;
+ outBuf = outBufLastSpace;
+ }
+ if (outBufLen <= 0) {
+ /* halt output */
+ goto no_room;
+ }
+ if (outBufSave != outBuf) {
+ *outBuf = '=';
+ ++outBuf;
+ --outBufLen;
+ }
+
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ static const unsigned char typeTable[] = {
+ EVENT_TYPE_INT,
+ EVENT_TYPE_LONG,
+ EVENT_TYPE_STRING,
+ EVENT_TYPE_LIST,
+ EVENT_TYPE_FLOAT
+ };
+
+ if ((*cp >= '1') &&
+ (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
+ (type != typeTable[(size_t)(*cp - '1')])) len = 0;
+
+ if (len) {
+ ++cp;
+ --len;
+ } else {
+ /* reset the format */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
+ }
+ }
+ }
+ lval = 0;
switch (type) {
case EVENT_TYPE_INT:
/* 32-bit signed int */
{
- int ival;
+ int32_t ival;
if (eventDataLen < 4)
return -1;
@@ -606,35 +735,24 @@
eventData += 4;
eventDataLen -= 4;
- outCount = snprintf(outBuf, outBufLen, "%d", ival);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
+ lval = ival;
}
- break;
+ goto pr_lval;
case EVENT_TYPE_LONG:
/* 64-bit signed long */
- {
- uint64_t lval;
-
- if (eventDataLen < 8)
- return -1;
- lval = get8LE(eventData);
- eventData += 8;
- eventDataLen -= 8;
-
- outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
+ if (eventDataLen < 8)
+ return -1;
+ lval = get8LE(eventData);
+ eventData += 8;
+ eventDataLen -= 8;
+ pr_lval:
+ outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else {
+ /* halt output */
+ goto no_room;
}
break;
case EVENT_TYPE_FLOAT:
@@ -674,6 +792,11 @@
if (eventDataLen < strLen)
return -1;
+ if (cp && (strLen == 0)) {
+ /* reset the format if no content */
+ outBuf = outBufSave;
+ outBufLen = outBufLenSave;
+ }
if (strLen < outBufLen) {
memcpy(outBuf, eventData, strLen);
outBuf += strLen;
@@ -710,7 +833,7 @@
for (i = 0; i < count; i++) {
result = android_log_printBinaryEvent(&eventData, &eventDataLen,
- &outBuf, &outBufLen);
+ &outBuf, &outBufLen, fmtStr, fmtLen);
if (result != 0)
goto bail;
@@ -736,12 +859,90 @@
fprintf(stderr, "Unknown binary event type %d\n", type);
return -1;
}
+ if (cp && len) {
+ if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
+ switch (*cp) {
+ case TYPE_OBJECTS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " objects"); */
+ break;
+ case TYPE_BYTES:
+ if ((lval != 0) && ((lval % 1024) == 0)) {
+ /* repaint with multiplier */
+ static const char suffixTable[] = { 'K', 'M', 'G', 'T' };
+ size_t idx = 0;
+ outBuf -= outCount;
+ outBufLen += outCount;
+ do {
+ lval /= 1024;
+ if ((lval % 1024) != 0) break;
+ } while (++idx < ((sizeof(suffixTable) /
+ sizeof(suffixTable[0])) - 1));
+ outCount = snprintf(outBuf, outBufLen,
+ "%" PRId64 "%cB",
+ lval, suffixTable[idx]);
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "B");
+ }
+ break;
+ case TYPE_MILLISECONDS:
+ if (((lval <= -1000) || (1000 <= lval)) &&
+ (outBufLen || (outBuf[-1] == '0'))) {
+ /* repaint as (fractional) seconds, possibly saving space */
+ if (outBufLen) outBuf[0] = outBuf[-1];
+ outBuf[-1] = outBuf[-2];
+ outBuf[-2] = outBuf[-3];
+ outBuf[-3] = '.';
+ while ((outBufLen == 0) || (*outBuf == '0')) {
+ --outBuf;
+ ++outBufLen;
+ }
+ if (*outBuf != '.') {
+ ++outBuf;
+ --outBufLen;
+ }
+ outCount = snprintf(outBuf, outBufLen, "s");
+ } else {
+ outCount = snprintf(outBuf, outBufLen, "ms");
+ }
+ break;
+ case TYPE_ALLOCATIONS:
+ outCount = 0;
+ /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
+ break;
+ case TYPE_ID:
+ outCount = 0;
+ break;
+ case TYPE_PERCENT:
+ outCount = snprintf(outBuf, outBufLen, "%%");
+ break;
+ default: /* ? */
+ outCount = 0;
+ break;
+ }
+ ++cp;
+ --len;
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else if (outCount) {
+ /* halt output */
+ goto no_room;
+ }
+ }
+ if (!findChar(&cp, &len, ')')) len = 0;
+ if (!findChar(&cp, &len, ',')) len = 0;
+ }
bail:
*pEventData = eventData;
*pEventDataLen = eventDataLen;
*pOutBuf = outBuf;
*pOutBufLen = outBufLen;
+ if (cp) {
+ *fmtStr = cp;
+ *fmtLen = len;
+ }
return result;
no_room:
@@ -764,7 +965,7 @@
char *messageBuf, int messageBufLen)
{
size_t inCount;
- unsigned int tagIndex;
+ uint32_t tagIndex;
const unsigned char* eventData;
entry->tv_sec = buf->sec;
@@ -817,7 +1018,7 @@
if (entry->tag == NULL) {
size_t tagLen;
- tagLen = snprintf(messageBuf, messageBufLen, "[%d]", tagIndex);
+ tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
if (tagLen >= (size_t)messageBufLen) {
tagLen = messageBufLen - 1;
}
@@ -831,10 +1032,27 @@
* Format the event log data into the buffer.
*/
char* outBuf = messageBuf;
- size_t outRemaining = messageBufLen-1; /* leave one for nul byte */
+ size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
int result;
+ const char* fmtStr = NULL;
+ size_t fmtLen = 0;
+ if (descriptive_output && map) {
+ fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
+ }
result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
- &outRemaining);
+ &outRemaining, &fmtStr, &fmtLen);
+ if ((result == 1) && fmtStr) {
+ /* We overflowed :-(, let's repaint the line w/o format dressings */
+ eventData = (const unsigned char*)buf->msg;
+ if (buf2->hdr_size) {
+ eventData = ((unsigned char *)buf2) + buf2->hdr_size;
+ }
+ eventData += 4;
+ outBuf = messageBuf;
+ outRemaining = messageBufLen - 1;
+ result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf,
+ &outRemaining, NULL, NULL);
+ }
if (result < 0) {
fprintf(stderr, "Binary log entry conversion failed\n");
return -1;
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 43e6c0a..eafc53d 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -551,15 +551,15 @@
return -1;
}
-char* NativeBridgeGetError() {
+const char* NativeBridgeGetError() {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
return callbacks->getError();
} else {
- ALOGE("not compatible with version %d, cannot get message", NAMESPACE_VERSION);
+ return "native bridge implementation is not compatible with version 3, cannot get message";
}
}
- return nullptr;
+ return "native bridge is not initialized";
}
bool NativeBridgeIsPathSupported(const char* path) {
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
index c538fa0..13fce85 100644
--- a/libnativebridge/tests/DummyNativeBridge3.cpp
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -68,7 +68,7 @@
return 0;
}
-extern "C" char* native_bridge3_getError() {
+extern "C" const char* native_bridge3_getError() {
return nullptr;
}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index e09cce3..15fe054 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -308,13 +308,17 @@
// code is one example) unknown to linker in which case linker uses anonymous
// namespace. The second argument specifies the search path for the anonymous
// namespace which is the library_path of the classloader.
- if (!is_native_bridge) {
- initialized_ = android_init_namespaces(public_libraries_.c_str(), library_path);
- if (!initialized_) {
- *error_msg = dlerror();
- }
- } else {
- initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(), library_path);
+ initialized_ = android_init_namespaces(public_libraries_.c_str(),
+ is_native_bridge ? nullptr : library_path);
+ if (!initialized_) {
+ *error_msg = dlerror();
+ return false;
+ }
+
+ // and now initialize native bridge namespaces if necessary.
+ if (NativeBridgeInitialized()) {
+ initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
+ is_native_bridge ? library_path : nullptr);
if (!initialized_) {
*error_msg = NativeBridgeGetError();
}
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index f08a6cd..d0c693d 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -82,8 +82,14 @@
static size_t g_printCount;
static bool g_printItAnyways;
+enum helpType {
+ HELP_FALSE,
+ HELP_TRUE,
+ HELP_FORMAT
+};
+
// if showHelp is set, newline required in fmt statement to transition to usage
-__noreturn static void logcat_panic(bool showHelp, const char *fmt, ...) __printflike(2,3);
+__noreturn static void logcat_panic(enum helpType showHelp, const char *fmt, ...) __printflike(2,3);
static int openLogFile (const char *pathname)
{
@@ -133,7 +139,7 @@
g_outFD = openLogFile(g_outputFileName);
if (g_outFD < 0) {
- logcat_panic(false, "couldn't open output file");
+ logcat_panic(HELP_FALSE, "couldn't open output file");
}
g_outByteCount = 0;
@@ -196,7 +202,7 @@
bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
if (bytesWritten < 0) {
- logcat_panic(false, "output error");
+ logcat_panic(HELP_FALSE, "output error");
}
}
}
@@ -210,7 +216,6 @@
}
error:
- //fprintf (stderr, "Error processing record\n");
return;
}
@@ -222,7 +227,7 @@
dev->printed ? "switch to" : "beginning of",
dev->device);
if (write(g_outFD, buf, strlen(buf)) < 0) {
- logcat_panic(false, "output error");
+ logcat_panic(HELP_FALSE, "output error");
}
}
dev->printed = true;
@@ -256,18 +261,18 @@
g_outFD = openLogFile (g_outputFileName);
if (g_outFD < 0) {
- logcat_panic(false, "couldn't open output file");
+ logcat_panic(HELP_FALSE, "couldn't open output file");
}
struct stat statbuf;
if (fstat(g_outFD, &statbuf) == -1) {
close(g_outFD);
- logcat_panic(false, "couldn't get output file stat\n");
+ logcat_panic(HELP_FALSE, "couldn't get output file stat\n");
}
if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
close(g_outFD);
- logcat_panic(false, "invalid output file stat\n");
+ logcat_panic(HELP_FALSE, "invalid output file stat\n");
}
g_outByteCount = statbuf.st_size;
@@ -288,9 +293,10 @@
" the fileset and continue\n"
" -v <format>, --format=<format>\n"
" Sets log print format verb and adverbs, where <format> is:\n"
- " brief long process raw tag thread threadtime time\n"
+ " brief help long process raw tag thread threadtime time\n"
" and individually flagged modifying adverbs can be added:\n"
- " color epoch monotonic printable uid usec UTC year zone\n"
+ " color descriptive epoch monotonic printable uid\n"
+ " usec UTC year zone\n"
" -D, --dividers Print dividers between each log buffer\n"
" -c, --clear Clear (flush) the entire log and exit\n"
" if Log to File specified, clear fileset instead\n"
@@ -356,6 +362,40 @@
"or defaults to \"threadtime\"\n\n");
}
+static void show_format_help()
+{
+ fprintf(stderr,
+ "-v <format>, --format=<format> options:\n"
+ " Sets log print format verb and adverbs, where <format> is:\n"
+ " brief long process raw tag thread threadtime time\n"
+ " and individually flagged modifying adverbs can be added:\n"
+ " color descriptive epoch monotonic printable uid usec UTC year zone\n"
+ "\nSingle format verbs:\n"
+ " brief — Display priority/tag and PID of the process issuing the message.\n"
+ " long — Display all metadata fields, separate messages with blank lines.\n"
+ " process — Display PID only.\n"
+ " raw — Display the raw log message, with no other metadata fields.\n"
+ " tag — Display the priority/tag only.\n"
+ " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
+ " and TID of the thread issuing the message. (the default format).\n"
+ " time — Display the date, invocation time, priority/tag, and PID of the\n"
+ " process issuing the message.\n"
+ "\nAdverb modifiers can be used in combination:\n"
+ " color — Display in highlighted color to match priority. i.e. \x1B[38;5;231mVERBOSE\n"
+ " \x1B[38;5;75mDEBUG \x1B[38;5;40mINFO \x1B[38;5;166mWARNING \x1B[38;5;196mERROR FATAL\x1B[0m\n"
+ " descriptive — events logs only, descriptions from event-log-tags database.\n"
+ " epoch — Display time as seconds since Jan 1 1970.\n"
+ " monotonic — Display time as cpu seconds since last boot.\n"
+ " printable — Ensure that any binary logging content is escaped.\n"
+ " uid — If permitted, display the UID or Android ID of logged process.\n"
+ " usec — Display time down the microsecond precision.\n"
+ " UTC — Display time as UTC.\n"
+ " year — Add the year to the displayed time.\n"
+ " zone — Add the local timezone to the displayed time.\n"
+ " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
+ );
+}
+
static int setLogFormat(const char * formatString)
{
static AndroidLogPrintFormat format;
@@ -418,15 +458,23 @@
return true;
}
-static void logcat_panic(bool showHelp, const char *fmt, ...)
+static void logcat_panic(enum helpType showHelp, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
- if (showHelp) {
+ switch (showHelp) {
+ case HELP_TRUE:
show_help(getprogname());
+ break;
+ case HELP_FORMAT:
+ show_format_help();
+ break;
+ case HELP_FALSE:
+ default:
+ break;
}
exit(EXIT_FAILURE);
@@ -616,7 +664,7 @@
if (long_options[option_index].name == pid_str) {
// ToDo: determine runtime PID_MAX?
if (!getSizeTArg(optarg, &pid, 1)) {
- logcat_panic(true, "%s %s out of range\n",
+ logcat_panic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
break;
@@ -628,7 +676,7 @@
// ToDo: implement API that supports setting a wrap timeout
size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
- logcat_panic(true, "%s %s out of range\n",
+ logcat_panic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
@@ -675,7 +723,8 @@
if (strspn(optarg, "0123456789") != strlen(optarg)) {
char *cp = parseTime(tail_time, optarg);
if (!cp) {
- logcat_panic(false, "-%c \"%s\" not in time format\n",
+ logcat_panic(HELP_FALSE,
+ "-%c \"%s\" not in time format\n",
ret, optarg);
}
if (*cp) {
@@ -707,7 +756,7 @@
case 'm': {
char *end = NULL;
if (!getSizeTArg(optarg, &g_maxCount)) {
- logcat_panic(false, "-%c \"%s\" isn't an "
+ logcat_panic(HELP_FALSE, "-%c \"%s\" isn't an "
"integer greater than zero\n", ret, optarg);
}
}
@@ -780,7 +829,8 @@
const char *name = android_log_id_to_name(log_id);
if (strcmp(name, optarg) != 0) {
- logcat_panic(true, "unknown buffer %s\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "unknown buffer %s\n", optarg);
}
idMask |= (1 << log_id);
}
@@ -841,20 +891,27 @@
case 'r':
if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
- logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "Invalid parameter \"%s\" to -r\n", optarg);
}
break;
case 'n':
if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
- logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
+ logcat_panic(HELP_TRUE,
+ "Invalid parameter \"%s\" to -n\n", optarg);
}
break;
case 'v':
- err = setLogFormat (optarg);
+ if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
+ show_format_help();
+ exit(0);
+ }
+ err = setLogFormat(optarg);
if (err < 0) {
- logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
+ logcat_panic(HELP_FORMAT,
+ "Invalid parameter \"%s\" to -v\n", optarg);
}
hasSetLogFormat |= err;
break;
@@ -932,17 +989,20 @@
break;
case ':':
- logcat_panic(true, "Option -%c needs an argument\n", optopt);
+ logcat_panic(HELP_TRUE,
+ "Option -%c needs an argument\n", optopt);
break;
default:
- logcat_panic(true, "Unrecognized Option %c\n", optopt);
+ logcat_panic(HELP_TRUE,
+ "Unrecognized Option %c\n", optopt);
break;
}
}
if (g_maxCount && got_t) {
- logcat_panic(true, "Cannot use -m (--max-count) and -t together\n");
+ logcat_panic(HELP_TRUE,
+ "Cannot use -m (--max-count) and -t together\n");
}
if (g_printItAnyways && (!g_regex || !g_maxCount)) {
// One day it would be nice if --print -v color and --regex <expr>
@@ -968,12 +1028,12 @@
}
if (g_logRotateSizeKBytes != 0 && g_outputFileName == NULL) {
- logcat_panic(true, "-r requires -f as well\n");
+ logcat_panic(HELP_TRUE, "-r requires -f as well\n");
}
if (setId != NULL) {
if (g_outputFileName == NULL) {
- logcat_panic(true, "--id='%s' requires -f as well\n", setId);
+ logcat_panic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
}
std::string file_name = android::base::StringPrintf("%s.id", g_outputFileName);
@@ -1003,7 +1063,8 @@
if (forceFilters) {
err = android_log_addFilterString(g_logformat, forceFilters);
if (err < 0) {
- logcat_panic(false, "Invalid filter expression in logcat args\n");
+ logcat_panic(HELP_FALSE,
+ "Invalid filter expression in logcat args\n");
}
} else if (argc == optind) {
// Add from environment variable
@@ -1013,7 +1074,7 @@
err = android_log_addFilterString(g_logformat, env_tags_orig);
if (err < 0) {
- logcat_panic(true,
+ logcat_panic(HELP_TRUE,
"Invalid filter expression in ANDROID_LOG_TAGS\n");
}
}
@@ -1023,7 +1084,8 @@
err = android_log_addFilterString(g_logformat, argv[i]);
if (err < 0) {
- logcat_panic(true, "Invalid filter expression '%s'\n", argv[i]);
+ logcat_panic(HELP_TRUE,
+ "Invalid filter expression '%s'\n", argv[i]);
}
}
}
@@ -1109,17 +1171,20 @@
}
// report any errors in the above loop and exit
if (openDeviceFail) {
- logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
+ logcat_panic(HELP_FALSE,
+ "Unable to open log device '%s'\n", openDeviceFail);
}
if (clearFail) {
- logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
+ logcat_panic(HELP_FALSE,
+ "failed to clear the '%s' log\n", clearFail);
}
if (setSizeFail) {
- logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
+ logcat_panic(HELP_FALSE,
+ "failed to set the '%s' log size\n", setSizeFail);
}
if (getSizeFail) {
- logcat_panic(false, "failed to get the readable '%s' log size",
- getSizeFail);
+ logcat_panic(HELP_FALSE,
+ "failed to get the readable '%s' log size", getSizeFail);
}
if (setPruneList) {
@@ -1130,11 +1195,11 @@
if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
buf[len] = '\0';
if (android_logger_set_prune_list(logger_list, buf, bLen)) {
- logcat_panic(false, "failed to set the prune list");
+ logcat_panic(HELP_FALSE, "failed to set the prune list");
}
free(buf);
} else {
- logcat_panic(false, "failed to set the prune list (alloc)");
+ logcat_panic(HELP_FALSE, "failed to set the prune list (alloc)");
}
}
@@ -1165,7 +1230,7 @@
}
if (!buf) {
- logcat_panic(false, "failed to read data");
+ logcat_panic(HELP_FALSE, "failed to read data");
}
// remove trailing FF
@@ -1217,7 +1282,7 @@
int ret = android_logger_list_read(logger_list, &log_msg);
if (ret == 0) {
- logcat_panic(false, "read: unexpected EOF!\n");
+ logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret < 0) {
@@ -1226,12 +1291,12 @@
}
if (ret == -EIO) {
- logcat_panic(false, "read: unexpected EOF!\n");
+ logcat_panic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret == -EINVAL) {
- logcat_panic(false, "read: unexpected length.\n");
+ logcat_panic(HELP_FALSE, "read: unexpected length.\n");
}
- logcat_panic(false, "logcat read failure");
+ logcat_panic(HELP_FALSE, "logcat read failure");
}
for (d = devices; d; d = d->next) {
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index bc0ea52..18067dc 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -25,6 +25,7 @@
#include <sys/wait.h>
#include <memory>
+#include <string>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -1235,3 +1236,163 @@
ASSERT_EQ(3, count);
}
+
+static bool End_to_End(const char* tag, const char* fmt, ...)
+#if defined(__GNUC__)
+ __attribute__((__format__(printf, 2, 3)))
+#endif
+ ;
+
+static bool End_to_End(const char* tag, const char* fmt, ...) {
+ FILE *fp = popen("logcat -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
+ if (!fp) return false;
+
+ char buffer[BIG_BUFFER];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ va_end(ap);
+
+ char *str = NULL;
+ asprintf(&str, "I/%s ( %%d): %s%%c", tag, buffer);
+ std::string expect(str);
+ free(str);
+
+ int count = 0;
+ pid_t pid = getpid();
+ std::string lastMatch;
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ char newline;
+ int p;
+ int ret = sscanf(buffer, expect.c_str(), &p, &newline);
+ if ((2 == ret) && (p == pid) && (newline == '\n')) ++count;
+ else if ((1 == ret) && (p == pid) && (count == 0)) lastMatch = buffer;
+ }
+
+ pclose(fp);
+
+ if ((count == 0) && (lastMatch.length() > 0)) {
+ // Help us pinpoint where things went wrong ...
+ fprintf(stderr, "Closest match for\n %s\n is\n %s",
+ expect.c_str(), lastMatch.c_str());
+ }
+
+ return count == 1;
+}
+
+TEST(logcat, descriptive) {
+ struct tag {
+ uint32_t tagNo;
+ const char* tagStr;
+ };
+
+ {
+ static const struct tag hhgtg = { 42, "answer" };
+ android_log_event_context ctx(hhgtg.tagNo);
+ static const char theAnswer[] = "what is five by seven";
+ ctx << theAnswer;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(hhgtg.tagStr,
+ "to life the universe etc=%s", theAnswer));
+ }
+
+ {
+ static const struct tag sync = { 2720, "sync" };
+ static const char id[] = "logcat.decriptive";
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[id=%s,event=42,source=-1,account=0]",
+ id));
+ }
+
+ // Partial match to description
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[id=%s,event=43,-1,0]",
+ id));
+ }
+
+ // Negative Test of End_to_End, ensure it is working
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
+ ctx.write();
+ fprintf(stderr, "Expect a \"Closest match\" message\n");
+ EXPECT_FALSE(End_to_End(sync.tagStr,
+ "[id=%s,event=44,source=-1,account=0]",
+ id));
+ }
+ }
+
+ {
+ static const struct tag sync = { 2747, "contacts_aggregation" };
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint64_t)30 << (int32_t)2;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[aggregation time=30ms,count=2]"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint64_t)31570 << (int32_t)911;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr,
+ "[aggregation time=31.57s,count=911]"));
+ }
+ }
+
+ {
+ static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)512;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)3072;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)2097152;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)2097153;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)1073741824;
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
+ }
+
+ {
+ android_log_event_context ctx(sync.tagNo);
+ ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
+ ctx.write();
+ EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
+ }
+ }
+
+}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index e8b1882..4e766bb 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -295,6 +295,10 @@
# Make sure /sys/kernel/debug (if present) is labeled properly
restorecon_recursive /sys/kernel/debug
+ # On systems with tracefs, tracing is a separate mount, so make sure
+ # it too is correctly labeled
+ restorecon_recursive /sys/kernel/debug/tracing
+
# We chown/chmod /cache again so because mount is run as root + defaults
chown system cache /cache
chmod 0770 /cache
@@ -562,7 +566,7 @@
on nonencrypted
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier nonencrypted
+ exec - root cache -- /system/bin/update_verifier nonencrypted
class_start main
class_start late_start
@@ -585,12 +589,12 @@
on property:vold.decrypt=trigger_restart_min_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_min_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_min_framework
class_start main
on property:vold.decrypt=trigger_restart_framework
# A/B update verifier that marks a successful boot.
- exec - root -- /system/bin/update_verifier trigger_restart_framework
+ exec - root cache -- /system/bin/update_verifier trigger_restart_framework
class_start main
class_start late_start