Merge "Add "fastboot --version"."
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index c36313b..4e935e6 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;
@@ -619,7 +618,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.
@@ -744,7 +743,7 @@
         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);
@@ -799,7 +798,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);
@@ -867,7 +866,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];
@@ -1074,7 +1074,7 @@
         return 0;
     }
 
-    usb = open_device();
+    usb_handle* usb = open_device();
 
     while (argc > 0) {
         if(!strcmp(*argv, "getvar")) {
@@ -1116,10 +1116,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);
@@ -1179,7 +1179,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);
@@ -1234,9 +1234,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/init/init.cpp b/init/init.cpp
index 60fcf64..2500985 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -380,7 +380,8 @@
 
     if ((svc->flags & SVC_EXEC) != 0) {
         INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
-             svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel);
+             svc->pid, svc->uid, svc->gid, svc->nr_supp_gids,
+             svc->seclabel ? : "default");
         waiting_for_exec = true;
     }
 
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index df049ed..f975b6c 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -664,6 +664,7 @@
 
 service* make_exec_oneshot_service(int nargs, char** args) {
     // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
+    // SECLABEL can be a - to denote default
     int command_arg = 1;
     for (int i = 1; i < nargs; ++i) {
         if (strcmp(args[i], "--") == 0) {
@@ -689,7 +690,7 @@
         return NULL;
     }
 
-    if (command_arg > 2) {
+    if ((command_arg > 2) && strcmp(args[1], "-")) {
         svc->seclabel = args[1];
     }
     if (command_arg > 3) {
diff --git a/init/readme.txt b/init/readme.txt
index 6b9c42d..c213041 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -180,7 +180,7 @@
    Fork and execute command with the given arguments. The command starts
    after "--" so that an optional security context, user, and supplementary
    groups can be provided. No other commands will be run until this one
-   finishes.
+   finishes. <seclabel> can be a - to denote default.
 
 export <name> <value>
    Set the environment variable <name> equal to <value> in the
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 50742df..9d5ea0e 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -22,7 +22,7 @@
 
 #include <log/log_read.h>
 
-const char log_time::default_format[] = "%m-%d %H:%M:%S.%3q";
+const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
 const timespec log_time::EPOCH = { 0, 0 };
 
 // Add %#q for fractional seconds to standard strptime function
diff --git a/logcat/Android.mk b/logcat/Android.mk
index f46a4de..7115f9b 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -5,7 +5,7 @@
 
 LOCAL_SRC_FILES:= logcat.cpp event.logtags
 
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 
 LOCAL_MODULE := logcat
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 2c2d785..6d7740e 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,29 +1,38 @@
 // Copyright 2006-2015 The Android Open Source Project
 
+#include <arpa/inet.h>
 #include <assert.h>
 #include <ctype.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <math.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
 #include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <unistd.h>
 #include <sys/cdefs.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
-#include <arpa/inet.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
+#include <memory>
+#include <string>
+
+#include <base/file.h>
+#include <base/strings.h>
+#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
+#include <log/event_tag_map.h>
 #include <log/log.h>
 #include <log/log_read.h>
-#include <log/logger.h>
 #include <log/logd.h>
+#include <log/logger.h>
 #include <log/logprint.h>
-#include <log/event_tag_map.h>
 
 #define DEFAULT_MAX_ROTATED_LOGS 4
 
@@ -202,7 +211,15 @@
         g_outFD = STDOUT_FILENO;
 
     } else {
-        struct stat statbuf;
+        if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+            fprintf(stderr, "failed to set background scheduling policy\n");
+        }
+
+        struct sched_param param;
+        memset(&param, 0, sizeof(param));
+        if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
+            fprintf(stderr, "failed to set to batch scheduler\n");
+        }
 
         g_outFD = openLogFile (g_outputFileName);
 
@@ -210,6 +227,7 @@
             logcat_panic(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");
@@ -231,7 +249,7 @@
     fprintf(stderr, "options include:\n"
                     "  -s              Set default filter to silent.\n"
                     "                  Like specifying filterspec '*:S'\n"
-                    "  -f <filename>   Log to file. Default to stdout\n"
+                    "  -f <filename>   Log to file. Default is stdout\n"
                     "  -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"
@@ -352,6 +370,86 @@
     exit(EXIT_FAILURE);
 }
 
+static const char g_defaultTimeFormat[] = "%m-%d %H:%M:%S.%q";
+
+// Find last logged line in gestalt of all matching existing output files
+static log_time lastLogTime(char *outputFileName) {
+    log_time retval(log_time::EPOCH);
+    if (!outputFileName) {
+        return retval;
+    }
+
+    log_time now(CLOCK_REALTIME);
+
+    std::string directory;
+    char *file = strrchr(outputFileName, '/');
+    if (!file) {
+        directory = ".";
+        file = outputFileName;
+    } else {
+        *file = '\0';
+        directory = outputFileName;
+        *file = '/';
+        ++file;
+    }
+    size_t len = strlen(file);
+    log_time modulo(0, NS_PER_SEC);
+    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(directory.c_str()), closedir);
+    struct dirent *dp;
+    while ((dp = readdir(dir.get())) != NULL) {
+        if ((dp->d_type != DT_REG)
+                || strncmp(dp->d_name, file, len)
+                || (dp->d_name[len]
+                    && ((dp->d_name[len] != '.')
+                        || !isdigit(dp->d_name[len+1])))) {
+            continue;
+        }
+
+        std::string file_name = directory;
+        file_name += "/";
+        file_name += dp->d_name;
+        std::string file;
+        if (!android::base::ReadFileToString(file_name, &file)) {
+            continue;
+        }
+
+        bool found = false;
+        for (const auto& line : android::base::Split(file, "\n")) {
+            log_time t(log_time::EPOCH);
+            char *ep = t.strptime(line.c_str(), g_defaultTimeFormat);
+            if (!ep || (*ep != ' ')) {
+                continue;
+            }
+            // determine the time precision of the logs (eg: msec or usec)
+            for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
+                if (t.tv_nsec % (mod * 10)) {
+                    modulo.tv_nsec = mod;
+                    break;
+                }
+            }
+            // We filter any times later than current as we may not have the
+            // year stored with each log entry. Also, since it is possible for
+            // entries to be recorded out of order (very rare) we select the
+            // maximum we find just in case.
+            if ((t < now) && (t > retval)) {
+                retval = t;
+                found = true;
+            }
+        }
+        // We count on the basename file to be the definitive end, so stop here.
+        if (!dp->d_name[len] && found) {
+            break;
+        }
+    }
+    if (retval == log_time::EPOCH) {
+        return retval;
+    }
+    // tail_time prints matching or higher, round up by the modulo to prevent
+    // a replay of the last entry we have just checked.
+    retval += modulo;
+    return retval;
+}
+
 } /* namespace android */
 
 
@@ -417,12 +515,11 @@
                 /* FALLTHRU */
             case 'T':
                 if (strspn(optarg, "0123456789") != strlen(optarg)) {
-                    char *cp = tail_time.strptime(optarg,
-                                                  log_time::default_format);
+                    char *cp = tail_time.strptime(optarg, g_defaultTimeFormat);
                     if (!cp) {
                         logcat_panic(false,
                                     "-%c \"%s\" not in \"%s\" time format\n",
-                                    ret, optarg, log_time::default_format);
+                                    ret, optarg, g_defaultTimeFormat);
                     }
                     if (*cp) {
                         char c = *cp;
@@ -545,9 +642,11 @@
             break;
 
             case 'f':
+                if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
+                    tail_time = lastLogTime(optarg);
+                }
                 // redirect output to a file
                 g_outputFileName = optarg;
-
             break;
 
             case 'r':
diff --git a/logd/Android.mk b/logd/Android.mk
index 73da8dc..615d030 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -41,4 +41,15 @@
 
 include $(BUILD_EXECUTABLE)
 
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := logpersist.start
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(bin_dir)
+LOCAL_SRC_FILES := logpersist
+ALL_TOOLS := logpersist.start logpersist.stop logpersist.cat
+LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(filter-out $(LOCAL_MODULE),$(ALL_TOOLS)),ln -sf $(LOCAL_MODULE) $(TARGET_OUT)/bin/$(t);)
+include $(BUILD_PREBUILT)
+
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/README.property b/logd/README.property
index ad7d0cd..a472efd 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -10,6 +10,8 @@
                                          default false
 ro.build.type               string       if user, logd.statistics & logd.klogd
                                          default false
+persist.logd.logpersistd    string       Enable logpersist daemon, "logcatd"
+                                         turns on logcat -f in logd context
 persist.logd.size          number 256K   default size of the buffer for all
                                          log ids at initial startup, at runtime
                                          use: logcat -b all -G <value>
diff --git a/logd/logpersist b/logd/logpersist
new file mode 100755
index 0000000..215e1e2
--- /dev/null
+++ b/logd/logpersist
@@ -0,0 +1,36 @@
+#! /system/bin/sh
+# logpersist cat start and stop handlers
+data=/data/misc/logd
+property=persist.logd.logpersistd
+service=logcatd
+progname="${0##*/}"
+if [ X"${1}" = "-h" -o X"${1}" = X"--help" ]; then
+  echo "${progname%.*}.cat            - dump current ${service%d} logs"
+  echo "${progname%.*}.start          - start ${service} service"
+  echo "${progname%.*}.stop [--clear] - stop ${service} service"
+  exit 0
+fi
+case ${progname} in
+*.cat)
+  su 1036 ls "${data}" |
+  tr -d '\r' |
+  sort -ru |
+  sed "s#^#${data}/#" |
+  su 1036 xargs cat
+  ;;
+*.start)
+  su 0 setprop ${property} ${service}
+  getprop ${property}
+  sleep 1
+  ps -t | grep "${data##*/}.*${service%d}"
+  ;;
+*.stop)
+  su 0 stop ${service}
+  su 0 setprop ${property} ""
+  [ X"${1}" != X"-c" -a X"${1}" != X"--clear" ] ||
+  ( sleep 1 ; su 1036,9998 rm -rf "${data}" )
+  ;;
+*)
+  echo "Unexpected command ${0##*/} ${@}" >&2
+  exit 1
+esac
diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk
index 0c9b0c6..8661d7d 100644
--- a/mkbootimg/Android.mk
+++ b/mkbootimg/Android.mk
@@ -2,12 +2,10 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := mkbootimg.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-LOCAL_CFLAGS := -Werror
+LOCAL_SRC_FILES := mkbootimg
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_IS_HOST_MODULE := true
 
 LOCAL_MODULE := mkbootimg
 
-include $(BUILD_HOST_EXECUTABLE)
-
-$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
+include $(BUILD_PREBUILT)
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
new file mode 100755
index 0000000..1e09f4d
--- /dev/null
+++ b/mkbootimg/mkbootimg
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# Copyright 2015, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+from sys import argv, exit, stderr
+from argparse import ArgumentParser, FileType, Action
+from os import fstat
+from struct import pack
+from hashlib import sha1
+
+def filesize(f):
+    if f is None:
+        return 0
+    try:
+        return fstat(f.fileno()).st_size
+    except OSError:
+        return 0
+
+
+def update_sha(sha, f):
+    if f:
+        sha.update(f.read())
+        f.seek(0)
+        sha.update(pack('I', filesize(f)))
+    else:
+        sha.update(pack('I', 0))
+
+
+def pad_file(f, padding):
+    pad = (padding - (f.tell() & (padding - 1))) & (padding - 1)
+    f.write(pack(str(pad) + 'x'))
+
+
+def write_header(args):
+    BOOT_MAGIC = 'ANDROID!'.encode()
+    args.output.write(pack('8s', BOOT_MAGIC))
+    args.output.write(pack('8I',
+        filesize(args.kernel),                          # size in bytes
+        args.base + args.kernel_offset,                 # physical load addr
+        filesize(args.ramdisk),                         # size in bytes
+        args.base + args.ramdisk_offset,                # physical load addr
+        filesize(args.second),                          # size in bytes
+        args.base + args.second_offset,                 # physical load addr
+        args.base + args.tags_offset,                   # physical addr for kernel tags
+        args.pagesize))                                 # flash page size we assume
+    args.output.write(pack('8x'))                       # future expansion: should be 0
+    args.output.write(pack('16s', args.board.encode())) # asciiz product name
+    args.output.write(pack('512s', args.cmdline[:512].encode()))
+
+    sha = sha1()
+    update_sha(sha, args.kernel)
+    update_sha(sha, args.ramdisk)
+    update_sha(sha, args.second)
+    img_id = pack('32s', sha.digest())
+
+    args.output.write(img_id)
+    args.output.write(pack('1024s', args.cmdline[512:].encode()))
+    pad_file(args.output, args.pagesize)
+    return img_id
+
+
+class ValidateStrLenAction(Action):
+    def __init__(self, option_strings, dest, nargs=None, **kwargs):
+        if 'maxlen' not in kwargs:
+            raise ValueError('maxlen must be set')
+        self.maxlen = int(kwargs['maxlen'])
+        del kwargs['maxlen']
+        super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        if len(values) > self.maxlen:
+            raise ValueError('String argument too long: max {0:d}, got {1:d}'.
+                format(self.maxlen, len(values)))
+        setattr(namespace, self.dest, values)
+
+
+def write_padded_file(f_out, f_in, padding):
+    if f_in is None:
+        return
+    f_out.write(f_in.read())
+    pad_file(f_out, padding)
+
+
+def parse_int(x):
+    return int(x,0)
+
+
+def parse_cmdline():
+    parser = ArgumentParser()
+    parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'),
+                        required=True)
+    parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
+    parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
+    parser.add_argument('--cmdline', help='extra arguments to be passed on the '
+                        'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
+    parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
+    parser.add_argument('----kernel_offset', help='kernel offset', type=parse_int, default=0x00008000)
+    parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000)
+    parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
+                        default=0x00f00000)
+    parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
+    parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
+                        maxlen=16)
+    parser.add_argument('--pagesize', help='page size', type=parse_int,
+                        choices=[2**i for i in range(11,15)], default=2048)
+    parser.add_argument('--id', help='print the image ID on standard output',
+                        action='store_true')
+    parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'),
+                        required=True)
+    return parser.parse_args()
+
+
+def write_data(args):
+    write_padded_file(args.output, args.kernel, args.pagesize)
+    write_padded_file(args.output, args.ramdisk, args.pagesize)
+    write_padded_file(args.output, args.second, args.pagesize)
+
+
+def main():
+    args = parse_cmdline()
+    img_id = write_header(args)
+    write_data(args)
+    if args.id:
+        print('0x' + ''.join('{:02x}'.format(ord(c)) for c in img_id))
+
+
+if __name__ == '__main__':
+    main()
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
deleted file mode 100644
index 40e5261..0000000
--- a/mkbootimg/mkbootimg.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* tools/mkbootimg/mkbootimg.c
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdbool.h>
-
-#include "mincrypt/sha.h"
-#include "bootimg.h"
-
-static void *load_file(const char *fn, unsigned *_sz)
-{
-    char *data;
-    int sz;
-    int fd;
-
-    data = 0;
-    fd = open(fn, O_RDONLY);
-    if(fd < 0) return 0;
-
-    sz = lseek(fd, 0, SEEK_END);
-    if(sz < 0) goto oops;
-
-    if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
-
-    data = (char*) malloc(sz);
-    if(data == 0) goto oops;
-
-    if(read(fd, data, sz) != sz) goto oops;
-    close(fd);
-
-    if(_sz) *_sz = sz;
-    return data;
-
-oops:
-    close(fd);
-    if(data != 0) free(data);
-    return 0;
-}
-
-int usage(void)
-{
-    fprintf(stderr,"usage: mkbootimg\n"
-            "       --kernel <filename>\n"
-            "       --ramdisk <filename>\n"
-            "       [ --second <2ndbootloader-filename> ]\n"
-            "       [ --cmdline <kernel-commandline> ]\n"
-            "       [ --board <boardname> ]\n"
-            "       [ --base <address> ]\n"
-            "       [ --pagesize <pagesize> ]\n"
-            "       [ --id ]\n"
-            "       -o|--output <filename>\n"
-            );
-    return 1;
-}
-
-
-
-static unsigned char padding[16384] = { 0, };
-
-static void print_id(const uint8_t *id, size_t id_len) {
-    printf("0x");
-    for (unsigned i = 0; i < id_len; i++) {
-        printf("%02x", id[i]);
-    }
-    printf("\n");
-}
-
-int write_padding(int fd, unsigned pagesize, unsigned itemsize)
-{
-    unsigned pagemask = pagesize - 1;
-    ssize_t count;
-
-    if((itemsize & pagemask) == 0) {
-        return 0;
-    }
-
-    count = pagesize - (itemsize & pagemask);
-
-    if(write(fd, padding, count) != count) {
-        return -1;
-    } else {
-        return 0;
-    }
-}
-
-int main(int argc, char **argv)
-{
-    boot_img_hdr hdr;
-
-    char *kernel_fn = NULL;
-    void *kernel_data = NULL;
-    char *ramdisk_fn = NULL;
-    void *ramdisk_data = NULL;
-    char *second_fn = NULL;
-    void *second_data = NULL;
-    char *cmdline = "";
-    char *bootimg = NULL;
-    char *board = "";
-    uint32_t pagesize = 2048;
-    int fd;
-    SHA_CTX ctx;
-    const uint8_t* sha;
-    uint32_t base           = 0x10000000U;
-    uint32_t kernel_offset  = 0x00008000U;
-    uint32_t ramdisk_offset = 0x01000000U;
-    uint32_t second_offset  = 0x00f00000U;
-    uint32_t tags_offset    = 0x00000100U;
-    size_t cmdlen;
-
-    argc--;
-    argv++;
-
-    memset(&hdr, 0, sizeof(hdr));
-
-    bool get_id = false;
-    while(argc > 0){
-        char *arg = argv[0];
-        if (!strcmp(arg, "--id")) {
-            get_id = true;
-            argc -= 1;
-            argv += 1;
-        } else if(argc >= 2) {
-            char *val = argv[1];
-            argc -= 2;
-            argv += 2;
-            if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
-                bootimg = val;
-            } else if(!strcmp(arg, "--kernel")) {
-                kernel_fn = val;
-            } else if(!strcmp(arg, "--ramdisk")) {
-                ramdisk_fn = val;
-            } else if(!strcmp(arg, "--second")) {
-                second_fn = val;
-            } else if(!strcmp(arg, "--cmdline")) {
-                cmdline = val;
-            } else if(!strcmp(arg, "--base")) {
-                base = strtoul(val, 0, 16);
-            } else if(!strcmp(arg, "--kernel_offset")) {
-                kernel_offset = strtoul(val, 0, 16);
-            } else if(!strcmp(arg, "--ramdisk_offset")) {
-                ramdisk_offset = strtoul(val, 0, 16);
-            } else if(!strcmp(arg, "--second_offset")) {
-                second_offset = strtoul(val, 0, 16);
-            } else if(!strcmp(arg, "--tags_offset")) {
-                tags_offset = strtoul(val, 0, 16);
-            } else if(!strcmp(arg, "--board")) {
-                board = val;
-            } else if(!strcmp(arg,"--pagesize")) {
-                pagesize = strtoul(val, 0, 10);
-                if ((pagesize != 2048) && (pagesize != 4096)
-                    && (pagesize != 8192) && (pagesize != 16384)) {
-                    fprintf(stderr,"error: unsupported page size %d\n", pagesize);
-                    return -1;
-                }
-            } else {
-                return usage();
-            }
-        } else {
-            return usage();
-        }
-    }
-    hdr.page_size = pagesize;
-
-    hdr.kernel_addr =  base + kernel_offset;
-    hdr.ramdisk_addr = base + ramdisk_offset;
-    hdr.second_addr =  base + second_offset;
-    hdr.tags_addr =    base + tags_offset;
-
-    if(bootimg == 0) {
-        fprintf(stderr,"error: no output filename specified\n");
-        return usage();
-    }
-
-    if(kernel_fn == 0) {
-        fprintf(stderr,"error: no kernel image specified\n");
-        return usage();
-    }
-
-    if(ramdisk_fn == 0) {
-        fprintf(stderr,"error: no ramdisk image specified\n");
-        return usage();
-    }
-
-    if(strlen(board) >= BOOT_NAME_SIZE) {
-        fprintf(stderr,"error: board name too large\n");
-        return usage();
-    }
-
-    strcpy((char *) hdr.name, board);
-
-    memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
-
-    cmdlen = strlen(cmdline);
-    if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) {
-        fprintf(stderr,"error: kernel commandline too large\n");
-        return 1;
-    }
-    /* Even if we need to use the supplemental field, ensure we
-     * are still NULL-terminated */
-    strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1);
-    hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0';
-    if (cmdlen >= (BOOT_ARGS_SIZE - 1)) {
-        cmdline += (BOOT_ARGS_SIZE - 1);
-        strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE);
-    }
-
-    kernel_data = load_file(kernel_fn, &hdr.kernel_size);
-    if(kernel_data == 0) {
-        fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
-        return 1;
-    }
-
-    if(!strcmp(ramdisk_fn,"NONE")) {
-        ramdisk_data = 0;
-        hdr.ramdisk_size = 0;
-    } else {
-        ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);
-        if(ramdisk_data == 0) {
-            fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn);
-            return 1;
-        }
-    }
-
-    if(second_fn) {
-        second_data = load_file(second_fn, &hdr.second_size);
-        if(second_data == 0) {
-            fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn);
-            return 1;
-        }
-    }
-
-    /* put a hash of the contents in the header so boot images can be
-     * differentiated based on their first 2k.
-     */
-    SHA_init(&ctx);
-    SHA_update(&ctx, kernel_data, hdr.kernel_size);
-    SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
-    SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
-    SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
-    SHA_update(&ctx, second_data, hdr.second_size);
-    SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
-    sha = SHA_final(&ctx);
-    memcpy(hdr.id, sha,
-           SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
-
-    fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
-    if(fd < 0) {
-        fprintf(stderr,"error: could not create '%s'\n", bootimg);
-        return 1;
-    }
-
-    if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
-    if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
-
-    if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail;
-    if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
-
-    if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail;
-    if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
-
-    if(second_data) {
-        if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail;
-        if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
-    }
-
-    if (get_id) {
-        print_id((uint8_t *) hdr.id, sizeof(hdr.id));
-    }
-
-    return 0;
-
-fail:
-    unlink(bootimg);
-    close(fd);
-    fprintf(stderr,"error: failed writing '%s': %s\n", bootimg,
-            strerror(errno));
-    return 1;
-}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0966038..1f421c5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -649,3 +649,17 @@
     class late_start
     user root
     oneshot
+
+on property:persist.logd.logpersistd=logcatd
+    # all exec/services are called with umask(077), so no gain beyond 0700
+    mkdir /data/misc/logd 0700 logd log
+    # logd for write to /data/misc/logd, log group for read from pstore (-L)
+    exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+    start logcatd
+
+service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+    class late_start
+    disabled
+    # logd for write to /data/misc/logd, log group for read from log daemon
+    user logd
+    group log
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index cd8d350..50944e6 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -1,6 +1,6 @@
 ## Permissions to allow system-wide tracing to the kernel trace buffer.
 ##
-on early-boot
+on boot
 
 # Allow writing to the kernel trace log.
     chmod 0222 /sys/kernel/debug/tracing/trace_marker