merge in mnc-release history after reset to mnc-dev
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 0648826..66a470a 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -14,6 +14,8 @@
LOCAL_PATH:= $(call my-dir)
+fastboot_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
@@ -25,14 +27,15 @@
LOCAL_CONLYFLAGS += -std=gnu99
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
+LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
+
ifeq ($(HOST_OS),linux)
LOCAL_SRC_FILES += usb_linux.c util_linux.c
endif
ifeq ($(HOST_OS),darwin)
LOCAL_SRC_FILES += usb_osx.c util_osx.c
- LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit \
- -framework Carbon
+ LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS += -Wno-unused-parameter
endif
@@ -58,7 +61,8 @@
libsparse_host \
libutils \
liblog \
- libz
+ libz \
+ libbase
ifneq ($(HOST_OS),windows)
LOCAL_STATIC_LIBRARIES += libselinux
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 51985af..be80cce 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -59,7 +59,6 @@
char cur_product[FB_RESPONSE_SZ + 1];
-static usb_handle *usb = 0;
static const char *serial = 0;
static const char *product = 0;
static const char *cmdline = 0;
@@ -407,6 +406,35 @@
return data;
}
+#if defined(_WIN32)
+
+// TODO: move this to somewhere it can be shared.
+
+#include <windows.h>
+
+// Windows' tmpfile(3) requires administrator rights because
+// it creates temporary files in the root directory.
+static FILE* win32_tmpfile() {
+ char temp_path[PATH_MAX];
+ DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
+ if (nchars == 0 || nchars >= sizeof(temp_path)) {
+ fprintf(stderr, "GetTempPath failed, error %ld\n", GetLastError());
+ return nullptr;
+ }
+
+ char filename[PATH_MAX];
+ if (GetTempFileName(temp_path, "fastboot", 0, filename) == 0) {
+ fprintf(stderr, "GetTempFileName failed, error %ld\n", GetLastError());
+ return nullptr;
+ }
+
+ return fopen(filename, "w+bTD");
+}
+
+#define tmpfile win32_tmpfile
+
+#endif
+
static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
FILE* fp = tmpfile();
if (fp == NULL) {
@@ -609,7 +637,7 @@
* erase partitions of type ext4 before flashing a filesystem so no stale
* inodes are left lying around. Otherwise, e2fsck gets very upset.
*/
-static int needs_erase(const char *part)
+static int needs_erase(usb_handle* usb, const char *part)
{
/* The function fb_format_supported() currently returns the value
* we want, so just call it.
@@ -725,19 +753,20 @@
setup_requirements(reinterpret_cast<char*>(data), sz);
- for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(images); ++i) {
int fd = unzip_to_file(zip, images[i].img_name);
- if (fd < 0) {
- if (images[i].is_optional)
+ if (fd == -1) {
+ if (images[i].is_optional) {
continue;
+ }
CloseArchive(zip);
- die("update package missing %s", images[i].img_name);
+ exit(1); // unzip_to_file already explained why.
}
fastboot_buffer buf;
int rc = load_buf_fd(usb, fd, &buf);
if (rc) die("cannot load %s from flash", images[i].img_name);
do_update_signature(zip, images[i].sig_name);
- if (erase_first && needs_erase(images[i].part_name)) {
+ if (erase_first && needs_erase(usb, images[i].part_name)) {
fb_queue_erase(images[i].part_name);
}
flash_buf(images[i].part_name, &buf);
@@ -792,7 +821,7 @@
die("could not load %s\n", images[i].img_name);
}
do_send_signature(fname);
- if (erase_first && needs_erase(images[i].part_name)) {
+ if (erase_first && needs_erase(usb, images[i].part_name)) {
fb_queue_erase(images[i].part_name);
}
flash_buf(images[i].part_name, &buf);
@@ -860,7 +889,8 @@
return num;
}
-void fb_perform_format(const char *partition, int skip_if_not_supported,
+void fb_perform_format(usb_handle* usb,
+ const char *partition, int skip_if_not_supported,
const char *type_override, const char *size_override)
{
char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
@@ -964,8 +994,9 @@
{"page_size", required_argument, 0, 'n'},
{"ramdisk_offset", required_argument, 0, 'r'},
{"tags_offset", required_argument, 0, 't'},
- {"help", 0, 0, 'h'},
- {"unbuffered", 0, 0, 0},
+ {"help", no_argument, 0, 'h'},
+ {"unbuffered", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
{0, 0, 0, 0}
};
@@ -1037,6 +1068,9 @@
if (strcmp("unbuffered", longopts[longindex].name) == 0) {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
+ } else if (strcmp("version", longopts[longindex].name) == 0) {
+ fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
+ return 0;
}
break;
default:
@@ -1063,7 +1097,7 @@
return 0;
}
- usb = open_device();
+ usb_handle* usb = open_device();
while (argc > 0) {
if(!strcmp(*argv, "getvar")) {
@@ -1105,10 +1139,10 @@
}
if (type_override && !type_override[0]) type_override = NULL;
if (size_override && !size_override[0]) size_override = NULL;
- if (erase_first && needs_erase(argv[1])) {
+ if (erase_first && needs_erase(usb, argv[1])) {
fb_queue_erase(argv[1]);
}
- fb_perform_format(argv[1], 0, type_override, size_override);
+ fb_perform_format(usb, argv[1], 0, type_override, size_override);
skip(2);
} else if(!strcmp(*argv, "signature")) {
require(2);
@@ -1163,7 +1197,7 @@
skip(2);
}
if (fname == 0) die("cannot determine image filename for '%s'", pname);
- if (erase_first && needs_erase(pname)) {
+ if (erase_first && needs_erase(usb, pname)) {
fb_queue_erase(pname);
}
do_flash(usb, pname, fname);
@@ -1214,9 +1248,9 @@
if (wants_wipe) {
fb_queue_erase("userdata");
- fb_perform_format("userdata", 1, NULL, NULL);
+ fb_perform_format(usb, "userdata", 1, NULL, NULL);
fb_queue_erase("cache");
- fb_perform_format("cache", 1, NULL, NULL);
+ fb_perform_format(usb, "cache", 1, NULL, NULL);
}
if (wants_reboot) {
fb_queue_reboot();
diff --git a/fingerprintd/FingerprintDaemonProxy.cpp b/fingerprintd/FingerprintDaemonProxy.cpp
index 4f35520..a8a4024 100644
--- a/fingerprintd/FingerprintDaemonProxy.cpp
+++ b/fingerprintd/FingerprintDaemonProxy.cpp
@@ -123,7 +123,7 @@
int32_t timeout) {
ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout);
if (tokenSize != sizeof(hw_auth_token_t) ) {
- ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %" PRId64 "\n", tokenSize);
+ ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zu\n", tokenSize);
return -1;
}
const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(token);
@@ -171,7 +171,7 @@
char path_name[PATH_MAX];
memcpy(path_name, path, pathlen);
path_name[pathlen] = '\0';
- ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %" PRId64 ")", groupId, path_name, pathlen);
+ ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, path_name, pathlen);
return mDevice->set_active_group(mDevice, groupId, path_name);
return -1;
}
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 96249e9..4b812cc 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -36,9 +36,10 @@
FORMAT_TIME,
FORMAT_THREADTIME,
FORMAT_LONG,
- /* The following two are modifiers to above formats */
+ /* The following three are modifiers to above formats */
FORMAT_MODIFIER_COLOR, /* converts priority to color */
FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
+ FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
diff --git a/liblog/logprint.c b/liblog/logprint.c
index a3f1d7e..c2f1545 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -32,6 +32,9 @@
#include <log/logd.h>
#include <log/logprint.h>
+/* open coded fragment, prevent circular dependencies */
+#define WEAK static
+
typedef struct FilterInfo_t {
char *mTag;
android_LogPriority mPri;
@@ -44,6 +47,7 @@
AndroidLogPrintFormat format;
bool colored_output;
bool usec_time_output;
+ bool printable_output;
};
/*
@@ -187,6 +191,7 @@
p_ret->format = FORMAT_BRIEF;
p_ret->colored_output = false;
p_ret->usec_time_output = false;
+ p_ret->printable_output = false;
return p_ret;
}
@@ -212,13 +217,18 @@
int android_log_setPrintFormat(AndroidLogFormat *p_format,
AndroidLogPrintFormat format)
{
- if (format == FORMAT_MODIFIER_COLOR) {
+ switch (format) {
+ case FORMAT_MODIFIER_COLOR:
p_format->colored_output = true;
return 0;
- }
- if (format == FORMAT_MODIFIER_TIME_USEC) {
+ case FORMAT_MODIFIER_TIME_USEC:
p_format->usec_time_output = true;
return 0;
+ case FORMAT_MODIFIER_PRINTABLE:
+ p_format->printable_output = true;
+ return 0;
+ default:
+ break;
}
p_format->format = format;
return 1;
@@ -241,6 +251,7 @@
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
else if (strcmp(formatString, "color") == 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 format = FORMAT_OFF;
return format;
@@ -276,29 +287,35 @@
}
if(0 == strncmp("*", filterExpression, tagNameLength)) {
- // This filter expression refers to the global filter
- // The default level for this is DEBUG if the priority
- // is unspecified
+ /*
+ * This filter expression refers to the global filter
+ * The default level for this is DEBUG if the priority
+ * is unspecified
+ */
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_DEBUG;
}
p_format->global_pri = pri;
} else {
- // for filter expressions that don't refer to the global
- // filter, the default is verbose if the priority is unspecified
+ /*
+ * for filter expressions that don't refer to the global
+ * filter, the default is verbose if the priority is unspecified
+ */
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_VERBOSE;
}
char *tagName;
-// Presently HAVE_STRNDUP is never defined, so the second case is always taken
-// Darwin doesn't have strnup, everything else does
+/*
+ * Presently HAVE_STRNDUP is never defined, so the second case is always taken
+ * Darwin doesn't have strnup, everything else does
+ */
#ifdef HAVE_STRNDUP
tagName = strndup(filterExpression, tagNameLength);
#else
- //a few extra bytes copied...
+ /* a few extra bytes copied... */
tagName = strdup(filterExpression);
tagName[tagNameLength] = '\0';
#endif /*HAVE_STRNDUP*/
@@ -335,9 +352,9 @@
char *p_ret;
int err;
- // Yes, I'm using strsep
+ /* Yes, I'm using strsep */
while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
- // ignore whitespace-only entries
+ /* ignore whitespace-only entries */
if(p_ret[0] != '\0') {
err = android_log_addFilterRule(p_format, p_ret);
@@ -381,8 +398,10 @@
* When that happens, we must null-terminate the message ourselves.
*/
if (buf->len < 3) {
- // An well-formed entry must consist of at least a priority
- // and two null characters
+ /*
+ * An well-formed entry must consist of at least a priority
+ * and two null characters
+ */
fprintf(stderr, "+++ LOG: entry too small\n");
return -1;
}
@@ -412,7 +431,7 @@
return -1;
}
if (msgEnd == -1) {
- // incoming message not null-terminated; force it
+ /* incoming message not null-terminated; force it */
msgEnd = buf->len - 1;
msg[msgEnd] = '\0';
}
@@ -473,8 +492,6 @@
type = *eventData++;
eventDataLen--;
- //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
-
switch (type) {
case EVENT_TYPE_INT:
/* 32-bit signed int */
@@ -735,6 +752,122 @@
return 0;
}
+/*
+ * One utf8 character at a time
+ *
+ * Returns the length of the utf8 character in the buffer,
+ * or -1 if illegal or truncated
+ *
+ * Open coded from libutils/Unicode.cpp, borrowed from utf8_length(),
+ * can not remove from here because of library circular dependencies.
+ * Expect one-day utf8_character_length with the same signature could
+ * _also_ be part of libutils/Unicode.cpp if its usefullness needs to
+ * propagate globally.
+ */
+WEAK ssize_t utf8_character_length(const char *src, size_t len)
+{
+ const char *cur = src;
+ const char first_char = *cur++;
+ static const uint32_t kUnicodeMaxCodepoint = 0x0010FFFF;
+ int32_t mask, to_ignore_mask;
+ size_t num_to_read;
+ uint32_t utf32;
+
+ if ((first_char & 0x80) == 0) { /* ASCII */
+ return 1;
+ }
+
+ /*
+ * (UTF-8's character must not be like 10xxxxxx,
+ * but 110xxxxx, 1110xxxx, ... or 1111110x)
+ */
+ if ((first_char & 0x40) == 0) {
+ return -1;
+ }
+
+ for (utf32 = 1, num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
+ num_to_read < 5 && (first_char & mask);
+ num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+ if (num_to_read > len) {
+ return -1;
+ }
+ if ((*cur & 0xC0) != 0x80) { /* can not be 10xxxxxx? */
+ return -1;
+ }
+ utf32 = (utf32 << 6) + (*cur++ & 0b00111111);
+ }
+ /* "first_char" must be (110xxxxx - 11110xxx) */
+ if (num_to_read >= 5) {
+ return -1;
+ }
+ to_ignore_mask |= mask;
+ utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
+ if (utf32 > kUnicodeMaxCodepoint) {
+ return -1;
+ }
+ return num_to_read;
+}
+
+/*
+ * Convert to printable from message to p buffer, return string length. If p is
+ * NULL, do not copy, but still return the expected string length.
+ */
+static size_t convertPrintable(char *p, const char *message, size_t messageLen)
+{
+ char *begin = p;
+ bool print = p != NULL;
+
+ while (messageLen) {
+ char buf[6];
+ ssize_t len = sizeof(buf) - 1;
+ if ((size_t)len > messageLen) {
+ len = messageLen;
+ }
+ len = utf8_character_length(message, len);
+
+ if (len < 0) {
+ snprintf(buf, sizeof(buf),
+ ((messageLen > 1) && isdigit(message[1]))
+ ? "\\%03o"
+ : "\\%o",
+ *message & 0377);
+ len = 1;
+ } else {
+ buf[0] = '\0';
+ if (len == 1) {
+ if (*message == '\a') {
+ strcpy(buf, "\\a");
+ } else if (*message == '\b') {
+ strcpy(buf, "\\b");
+ } else if (*message == '\t') {
+ strcpy(buf, "\\t");
+ } else if (*message == '\v') {
+ strcpy(buf, "\\v");
+ } else if (*message == '\f') {
+ strcpy(buf, "\\f");
+ } else if (*message == '\r') {
+ strcpy(buf, "\\r");
+ } else if (*message == '\\') {
+ strcpy(buf, "\\\\");
+ } else if ((*message < ' ') || (*message & 0x80)) {
+ snprintf(buf, sizeof(buf), "\\%o", *message & 0377);
+ }
+ }
+ if (!buf[0]) {
+ strncpy(buf, message, len);
+ buf[len] = '\0';
+ }
+ }
+ if (print) {
+ strcpy(p, buf);
+ }
+ p += strlen(buf);
+ message += len;
+ messageLen -= len;
+ }
+ return p - begin;
+}
+
/**
* Formats a log message into a buffer
*
@@ -778,7 +911,7 @@
#else
ptm = localtime(&(entry->tv_sec));
#endif
- //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+ /* strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm); */
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
len = strlen(timeBuf);
if (p_format->usec_time_output) {
@@ -873,24 +1006,34 @@
const char *pm;
if (prefixSuffixIsHeaderFooter) {
- // we're just wrapping message with a header/footer
+ /* we're just wrapping message with a header/footer */
numLines = 1;
} else {
pm = entry->message;
numLines = 0;
- // The line-end finding here must match the line-end finding
- // in for ( ... numLines...) loop below
+ /*
+ * The line-end finding here must match the line-end finding
+ * in for ( ... numLines...) loop below
+ */
while (pm < (entry->message + entry->messageLen)) {
if (*pm++ == '\n') numLines++;
}
- // plus one line for anything not newline-terminated at the end
+ /* plus one line for anything not newline-terminated at the end */
if (pm > entry->message && *(pm-1) != '\n') numLines++;
}
- // this is an upper bound--newlines in message may be counted
- // extraneously
- bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
+ /*
+ * this is an upper bound--newlines in message may be counted
+ * extraneously
+ */
+ bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
+ if (p_format->printable_output) {
+ /* Calculate extra length to convert non-printable to printable */
+ bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
+ } else {
+ bufferSize += entry->messageLen;
+ }
if (defaultBufferSize >= bufferSize) {
ret = defaultBuffer;
@@ -910,8 +1053,12 @@
if (prefixSuffixIsHeaderFooter) {
strcat(p, prefixBuf);
p += prefixLen;
- strncat(p, entry->message, entry->messageLen);
- p += entry->messageLen;
+ if (p_format->printable_output) {
+ p += convertPrintable(p, entry->message, entry->messageLen);
+ } else {
+ strncat(p, entry->message, entry->messageLen);
+ p += entry->messageLen;
+ }
strcat(p, suffixBuf);
p += suffixLen;
} else {
@@ -920,15 +1067,19 @@
size_t lineLen;
lineStart = pm;
- // Find the next end-of-line in message
+ /* Find the next end-of-line in message */
while (pm < (entry->message + entry->messageLen)
&& *pm != '\n') pm++;
lineLen = pm - lineStart;
strcat(p, prefixBuf);
p += prefixLen;
- strncat(p, lineStart, lineLen);
- p += lineLen;
+ if (p_format->printable_output) {
+ p += convertPrintable(p, lineStart, lineLen);
+ } else {
+ strncat(p, lineStart, lineLen);
+ p += lineLen;
+ }
strcat(p, suffixBuf);
p += suffixLen;
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 8582344..b2a9f88 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -30,6 +30,7 @@
#include <memory>
#include <vector>
+#include "base/file.h"
#include "base/macros.h" // TEMP_FAILURE_RETRY may or may not be in unistd
#include "base/memory.h"
#include "log/log.h"
@@ -85,7 +86,8 @@
// Length of the central directory comment.
uint16_t comment_length;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+ EocdRecord() = default;
+ DISALLOW_COPY_AND_ASSIGN(EocdRecord);
} __attribute__((packed));
// A structure representing the fixed length fields for a single
@@ -138,7 +140,8 @@
// beginning of this archive.
uint32_t local_file_header_offset;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+ CentralDirectoryRecord() = default;
+ DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord);
} __attribute__((packed));
// The local file header for a given entry. This duplicates information
@@ -175,7 +178,8 @@
// will appear immediately after the entry file name.
uint16_t extra_field_length;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+ LocalFileHeader() = default;
+ DISALLOW_COPY_AND_ASSIGN(LocalFileHeader);
} __attribute__((packed));
struct DataDescriptor {
@@ -189,10 +193,10 @@
// Uncompressed size of the entry.
uint32_t uncompressed_size;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+ DataDescriptor() = default;
+ DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
} __attribute__((packed));
-#undef DISALLOW_IMPLICIT_CONSTRUCTORS
static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
@@ -265,8 +269,6 @@
static const int32_t kErrorMessageLowerBound = -13;
-static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
-
/*
* A Read-only Zip archive.
*
@@ -324,35 +326,6 @@
}
};
-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];
-
- uint32_t count = 0;
- uint64_t crc = 0;
- while (count < length) {
- uint32_t remaining = length - count;
-
- // Safe conversion because kBufSize is narrow enough for a 32 bit signed
- // value.
- ssize_t get_size = (remaining > kBufSize) ? kBufSize : remaining;
- ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
-
- if (actual != get_size) {
- ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
- return kIoError;
- }
-
- memcpy(begin + count, buf, get_size);
- crc = crc32(crc, buf, get_size);
- count += get_size;
- }
-
- *crc_out = crc;
-
- return 0;
-}
-
/*
* Round up to the next highest power of 2.
*
@@ -972,6 +945,122 @@
return kIterationEnd;
}
+class Writer {
+ public:
+ virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
+ virtual ~Writer() {}
+ protected:
+ Writer() = default;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Writer);
+};
+
+// A Writer that writes data to a fixed size memory region.
+// The size of the memory region must be equal to the total size of
+// the data appended to it.
+class MemoryWriter : public Writer {
+ public:
+ MemoryWriter(uint8_t* buf, size_t size) : Writer(),
+ buf_(buf), size_(size), bytes_written_(0) {
+ }
+
+ virtual bool Append(uint8_t* buf, size_t buf_size) override {
+ if (bytes_written_ + buf_size > size_) {
+ ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+ size_, bytes_written_ + buf_size);
+ return false;
+ }
+
+ memcpy(buf_ + bytes_written_, buf, buf_size);
+ bytes_written_ += buf_size;
+ return true;
+ }
+
+ private:
+ uint8_t* const buf_;
+ const size_t size_;
+ size_t bytes_written_;
+};
+
+// A Writer that appends data to a file |fd| at its current position.
+// The file will be truncated to the end of the written data.
+class FileWriter : public Writer {
+ public:
+
+ // Creates a FileWriter for |fd| and prepare to write |entry| to it,
+ // guaranteeing that the file descriptor is valid and that there's enough
+ // space on the volume to write out the entry completely and that the file
+ // is truncated to the correct length.
+ //
+ // Returns a valid FileWriter on success, |nullptr| if an error occurred.
+ static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
+ const uint32_t declared_length = entry->uncompressed_length;
+ const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
+ if (current_offset == -1) {
+ ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
+ return nullptr;
+ }
+
+ int result = 0;
+#if defined(__linux__)
+ if (declared_length > 0) {
+ // Make sure we have enough space on the volume to extract the compressed
+ // entry. Note that the call to ftruncate below will change the file size but
+ // will not allocate space on disk and this call to fallocate will not
+ // change the file size.
+ // Note: fallocate is only supported by the following filesystems -
+ // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with
+ // EOPNOTSUPP error when issued in other filesystems.
+ // Hence, check for the return error code before concluding that the
+ // disk does not have enough space.
+ result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
+ if (result == -1 && errno == ENOSPC) {
+ ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+ return std::unique_ptr<FileWriter>(nullptr);
+ }
+ }
+#endif // __linux__
+
+ result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+ if (result == -1) {
+ ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+ return std::unique_ptr<FileWriter>(nullptr);
+ }
+
+ return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
+ }
+
+ virtual bool Append(uint8_t* buf, size_t buf_size) override {
+ if (total_bytes_written_ + buf_size > declared_length_) {
+ ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+ declared_length_, total_bytes_written_ + buf_size);
+ return false;
+ }
+
+ const bool result = android::base::WriteFully(fd_, buf, buf_size);
+ if (result) {
+ total_bytes_written_ += buf_size;
+ } else {
+ ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno));
+ }
+
+ return result;
+ }
+ private:
+ FileWriter(const int fd, const size_t declared_length) :
+ Writer(),
+ fd_(fd),
+ declared_length_(declared_length),
+ total_bytes_written_(0) {
+ }
+
+ const int fd_;
+ const size_t declared_length_;
+ size_t total_bytes_written_;
+};
+
// This method is using libz macros with old-style-casts
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -980,9 +1069,8 @@
}
#pragma GCC diagnostic pop
-static int32_t InflateToFile(int fd, const ZipEntry* entry,
- uint8_t* begin, uint32_t length,
- uint64_t* crc_out) {
+static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
+ Writer* writer, uint64_t* crc_out) {
const size_t kBufSize = 32768;
std::vector<uint8_t> read_buf(kBufSize);
std::vector<uint8_t> write_buf(kBufSize);
@@ -1027,7 +1115,6 @@
const uint32_t uncompressed_length = entry->uncompressed_length;
uint32_t compressed_length = entry->compressed_length;
- uint32_t write_count = 0;
do {
/* read as much as we can */
if (zstream.avail_in == 0) {
@@ -1057,12 +1144,10 @@
if (zstream.avail_out == 0 ||
(zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
const size_t write_size = zstream.next_out - &write_buf[0];
- // The file might have declared a bogus length.
- if (write_size + write_count > length) {
- return -1;
+ if (!writer->Append(&write_buf[0], write_size)) {
+ // The file might have declared a bogus length.
+ return kInconsistentInformation;
}
- memcpy(begin + write_count, &write_buf[0], write_size);
- write_count += write_size;
zstream.next_out = &write_buf[0];
zstream.avail_out = kBufSize;
@@ -1083,8 +1168,41 @@
return 0;
}
-int32_t ExtractToMemory(ZipArchiveHandle handle,
- ZipEntry* entry, uint8_t* begin, uint32_t size) {
+static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
+ uint64_t *crc_out) {
+ static const uint32_t kBufSize = 32768;
+ std::vector<uint8_t> buf(kBufSize);
+
+ const uint32_t length = entry->uncompressed_length;
+ uint32_t count = 0;
+ uint64_t crc = 0;
+ while (count < length) {
+ uint32_t remaining = length - count;
+
+ // Safe conversion because kBufSize is narrow enough for a 32 bit signed
+ // value.
+ const ssize_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
+ const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, &buf[0], block_size));
+
+ if (actual != block_size) {
+ ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, block_size);
+ return kIoError;
+ }
+
+ if (!writer->Append(&buf[0], block_size)) {
+ return kIoError;
+ }
+ crc = crc32(crc, &buf[0], block_size);
+ count += block_size;
+ }
+
+ *crc_out = crc;
+
+ return 0;
+}
+
+int32_t ExtractToWriter(ZipArchiveHandle handle,
+ ZipEntry* entry, Writer* writer) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
off64_t data_offset = entry->offset;
@@ -1098,9 +1216,9 @@
int32_t return_value = -1;
uint64_t crc = 0;
if (method == kCompressStored) {
- return_value = CopyFileToFile(archive->fd, begin, size, &crc);
+ return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
} else if (method == kCompressDeflated) {
- return_value = InflateToFile(archive->fd, entry, begin, size, &crc);
+ return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
}
if (!return_value && entry->has_data_descriptor) {
@@ -1120,55 +1238,20 @@
return return_value;
}
+int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
+ uint8_t* begin, uint32_t size) {
+ std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
+ return ExtractToWriter(handle, entry, writer.get());
+}
+
int32_t ExtractEntryToFile(ZipArchiveHandle handle,
ZipEntry* entry, int fd) {
- const uint32_t declared_length = entry->uncompressed_length;
-
- const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
- if (current_offset == -1) {
- ALOGW("Zip: unable to seek to current location on fd %d: %s", fd,
- strerror(errno));
+ std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
+ if (writer.get() == nullptr) {
return kIoError;
}
- int result = 0;
-#if defined(__linux__)
- // Make sure we have enough space on the volume to extract the compressed
- // entry. Note that the call to ftruncate below will change the file size but
- // will not allocate space on disk.
- if (declared_length > 0) {
- result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
- if (result == -1) {
- ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
- static_cast<int64_t>(declared_length + current_offset), strerror(errno));
- return kIoError;
- }
- }
-#endif // defined(__linux__)
-
- result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
- if (result == -1) {
- ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
- static_cast<int64_t>(declared_length + current_offset), strerror(errno));
- return kIoError;
- }
-
- // Don't attempt to map a region of length 0. We still need the
- // ftruncate() though, since the API guarantees that we will truncate
- // the file to the end of the uncompressed output.
- if (declared_length == 0) {
- return 0;
- }
-
- 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());
- return error;
+ return ExtractToWriter(handle, entry, writer.get());
}
const char* ErrorCodeString(int32_t error_code) {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 64faa6d..f8952ce 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <vector>
+#include <base/file.h>
#include <gtest/gtest.h>
static std::string test_data_dir;
@@ -228,6 +229,44 @@
0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
+// This is a zip file containing a single entry (ab.txt) that contains
+// 90072 repetitions of the string "ab\n" and has an uncompressed length
+// of 270216 bytes.
+static const uint16_t kAbZip[] = {
+ 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
+ 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
+ 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
+ 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
+ 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
+ 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
+ 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
+ 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
+ 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
+ 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
+ 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
+ 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
+};
+
+static const uint8_t kAbTxtName[] = { 'a', 'b', '.', 't', 'x', 't' };
+static const uint16_t kAbTxtNameLength = sizeof(kAbTxtName);
+static const size_t kAbUncompressedSize = 270216;
+
static int make_temporary_file(const char* file_name_pattern) {
char full_path[1024];
// Account for differences between the host and the target.
@@ -275,6 +314,55 @@
close(output_fd);
}
+TEST(ziparchive, EntryLargerThan32K) {
+ char temp_file_pattern[] = "entry_larger_than_32k_test_XXXXXX";
+ int fd = make_temporary_file(temp_file_pattern);
+ ASSERT_NE(-1, fd);
+ ASSERT_TRUE(android::base::WriteFully(fd, reinterpret_cast<const uint8_t*>(kAbZip),
+ sizeof(kAbZip) - 1));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFd(fd, "EntryLargerThan32KTest", &handle));
+
+ ZipEntry entry;
+ ZipEntryName ab_name;
+ ab_name.name = kAbTxtName;
+ ab_name.name_length = kAbTxtNameLength;
+ ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
+ ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
+
+ // Extract the entry to memory.
+ std::vector<uint8_t> buffer(kAbUncompressedSize);
+ ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
+
+ // Extract the entry to a file.
+ char output_file_pattern[] = "entry_larger_than_32k_test_output_XXXXXX";
+ int output_fd = make_temporary_file(output_file_pattern);
+ ASSERT_NE(-1, output_fd);
+ ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
+
+ // Make sure the extracted file size is as expected.
+ struct stat stat_buf;
+ ASSERT_EQ(0, fstat(output_fd, &stat_buf));
+ ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
+
+ // Read the file back to a buffer and make sure the contents are
+ // the same as the memory buffer we extracted directly to.
+ std::vector<uint8_t> file_contents(kAbUncompressedSize);
+ ASSERT_EQ(0, lseek64(output_fd, 0, SEEK_SET));
+ ASSERT_TRUE(android::base::ReadFully(output_fd, &file_contents[0], file_contents.size()));
+ ASSERT_EQ(file_contents, buffer);
+
+ for (int i = 0; i < 90072; ++i) {
+ const uint8_t* line = &file_contents[0] + (3 * i);
+ ASSERT_EQ('a', line[0]);
+ ASSERT_EQ('b', line[1]);
+ ASSERT_EQ('\n', line[2]);
+ }
+
+ close(fd);
+ close(output_fd);
+}
+
TEST(ziparchive, TrailerAfterEOCD) {
char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
int fd = make_temporary_file(temp_file_pattern);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 6d7740e..736e02e 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -253,7 +253,8 @@
" -r <kbytes> Rotate log every kbytes. Requires -f\n"
" -n <count> Sets max number of rotated logs to <count>, default 4\n"
" -v <format> Sets the log print format, where <format> is:\n\n"
- " brief color long process raw tag thread threadtime time usec\n\n"
+ " brief color long printable process raw tag thread\n"
+ " threadtime time usec\n\n"
" -D print dividers between each log buffer\n"
" -c clear (flush) the entire log and exit\n"
" -d dump the log and then exit (don't block)\n"
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 80fc9f5..4373e2a 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -281,7 +281,8 @@
}
void clear(LogBufferElement *e) {
- uint64_t current = e->getRealTime().nsec() - NS_PER_SEC;
+ uint64_t current = e->getRealTime().nsec()
+ - (EXPIRE_RATELIMIT * NS_PER_SEC);
for(LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
LogBufferElement *l = it->second;
if ((l->getDropped() >= EXPIRE_THRESHOLD)
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 3d7237e..8238a52 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -104,8 +104,8 @@
// assumption: mMsg == NULL
size_t LogBufferElement::populateDroppedMessage(char *&buffer,
LogBuffer *parent) {
- static const char tag[] = "logd";
- static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s";
+ static const char tag[] = "chatty";
+ static const char format_uid[] = "uid=%u%s%s expire %u line%s";
char *name = parent->uidToName(mUid);
char *commName = android::tidToName(mTid);
@@ -115,9 +115,15 @@
if (!commName) {
commName = parent->pidToName(mPid);
}
- if (name && commName && !strcmp(name, commName)) {
- free(commName);
- commName = NULL;
+ size_t len = name ? strlen(name) : 0;
+ if (len && commName && !strncmp(name, commName, len)) {
+ if (commName[len] == '\0') {
+ free(commName);
+ commName = NULL;
+ } else {
+ free(name);
+ name = NULL;
+ }
}
if (name) {
char *p = NULL;
@@ -129,16 +135,16 @@
}
if (commName) {
char *p = NULL;
- asprintf(&p, " comm=%s", commName);
+ asprintf(&p, " %s", commName);
if (p) {
free(commName);
commName = p;
}
}
// identical to below to calculate the buffer size required
- size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
- commName ? commName : "",
- mDropped, (mDropped > 1) ? "s" : "");
+ len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
+ commName ? commName : "",
+ mDropped, (mDropped > 1) ? "s" : "");
size_t hdrLen;
if (mLogId == LOG_ID_EVENTS) {
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 3dcf9d1..ca2c3a6 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -50,8 +50,9 @@
#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
// non-chatty UIDs less than this age in hours
-#define EXPIRE_THRESHOLD 4 // A smaller expire count is considered too
+#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
// chatty for the temporal expire messages
+#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
class LogBufferElement {
const log_id_t mLogId;
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index ec67c07..68a0680 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -31,6 +31,7 @@
mRelease(false),
mError(false),
threadRunning(false),
+ leadingDropped(false),
mReader(reader),
mLogMask(logMask),
mPid(pid),
@@ -123,6 +124,8 @@
bool privileged = FlushCommand::hasReadLogs(client);
+ me->leadingDropped = true;
+
lock();
while (me->threadRunning && !me->isError_Locked()) {
@@ -132,6 +135,7 @@
if (me->mTail) {
logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
+ me->leadingDropped = true;
}
start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
@@ -163,6 +167,14 @@
LogTimeEntry::lock();
+ if (me->leadingDropped) {
+ if (element->getDropped()) {
+ LogTimeEntry::unlock();
+ return false;
+ }
+ me->leadingDropped = false;
+ }
+
if (me->mCount == 0) {
me->mStart = element->getSequence();
}
@@ -190,6 +202,13 @@
goto skip;
}
+ if (me->leadingDropped) {
+ if (element->getDropped()) {
+ goto skip;
+ }
+ me->leadingDropped = false;
+ }
+
// Truncate to close race between first and second pass
if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
goto stop;
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index ae2f92b..783bce6 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -32,6 +32,7 @@
bool mRelease;
bool mError;
bool threadRunning;
+ bool leadingDropped;
pthread_cond_t threadTriggeredCondition;
pthread_t mThread;
LogReader &mReader;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b5ee98b..2fbac23 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -546,6 +546,7 @@
--fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
class core
socket vold stream 0660 root mount
+ socket cryptd stream 0660 root mount
ioprio be 2
service netd /system/bin/netd