Merge "Switch to the new bionic fatal logging interface."
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index b9b3c92..05ddf2a 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
   $(LOCAL_PATH)/../../extras/ext4_utils
-LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c
+LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
 LOCAL_CFLAGS += -std=gnu99
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 972c4ed..5a6709b 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -27,7 +27,7 @@
  */
 
 #include "fastboot.h"
-#include "make_ext4fs.h"
+#include "fs.h"
 
 #include <errno.h>
 #include <stdio.h>
@@ -51,9 +51,8 @@
 #define OP_COMMAND    2
 #define OP_QUERY      3
 #define OP_NOTICE     4
-#define OP_FORMAT     5
-#define OP_DOWNLOAD_SPARSE 6
-#define OP_WAIT_FOR_DISCONNECT 7
+#define OP_DOWNLOAD_SPARSE 5
+#define OP_WAIT_FOR_DISCONNECT 6
 
 typedef struct Action Action;
 
@@ -79,14 +78,7 @@
 static Action *action_last = 0;
 
 
-struct image_data {
-    long long partition_size;
-    long long image_size; // real size of image file
-    void *buffer;
-};
 
-void generate_ext4_image(struct image_data *image);
-void cleanup_image(struct image_data *image);
 
 int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...)
 {
@@ -102,24 +94,6 @@
     return fb_command_response(usb, cmd, response);
 }
 
-struct generator {
-    char *fs_type;
-
-    /* generate image and return it as image->buffer.
-     * size of the buffer returned as image->image_size.
-     *
-     * image->partition_size specifies what is the size of the
-     * file partition we generate image for.
-     */
-    void (*generate)(struct image_data *image);
-
-    /* it cleans the buffer allocated during image creation.
-     * this function probably does free() or munmap().
-     */
-    void (*cleanup)(struct image_data *image);
-} generators[] = {
-    { "ext4", generate_ext4_image, cleanup_image }
-};
 
 /* Return true if this partition is supported by the fastboot format command.
  * It is also used to determine if we should first erase a partition before
@@ -128,30 +102,20 @@
  * Not all devices report the filesystem type, so don't report any errors,
  * just return false.
  */
-int fb_format_supported(usb_handle *usb, const char *partition)
+int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override)
 {
-    char response[FB_RESPONSE_SZ+1];
-    struct generator *generator = NULL;
+    char fs_type[FB_RESPONSE_SZ + 1] = {0,};
     int status;
     unsigned int i;
 
-    status = fb_getvar(usb, response, "partition-type:%s", partition);
+    if (type_override) {
+        return !!fs_get_generator(type_override);
+    }
+    status = fb_getvar(usb, fs_type, "partition-type:%s", partition);
     if (status) {
         return 0;
     }
-
-    for (i = 0; i < ARRAY_SIZE(generators); i++) {
-        if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
-            generator = &generators[i];
-            break;
-        }
-    }
-
-    if (generator) {
-        return 1;
-    }
-
-    return 0;
+    return !!fs_get_generator(fs_type);
 }
 
 static int cb_default(Action *a, int status, char *resp)
@@ -205,163 +169,6 @@
     a->msg = mkmsg("erasing '%s'", ptn);
 }
 
-/* Loads file content into buffer. Returns NULL on error. */
-static void *load_buffer(int fd, off_t size)
-{
-    void *buffer;
-
-#ifdef USE_MINGW
-    ssize_t count = 0;
-
-    // mmap is more efficient but mingw does not support it.
-    // In this case we read whole image into memory buffer.
-    buffer = malloc(size);
-    if (!buffer) {
-        perror("malloc");
-        return NULL;
-    }
-
-    lseek(fd, 0, SEEK_SET);
-    while(count < size) {
-        ssize_t actually_read = read(fd, (char*)buffer+count, size-count);
-
-        if (actually_read == 0) {
-            break;
-        }
-        if (actually_read < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
-            perror("read");
-            free(buffer);
-            return NULL;
-        }
-
-        count += actually_read;
-    }
-#else
-    buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (buffer == MAP_FAILED) {
-        perror("mmap");
-        return NULL;
-    }
-#endif
-
-    return buffer;
-}
-
-void cleanup_image(struct image_data *image)
-{
-#ifdef USE_MINGW
-    free(image->buffer);
-#else
-    munmap(image->buffer, image->image_size);
-#endif
-}
-
-void generate_ext4_image(struct image_data *image)
-{
-    int fd;
-    struct stat st;
-
-    fd = fileno(tmpfile());
-    make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
-
-    fstat(fd, &st);
-    image->image_size = st.st_size;
-    image->buffer = load_buffer(fd, st.st_size);
-
-    close(fd);
-}
-
-int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
-{
-    const char *partition = a->cmd;
-    char response[FB_RESPONSE_SZ+1];
-    int status = 0;
-    struct image_data image;
-    struct generator *generator = NULL;
-    int fd;
-    unsigned i;
-    char cmd[CMD_SIZE];
-
-    status = fb_getvar(usb, response, "partition-type:%s", partition);
-    if (status) {
-        if (skip_if_not_supported) {
-            fprintf(stderr,
-                    "Erase successful, but not automatically formatting.\n");
-            fprintf(stderr,
-                    "Can't determine partition type.\n");
-            return 0;
-        }
-        fprintf(stderr,"FAILED (%s)\n", fb_get_error());
-        return status;
-    }
-
-    for (i = 0; i < ARRAY_SIZE(generators); i++) {
-        if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
-            generator = &generators[i];
-            break;
-        }
-    }
-    if (!generator) {
-        if (skip_if_not_supported) {
-            fprintf(stderr,
-                    "Erase successful, but not automatically formatting.\n");
-            fprintf(stderr,
-                    "File system type %s not supported.\n", response);
-            return 0;
-        }
-        fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
-                response);
-        return -1;
-    }
-
-    status = fb_getvar(usb, response, "partition-size:%s", partition);
-    if (status) {
-        if (skip_if_not_supported) {
-            fprintf(stderr,
-                    "Erase successful, but not automatically formatting.\n");
-            fprintf(stderr, "Unable to get partition size\n.");
-            return 0;
-        }
-        fprintf(stderr,"FAILED (%s)\n", fb_get_error());
-        return status;
-    }
-    image.partition_size = strtoll(response, (char **)NULL, 16);
-
-    generator->generate(&image);
-    if (!image.buffer) {
-        fprintf(stderr,"Cannot generate image.\n");
-        return -1;
-    }
-
-    // Following piece of code is similar to fb_queue_flash() but executes
-    // actions directly without queuing
-    fprintf(stderr, "sending '%s' (%lli KB)...\n", partition, image.image_size/1024);
-    status = fb_download_data(usb, image.buffer, image.image_size);
-    if (status) goto cleanup;
-
-    fprintf(stderr, "writing '%s'...\n", partition);
-    snprintf(cmd, sizeof(cmd), "flash:%s", partition);
-    status = fb_command(usb, cmd);
-    if (status) goto cleanup;
-
-cleanup:
-    generator->cleanup(&image);
-
-    return status;
-}
-
-void fb_queue_format(const char *partition, int skip_if_not_supported)
-{
-    Action *a;
-
-    a = queue_action(OP_FORMAT, partition);
-    a->data = (void*)skip_if_not_supported;
-    a->msg = mkmsg("formatting '%s' partition", partition);
-}
-
 void fb_queue_flash(const char *ptn, void *data, unsigned sz)
 {
     Action *a;
@@ -589,10 +396,6 @@
             if (status) break;
         } else if (a->op == OP_NOTICE) {
             fprintf(stderr,"%s\n",(char*)a->data);
-        } else if (a->op == OP_FORMAT) {
-            status = fb_format(a, usb, (int)a->data);
-            status = a->func(a, status, status ? fb_get_error() : "");
-            if (status) break;
         } else if (a->op == OP_DOWNLOAD_SPARSE) {
             status = fb_download_data_sparse(usb, a->data);
             status = a->func(a, status, status ? fb_get_error() : "");
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 7d26c6f..4d3e0af 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -33,6 +33,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
+
 #include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -49,6 +50,7 @@
 #include <zipfile/zipfile.h>
 
 #include "fastboot.h"
+#include "fs.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -99,10 +101,11 @@
     char sig_name[13];
     char part_name[9];
     bool is_optional;
-} images[3] = {
+} images[4] = {
     {"boot.img", "boot.sig", "boot", false},
     {"recovery.img", "recovery.sig", "recovery", true},
     {"system.img", "system.sig", "system", false},
+    {"tos.img", "tos.sig", "tos", true},
 };
 
 void get_my_path(char *path);
@@ -119,6 +122,8 @@
         fn = "recovery.img";
     } else if(!strcmp(item,"system")) {
         fn = "system.img";
+    } else if(!strcmp(item,"tos")) {
+        fn = "tos.img";
     } else if(!strcmp(item,"userdata")) {
         fn = "userdata.img";
     } else if(!strcmp(item,"cache")) {
@@ -284,10 +289,13 @@
             "\n"
             "commands:\n"
             "  update <filename>                        reflash device from update.zip\n"
-            "  flashall                                 flash boot + recovery + system\n"
+            "  flashall                                 flash boot, system, and if found,\n"
+            "                                           recovery, tos\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
             "  erase <partition>                        erase a flash partition\n"
-            "  format <partition>                       format a flash partition \n"
+            "  format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
+            "                                           Can override the fs type and/or\n"
+            "                                           size the bootloader reports.\n"
             "  getvar <variable>                        display a bootloader variable\n"
             "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
             "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
@@ -308,10 +316,12 @@
             "  -p <product>                             specify product name\n"
             "  -c <cmdline>                             override kernel commandline\n"
             "  -i <vendor id>                           specify a custom USB vendor id\n"
-            "  -b <base_addr>                           specify a custom kernel base address. default: 0x10000000\n"
-            "  -n <page size>                           specify the nand page size. default: 2048\n"
-            "  -S <size>[K|M|G]                         automatically sparse files greater than\n"
-            "                                           size.  0 to disable\n"
+            "  -b <base_addr>                           specify a custom kernel base address.\n"
+            "                                           default: 0x10000000\n"
+            "  -n <page size>                           specify the nand page size.\n"
+            "                                           default: 2048\n"
+            "  -S <size>[K|M|G]                         automatically sparse files greater\n"
+            "                                           than size.  0 to disable\n"
         );
 }
 
@@ -612,7 +622,7 @@
     /* The function fb_format_supported() currently returns the value
      * we want, so just call it.
      */
-     return fb_format_supported(usb, part);
+     return fb_format_supported(usb, part, NULL);
 }
 
 static int load_buf_fd(usb_handle *usb, int fd,
@@ -622,10 +632,13 @@
     void *data;
     int64_t limit;
 
+
     sz64 = file_size(fd);
     if (sz64 < 0) {
         return -1;
     }
+
+    lseek(fd, 0, SEEK_SET);
     limit = get_sparse_limit(usb, sz64);
     if (limit) {
         struct sparse_file **s = load_sparse_files(fd, limit);
@@ -653,7 +666,7 @@
 
     fd = open(fname, O_RDONLY | O_BINARY);
     if (fd < 0) {
-        die("cannot open '%s'\n", fname);
+        return -1;
     }
 
     return load_buf_fd(usb, fd, buf);
@@ -872,6 +885,92 @@
     return num;
 }
 
+void fb_perform_format(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];
+    char *pType = pTypeBuff;
+    char *pSize = pSizeBuff;
+    unsigned int limit = INT_MAX;
+    struct fastboot_buffer buf;
+    const char *errMsg = NULL;
+    const struct fs_generator *gen;
+    uint64_t pSz;
+    int status;
+    int fd;
+
+    if (target_sparse_limit > 0 && target_sparse_limit < limit)
+        limit = target_sparse_limit;
+    if (sparse_limit > 0 && sparse_limit < limit)
+        limit = sparse_limit;
+
+    status = fb_getvar(usb, pType, "partition-type:%s", partition);
+    if (status) {
+        errMsg = "Can't determine partition type.\n";
+        goto failed;
+    }
+    if (type_override) {
+        if (strcmp(type_override, pType)) {
+            fprintf(stderr,
+                    "Warning: %s type is %s, but %s was requested for formating.\n",
+                    partition, pType, type_override);
+        }
+        pType = type_override;
+    }
+
+    status = fb_getvar(usb, pSize, "partition-size:%s", partition);
+    if (status) {
+        errMsg = "Unable to get partition size\n";
+        goto failed;
+    }
+    if (size_override) {
+        if (strcmp(size_override, pSize)) {
+            fprintf(stderr,
+                    "Warning: %s size is %s, but %s was requested for formating.\n",
+                    partition, pSize, size_override);
+        }
+        pSize = size_override;
+    }
+
+    gen = fs_get_generator(pType);
+    if (!gen) {
+        if (skip_if_not_supported) {
+            fprintf(stderr, "Erase successful, but not automatically formatting.\n");
+            fprintf(stderr, "File system type %s not supported.\n", pType);
+            return;
+        }
+        fprintf(stderr, "Formatting is not supported for filesystem with type '%s'.\n", pType);
+        return;
+    }
+
+    pSz = strtoll(pSize, (char **)NULL, 16);
+
+    fd = fileno(tmpfile());
+    if (fs_generator_generate(gen, fd, pSz)) {
+        close(fd);
+        fprintf(stderr, "Cannot generate image.\n");
+        return;
+    }
+
+    if (load_buf_fd(usb, fd, &buf)) {
+        fprintf(stderr, "Cannot read image.\n");
+        close(fd);
+        return;
+    }
+    flash_buf(partition, &buf);
+
+    return;
+
+
+failed:
+    if (skip_if_not_supported) {
+        fprintf(stderr, "Erase successful, but not automatically formatting.\n");
+        if (errMsg)
+            fprintf(stderr, "%s", errMsg);
+    }
+    fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+}
+
 int main(int argc, char **argv)
 {
     int wants_wipe = 0;
@@ -993,18 +1092,42 @@
         } else if(!strcmp(*argv, "erase")) {
             require(2);
 
-            if (fb_format_supported(usb, argv[1])) {
+            if (fb_format_supported(usb, argv[1], NULL)) {
                 fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
             }
 
             fb_queue_erase(argv[1]);
             skip(2);
-        } else if(!strcmp(*argv, "format")) {
+        } else if(!strncmp(*argv, "format", strlen("format"))) {
+            char *overrides;
+            char *type_override = NULL;
+            char *size_override = NULL;
             require(2);
+            /*
+             * Parsing for: "format[:[type][:[size]]]"
+             * Some valid things:
+             *  - select ontly the size, and leave default fs type:
+             *    format::0x4000000 userdata
+             *  - default fs type and size:
+             *    format userdata
+             *    format:: userdata
+             */
+            overrides = strchr(*argv, ':');
+            if (overrides) {
+                overrides++;
+                size_override = strchr(overrides, ':');
+                if (size_override) {
+                    size_override[0] = '\0';
+                    size_override++;
+                }
+                type_override = overrides;
+            }
+            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])) {
                 fb_queue_erase(argv[1]);
             }
-            fb_queue_format(argv[1], 0);
+            fb_perform_format(argv[1], 0, type_override, size_override);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -1092,9 +1215,9 @@
 
     if (wants_wipe) {
         fb_queue_erase("userdata");
-        fb_queue_format("userdata", 1);
+        fb_perform_format("userdata", 1, NULL, NULL);
         fb_queue_erase("cache");
-        fb_queue_format("cache", 1);
+        fb_perform_format("cache", 1, NULL, NULL);
     }
     if (wants_reboot) {
         fb_queue_reboot();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 976c397..fc5d4f4 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -45,11 +45,11 @@
 
 /* engine.c - high level command queue engine */
 int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...);
-int fb_format_supported(usb_handle *usb, const char *partition);
+int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override);
 void fb_queue_flash(const char *ptn, void *data, unsigned sz);
 void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz);
 void fb_queue_erase(const char *ptn);
-void fb_queue_format(const char *ptn, int skip_if_not_supported);
+void fb_queue_format(const char *ptn, int skip_if_not_supported, unsigned int max_chunk_sz);
 void fb_queue_require(const char *prod, const char *var, int invert,
         unsigned nvalues, const char **value);
 void fb_queue_display(const char *var, const char *prettyname);
diff --git a/fastboot/fs.c b/fastboot/fs.c
new file mode 100644
index 0000000..cd4b880
--- /dev/null
+++ b/fastboot/fs.c
@@ -0,0 +1,56 @@
+#include "fastboot.h"
+#include "make_ext4fs.h"
+#include "fs.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sparse/sparse.h>
+#include <unistd.h>
+
+#ifdef USE_MINGW
+#include <fcntl.h>
+#else
+#include <sys/mman.h>
+#endif
+
+
+
+static int generate_ext4_image(int fd, long long partSize)
+{
+    make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+
+    return 0;
+}
+
+static const struct fs_generator {
+
+    char *fs_type;  //must match what fastboot reports for partition type
+    int (*generate)(int fd, long long partSize); //returns 0 or error value
+
+} generators[] = {
+
+    { "ext4", generate_ext4_image}
+
+};
+
+const struct fs_generator* fs_get_generator(const char *fs_type)
+{
+    unsigned i;
+
+    for (i = 0; i < sizeof(generators) / sizeof(*generators); i++)
+        if (!strcmp(generators[i].fs_type, fs_type))
+            return generators + i;
+
+    return NULL;
+}
+
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
+{
+    return gen->generate(tmpFileNo, partSize);
+}
diff --git a/fastboot/fs.h b/fastboot/fs.h
new file mode 100644
index 0000000..8388629
--- /dev/null
+++ b/fastboot/fs.h
@@ -0,0 +1,12 @@
+#ifndef _FS_H_
+#define _FH_H_
+
+#include <stdint.h>
+
+struct fs_generator;
+
+const struct fs_generator* fs_get_generator(const char *fs_type);
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
+
+#endif
+
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 07f7be2..f666015 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -152,7 +152,7 @@
 }
 
 int usb_write(usb_handle* handle, const void* data, int len) {
-    unsigned long time_out = 500 + len * 8;
+    unsigned long time_out = 5000;
     unsigned long written = 0;
     unsigned count = 0;
     int ret;
@@ -194,7 +194,7 @@
 }
 
 int usb_read(usb_handle *handle, void* data, int len) {
-    unsigned long time_out = 500 + len * 8;
+    unsigned long time_out = 0;
     unsigned long read = 0;
     int ret;
 
@@ -212,7 +212,7 @@
             DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
             if (ret) {
                 return read;
-            } else if (errno != ERROR_SEM_TIMEOUT) {
+            } else {
                 // assume ERROR_INVALID_HANDLE indicates we are disconnected
                 if (errno == ERROR_INVALID_HANDLE)
                     usb_kick(handle);
diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c
index 7659632..5d0ee62 100644
--- a/libdiskconfig/diskutils.c
+++ b/libdiskconfig/diskutils.c
@@ -41,7 +41,7 @@
     int done = 0;
     uint64_t total = 0;
 
-    ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, offset);
+    ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, (unsigned long long)offset);
     if ((src_fd = open(src, O_RDONLY)) < 0) {
         ALOGE("Could not open %s for reading (errno=%d).", src, errno);
         goto fail;
@@ -54,7 +54,7 @@
         }
 
         if (lseek64(dst_fd, offset, SEEK_SET) != offset) {
-            ALOGE("Could not seek to offset %lld in %s.", offset, dst);
+            ALOGE("Could not seek to offset %lld in %s.", (long long)offset, dst);
             goto fail;
         }
     }
@@ -102,7 +102,7 @@
     if (dst_fd >= 0)
         fsync(dst_fd);
 
-    ALOGI("Wrote %" PRIu64 " bytes to %s @ %lld", total, dst, offset);
+    ALOGI("Wrote %" PRIu64 " bytes to %s @ %lld", total, dst, (long long)offset);
 
     close(src_fd);
     if (dst_fd >= 0)
diff --git a/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c
index 826ef7a..90b1c82 100644
--- a/libdiskconfig/write_lst.c
+++ b/libdiskconfig/write_lst.c
@@ -71,18 +71,18 @@
 {
     for(; lst; lst = lst->next) {
         if (lseek64(fd, lst->offset, SEEK_SET) != (loff_t)lst->offset) {
-            ALOGE("Cannot seek to the specified position (%lld).", lst->offset);
+            ALOGE("Cannot seek to the specified position (%lld).", (long long)lst->offset);
             goto fail;
         }
 
         if (!test) {
             if (write(fd, lst->data, lst->len) != (int)lst->len) {
                 ALOGE("Failed writing %u bytes at position %lld.", lst->len,
-                     lst->offset);
+                     (long long)lst->offset);
                 goto fail;
             }
         } else
-            ALOGI("Would write %d bytes @ offset %lld.", lst->len, lst->offset);
+            ALOGI("Would write %d bytes @ offset %lld.", lst->len, (long long)lst->offset);
     }
 
     return 0;
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index ea46345..db4fddd 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -281,6 +281,30 @@
     return 0;
 }
 
+static const char multipliers[][2] = {
+    { "" },
+    { "K" },
+    { "M" },
+    { "G" }
+};
+
+static unsigned long value_of_size(unsigned long value)
+{
+    for (unsigned i = 0;
+            (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
+            value /= 1024, ++i) ;
+    return value;
+}
+
+static const char *multiplier_of_size(unsigned long value)
+{
+    unsigned i;
+    for (i = 0;
+            (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
+            value /= 1024, ++i) ;
+    return multipliers[i];
+}
+
 int main(int argc, char **argv)
 {
     int err;
@@ -715,9 +739,10 @@
                 exit(EXIT_FAILURE);
             }
 
-            printf("%s: ring buffer is %ldKb (%ldKb consumed), "
+            printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
                    "max entry is %db, max payload is %db\n", dev->device,
-                   size / 1024, readable / 1024,
+                   value_of_size(size), multiplier_of_size(size),
+                   value_of_size(readable), multiplier_of_size(readable),
                    (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
         }
 
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 38a237c..dc9d47e 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -14,29 +14,68 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <cutils/properties.h>
 #include <log/logger.h>
 
 #include "LogBuffer.h"
+#include "LogReader.h"
 #include "LogStatistics.h"
 #include "LogWhiteBlackList.h"
-#include "LogReader.h"
 
 // Default
 #define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
 #define log_buffer_size(id) mMaxSize[id]
 
+static unsigned long property_get_size(const char *key) {
+    char property[PROPERTY_VALUE_MAX];
+    property_get(key, property, "");
+
+    char *cp;
+    unsigned long value = strtoul(property, &cp, 10);
+
+    switch(*cp) {
+    case 'm':
+    case 'M':
+        value *= 1024;
+    /* FALLTHRU */
+    case 'k':
+    case 'K':
+        value *= 1024;
+    /* FALLTHRU */
+    case '\0':
+        break;
+
+    default:
+        value = 0;
+    }
+
+    return value;
+}
+
 LogBuffer::LogBuffer(LastLogTimes *times)
         : mTimes(*times) {
     pthread_mutex_init(&mLogElementsLock, NULL);
     dgram_qlen_statistics = false;
 
+    static const char global_default[] = "persist.logd.size";
+    unsigned long default_size = property_get_size(global_default);
+
     log_id_for_each(i) {
-        mMaxSize[i] = LOG_BUFFER_SIZE;
+        setSize(i, LOG_BUFFER_SIZE);
+        setSize(i, default_size);
+
+        char key[PROP_NAME_MAX];
+        snprintf(key, sizeof(key), "%s.%s",
+                 global_default, android_log_id_to_name(i));
+
+        setSize(i, property_get_size(key));
     }
 }
 
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index c6c7b23..e87b604 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -47,7 +47,7 @@
 }
 
 PruneList::PruneList()
-        : mWorstUidEnabled(true) {
+        : mWorstUidEnabled(false) {
     mNaughty.clear();
     mNice.clear();
 }
@@ -65,7 +65,7 @@
 }
 
 int PruneList::init(char *str) {
-    mWorstUidEnabled = true;
+    mWorstUidEnabled = false;
     PruneCollection::iterator it;
     for (it = mNice.begin(); it != mNice.end();) {
         delete (*it);
diff --git a/logd/README.property b/logd/README.property
index 5d92d09..f4b3c3c 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -10,3 +10,16 @@
                                          minimum domain socket network FIFO
                                          size (see source for details) based
                                          on typical load (logcat -S to view)
+persist.logd.size          number 256K   default size of the buffer for all
+                                         log ids at initial startup, at runtime
+                                         use: logcat -b all -G <value>
+persist.logd.size.main     number 256K   Size of the buffer for the main log
+persist.logd.size.system   number 256K   Size of the buffer for the system log
+persist.logd.size.radio    number 256K   Size of the buffer for the radio log
+persist.logd.size.event    number 256K   Size of the buffer for the event log
+persist.logd.size.crash    number 256K   Size of the buffer for the crash log
+
+NB:
+- number support multipliers (K or M) for convenience. Range is limited
+  to between 64K and 256M for log buffer sizes. Individual logs override the
+  global default.