Merge "Add wall-clock timing for each fastboot Action."
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b65
--- /dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/adb/adb.h b/adb/adb.h
index a148019..aaf8a28 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -33,7 +33,7 @@
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    25    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    26    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
diff --git a/adb/commandline.c b/adb/commandline.c
index 0352cf2..857cee3 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -105,8 +105,8 @@
         "                                 environment variable is used, which must\n"
         "                                 be an absolute path.\n"
         " devices                       - list all connected devices\n"
-        " connect <host>:<port>         - connect to a device via TCP/IP"
-        " disconnect <host>:<port>      - disconnect from a TCP/IP device"
+        " connect <host>:<port>         - connect to a device via TCP/IP\n"
+        " disconnect <host>:<port>      - disconnect from a TCP/IP device\n"
         "\n"
         "device commands:\n"
         "  adb push <local> <remote>    - copy file/dir to device\n"
@@ -221,8 +221,8 @@
             if(errno == EINTR) continue;
             break;
         }
-        /* we want to output to stdout, so no adb_write here !! */
-        unix_write(1, buf, len);
+        fwrite(buf, 1, len, stdout);
+        fflush(stdout);
     }
 }
 
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 66ee317..bb86813 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -21,6 +21,7 @@
 
 #include <sys/ioctl.h>
 #include <sys/types.h>
+#include <sys/time.h>
 #include <dirent.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -287,6 +288,8 @@
 {
     struct usbdevfs_urb *urb = &h->urb_out;
     int res;
+    struct timeval tv;
+    struct timespec ts;
 
     memset(urb, 0, sizeof(*urb));
     urb->type = USBDEVFS_URB_TYPE_BULK;
@@ -313,8 +316,12 @@
     res = -1;
     h->urb_out_busy = 1;
     for(;;) {
-        adb_cond_wait(&h->notify, &h->lock);
-        if(h->dead) {
+        /* time out after five seconds */
+        gettimeofday(&tv, NULL);
+        ts.tv_sec = tv.tv_sec + 5;
+        ts.tv_nsec = tv.tv_usec * 1000L;
+        res = pthread_cond_timedwait(&h->notify, &h->lock, &ts);
+        if(res < 0 || h->dead) {
             break;
         }
         if(h->urb_out_busy == 0) {
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 866e3af..fd34052 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -61,6 +61,8 @@
 #define VENDOR_ID_GARMIN_ASUS   0x091E
 // Sharp's USB Vendor ID
 #define VENDOR_ID_SHARP         0x04dd
+// ZTE's USB Vendor ID
+#define VENDOR_ID_ZTE           0x19D2
 
 /** built-in vendor list */
 int builtInVendorIds[] = {
@@ -77,6 +79,7 @@
     VENDOR_ID_NVIDIA,
     VENDOR_ID_GARMIN_ASUS,
     VENDOR_ID_SHARP,
+    VENDOR_ID_ZTE,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index b86f2a5..3c1cf02 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -9,6 +9,13 @@
 LOCAL_CFLAGS := -Wall
 LOCAL_MODULE := debuggerd
 
+ifeq ($(ARCH_ARM_HAVE_VFP),true)
+LOCAL_CFLAGS += -DWITH_VFP
+endif # ARCH_ARM_HAVE_VFP
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_CFLAGS += -DWITH_VFP_D32
+endif # ARCH_ARM_HAVE_VFP_D32
+
 LOCAL_STATIC_LIBRARIES := libcutils libc
 
 include $(BUILD_EXECUTABLE)
@@ -23,14 +30,20 @@
 LOCAL_SHARED_LIBRARIES := libcutils libc
 include $(BUILD_EXECUTABLE)
 
-ifeq ($(TARGET_ARCH_VARIANT),armv7-a)
+ifeq ($(ARCH_ARM_HAVE_VFP),true)
 include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -DWITH_VFP
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_CFLAGS += -DWITH_VFP_D32
+endif # ARCH_ARM_HAVE_VFP_D32
+
 LOCAL_SRC_FILES := vfp-crasher.c vfp.S
 LOCAL_MODULE := vfp-crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := eng
 LOCAL_SHARED_LIBRARIES := libcutils libc
 include $(BUILD_EXECUTABLE)
-endif # TARGET_ARCH_VARIANT == armv7-a
+endif # ARCH_ARM_HAVE_VFP == true
 
 endif # TARGET_ARCH == arm
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 7b987cf..e850a2e 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -42,6 +42,14 @@
 
 #include "utility.h"
 
+#ifdef WITH_VFP
+#ifdef WITH_VFP_D32
+#define NUM_VFP_REGS 32
+#else
+#define NUM_VFP_REGS 16
+#endif
+#endif
+
 /* Main entry point to get the backtrace from the crashing process */
 extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
                                         unsigned int sp_list[],
@@ -278,7 +286,7 @@
          " ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
          r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr);
 
-#if __ARM_NEON__
+#ifdef WITH_VFP
     struct user_vfp vfp_regs;
     int i;
 
@@ -288,7 +296,7 @@
         return;
     }
 
-    for (i = 0; i < 32; i += 2) {
+    for (i = 0; i < NUM_VFP_REGS; i += 2) {
         _LOG(tfd, only_in_tombstone,
              " d%-2d %016llx  d%-2d %016llx\n",
               i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
diff --git a/debuggerd/vfp.S b/debuggerd/vfp.S
index 2192415..9744f6f 100644
--- a/debuggerd/vfp.S
+++ b/debuggerd/vfp.S
@@ -19,6 +19,7 @@
     fconstd   d13, #13
     fconstd   d14, #14
     fconstd   d15, #15
+#ifdef WITH_VFP_D32
     fconstd   d16, #16
     fconstd   d17, #17
     fconstd   d18, #18
@@ -35,6 +36,7 @@
     fconstd   d29, #29
     fconstd   d30, #30
     fconstd   d31, #31
+#endif
     mov       r0, #0
     str       r0, [r0]
     bx        lr
diff --git a/include/cutils/iosched_policy.h b/include/cutils/iosched_policy.h
new file mode 100644
index 0000000..07c5d1f
--- /dev/null
+++ b/include/cutils/iosched_policy.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef __CUTILS_IOSCHED_POLICY_H
+#define __CUTILS_IOSCHED_POLICY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    IoSchedClass_NONE,
+    IoSchedClass_RT,
+    IoSchedClass_BE,
+    IoSchedClass_IDLE,
+} IoSchedClass;
+
+extern int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio);
+extern int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_IOSCHED_POLICY_H */ 
diff --git a/include/cutils/log.h b/include/cutils/log.h
index ec3cac8..dd47c35 100644
--- a/include/cutils/log.h
+++ b/include/cutils/log.h
@@ -196,6 +196,91 @@
 #define IF_LOGE() IF_LOG(LOG_ERROR, LOG_TAG)
 #endif
 
+
+// ---------------------------------------------------------------------
+
+/*
+ * Simplified macro to send a verbose system log message using the current LOG_TAG.
+ */
+#ifndef SLOGV
+#if LOG_NDEBUG
+#define SLOGV(...)   ((void)0)
+#else
+#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#define CONDITION(cond)     (__builtin_expect((cond)!=0, 0))
+
+#ifndef SLOGV_IF
+#if LOG_NDEBUG
+#define SLOGV_IF(cond, ...)   ((void)0)
+#else
+#define SLOGV_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug system log message using the current LOG_TAG.
+ */
+#ifndef SLOGD
+#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGD_IF
+#define SLOGD_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an info system log message using the current LOG_TAG.
+ */
+#ifndef SLOGI
+#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGI_IF
+#define SLOGI_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send a warning system log message using the current LOG_TAG.
+ */
+#ifndef SLOGW
+#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGW_IF
+#define SLOGW_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+/*
+ * Simplified macro to send an error system log message using the current LOG_TAG.
+ */
+#ifndef SLOGE
+#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef SLOGE_IF
+#define SLOGE_IF(cond, ...) \
+    ( (CONDITION(cond)) \
+    ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
+    : (void)0 )
+#endif
+
+    
+
 // ---------------------------------------------------------------------
 
 /*
@@ -338,6 +423,21 @@
 #define android_logToFile(tag, file) (0)
 #define android_logToFd(tag, fd) (0)
 
+typedef enum {
+    LOG_ID_MAIN = 0,
+    LOG_ID_RADIO = 1,
+    LOG_ID_EVENTS = 2,
+    LOG_ID_SYSTEM = 3,
+
+    LOG_ID_MAX
+} log_id_t;
+
+/*
+ * Send a simple string to the log.
+ */
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
+
 
 #ifdef __cplusplus
 }
diff --git a/include/cutils/logger.h b/include/cutils/logger.h
index 3a08019..b60f7ad 100644
--- a/include/cutils/logger.h
+++ b/include/cutils/logger.h
@@ -25,6 +25,7 @@
 #define LOGGER_LOG_MAIN		"log/main"
 #define LOGGER_LOG_RADIO	"log/radio"
 #define LOGGER_LOG_EVENTS	"log/events"
+#define LOGGER_LOG_SYSTEM	"log/system"
 
 #define LOGGER_ENTRY_MAX_LEN		(4*1024)
 #define LOGGER_ENTRY_MAX_PAYLOAD	\
diff --git a/include/cutils/logprint.h b/include/cutils/logprint.h
index d6ec480..769c8a7 100644
--- a/include/cutils/logprint.h
+++ b/include/cutils/logprint.h
@@ -142,7 +142,7 @@
  * Assumes single threaded execution
  *
  */
-int android_log_filterAndPrintLogLine(
+int android_log_printLogLine(
     AndroidLogFormat *p_format,
     int fd,
     const AndroidLogEntry *entry);
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 24b7c81..49fa912 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -156,9 +156,10 @@
     { 00550, AID_ROOT,      AID_SHELL,     "system/etc/init.testmenu" },
     { 00550, AID_DHCP,      AID_SHELL,     "system/etc/dhcpcd/dhcpcd-run-hooks" },
     { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/dbus.conf" },
-    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/main.conf" },
-    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/input.conf" },
-    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluez/audio.conf" },
+    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/main.conf" },
+    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/input.conf" },
+    { 00440, AID_BLUETOOTH, AID_BLUETOOTH, "system/etc/bluetooth/audio.conf" },
+    { 00640, AID_SYSTEM,    AID_SYSTEM,    "system/etc/bluetooth/auto_pairing.conf" },
     { 00444, AID_RADIO,     AID_AUDIO,     "system/etc/AudioPara4.csv" },
     { 00555, AID_ROOT,      AID_ROOT,      "system/etc/ppp/*" },
     { 00644, AID_SYSTEM,    AID_SYSTEM,    "data/app/*" },
@@ -167,7 +168,7 @@
         /* the following two files are INTENTIONALLY set-gid and not set-uid.
          * Do not change. */
     { 02755, AID_ROOT,      AID_NET_RAW,   "system/bin/ping" },
-    { 02755, AID_ROOT,      AID_INET,      "system/bin/netcfg" },
+    { 02750, AID_ROOT,      AID_INET,      "system/bin/netcfg" },
     	/* the following four files are INTENTIONALLY set-uid, but they
 	 * are NOT included on user builds. */
     { 06755, AID_ROOT,      AID_ROOT,      "system/xbin/su" },
diff --git a/include/sysutils/FrameworkListener.h b/include/sysutils/FrameworkListener.h
index 4e3d396..142f50c 100644
--- a/include/sysutils/FrameworkListener.h
+++ b/include/sysutils/FrameworkListener.h
@@ -23,7 +23,7 @@
 
 class FrameworkListener : public SocketListener {
 public:
-    static const int CMD_ARGS_MAX = 8;
+    static const int CMD_ARGS_MAX = 16;
 private:
     FrameworkCommandCollection *mCommands;
 
diff --git a/init/init.c b/init/init.c
index 16a3530..4d98cc2 100755
--- a/init/init.c
+++ b/init/init.c
@@ -35,6 +35,7 @@
 #include <sys/reboot.h>
 
 #include <cutils/sockets.h>
+#include <cutils/iosched_policy.h>
 #include <termios.h>
 #include <linux/kd.h>
 #include <linux/keychord.h>
@@ -224,6 +225,13 @@
             }
         }
 
+        if (svc->ioprio_class != IoSchedClass_NONE) {
+            if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
+                ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
+                      getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
+            }
+        }
+
         if (needs_console) {
             setsid();
             open_console();
diff --git a/init/init.h b/init/init.h
index 60c3055..8c0571c 100644
--- a/init/init.h
+++ b/init/init.h
@@ -146,6 +146,9 @@
     int nkeycodes;
     int keychord_id;
 
+    int ioprio_class;
+    int ioprio_pri;
+
     int nargs;
     /* "MUST BE AT THE END OF THE STRUCT" */
     char *args[1];
diff --git a/init/keywords.h b/init/keywords.h
index 308118e..254c785 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -75,6 +75,7 @@
     KEYWORD(chmod,       COMMAND, 2, do_chmod)
     KEYWORD(loglevel,    COMMAND, 1, do_loglevel)
     KEYWORD(device,      COMMAND, 4, do_device)
+    KEYWORD(ioprio,      OPTION,  0, 0)
 #ifdef __MAKE_KEYWORD_ENUM__
     KEYWORD_COUNT,
 };
diff --git a/init/parser.c b/init/parser.c
index 54622cc..7da0d19 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -10,6 +10,8 @@
 #include "init.h"
 #include "property_service.h"
 
+#include <cutils/iosched_policy.h>
+
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
@@ -155,6 +157,7 @@
         if (!strcmp(s, "ostname")) return K_hostname;
         break;
     case 'i':
+        if (!strcmp(s, "oprio")) return K_ioprio;
         if (!strcmp(s, "fup")) return K_ifup;
         if (!strcmp(s, "nsmod")) return K_insmod;
         if (!strcmp(s, "mport")) return K_import;
@@ -619,6 +622,8 @@
         return;
     }
     
+    svc->ioprio_class = IoSchedClass_NONE;
+
     kw = lookup_keyword(args[0]);
     switch (kw) {
     case K_capability:
@@ -636,6 +641,28 @@
     case K_disabled:
         svc->flags |= SVC_DISABLED;
         break;
+    case K_ioprio:
+        if (nargs != 3) {
+            parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
+        } else {
+            svc->ioprio_pri = strtoul(args[2], 0, 8);
+
+            if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
+                parse_error(state, "priority value must be range 0 - 7\n");
+                break;
+            }
+
+            if (!strcmp(args[1], "rt")) {
+                svc->ioprio_class = IoSchedClass_RT;
+            } else if (!strcmp(args[1], "be")) {
+                svc->ioprio_class = IoSchedClass_BE;
+            } else if (!strcmp(args[1], "idle")) {
+                svc->ioprio_class = IoSchedClass_IDLE;
+            } else {
+                parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
+            }
+        }
+        break;
     case K_group:
         if (nargs < 2) {
             parse_error(state, "group option requires a group id\n");
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 93933e2..4c45cc9 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -38,7 +38,8 @@
 	process_name.c \
 	properties.c \
 	threads.c \
-	sched_policy.c
+	sched_policy.c \
+	iosched_policy.c
 
 commonHostSources := \
         ashmem-host.c
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
new file mode 100644
index 0000000..f350f58
--- /dev/null
+++ b/libcutils/iosched_policy.c
@@ -0,0 +1,67 @@
+
+/* libs/cutils/iosched_policy.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 <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SCHED_H
+
+#include <cutils/iosched_policy.h>
+
+extern int ioprio_set(int which, int who, int ioprio);
+
+enum {
+    WHO_PROCESS = 1,
+    WHO_PGRP,
+    WHO_USER,
+};
+
+#define CLASS_SHIFT 13
+#define IOPRIO_NORM 4
+
+int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio) {
+#ifdef HAVE_ANDROID_OS
+    if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) {
+        return -1;
+    }
+#endif
+    return 0;
+}
+
+int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio) {
+#ifdef HAVE_ANDROID_OS
+    int rc;
+
+    if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) {
+        return -1;
+    }
+
+    *clazz = (rc >> CLASS_SHIFT);
+    *ioprio = (rc & 0xff);
+#else
+    *clazz = IoSchedClass_NONE;
+    *ioprio = 0;
+#endif
+    return 0;
+}
+
+#endif /* HAVE_SCHED_H */
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 8134aa1..2333762 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -90,8 +90,9 @@
 /*
  * Try to get the scheduler group.
  *
- * The data from /proc/<pid>/cgroup looks like:
+ * The data from /proc/<pid>/cgroup looks (something) like:
  *  2:cpu:/bg_non_interactive
+ *  1:cpuacct:/
  *
  * We return the part after the "/", which will be an empty string for
  * the default cgroup.  If the string is longer than "bufLen", the string
@@ -101,34 +102,57 @@
 {
 #ifdef HAVE_ANDROID_OS
     char pathBuf[32];
-    char readBuf[256];
-    ssize_t count;
-    int fd;
+    char lineBuf[256];
+    FILE *fp;
 
     snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
-    if ((fd = open(pathBuf, O_RDONLY)) < 0) {
+    if (!(fp = fopen(pathBuf, "r"))) {
         return -1;
     }
 
-    count = read(fd, readBuf, sizeof(readBuf));
-    if (count <= 0) {
-        close(fd);
-        errno = ENODATA;
-        return -1;
-    }
-    close(fd);
+    while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
+        char *next = lineBuf;
+        char *subsys;
+        char *grp;
+        size_t len;
 
-    readBuf[--count] = '\0';    /* remove the '\n', now count==strlen */
+        /* Junk the first field */
+        if (!strsep(&next, ":")) {
+            goto out_bad_data;
+        }
 
-    char* cp = strchr(readBuf, '/');
-    if (cp == NULL) {
-        readBuf[sizeof(readBuf)-1] = '\0';
-        errno = ENODATA;
-        return -1;
+        if (!(subsys = strsep(&next, ":"))) {
+            goto out_bad_data;
+        }
+
+        if (strcmp(subsys, "cpu")) {
+            /* Not the subsys we're looking for */
+            continue;
+        }
+
+        if (!(grp = strsep(&next, ":"))) {
+            goto out_bad_data;
+        }
+        grp++; /* Drop the leading '/' */
+        len = strlen(grp);
+        grp[len-1] = '\0'; /* Drop the trailing '\n' */
+
+        if (bufLen <= len) {
+            len = bufLen - 1;
+        }
+        strncpy(buf, grp, len);
+        buf[len] = '\0';
+        fclose(fp);
+        return 0;
     }
 
-    memcpy(buf, cp+1, count);   /* count-1 for cp+1, count+1 for NUL */
-    return 0;
+    LOGE("Failed to find cpu subsys");
+    fclose(fp);
+    return -1;
+ out_bad_data:
+    LOGE("Bad cgroup data {%s}", lineBuf);
+    fclose(fp);
+    return -1;
 #else
     errno = ENOSYS;
     return -1;
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 241dbf0..9923bba 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -27,6 +27,7 @@
 
 #include <cutils/logger.h>
 #include <cutils/logd.h>
+#include <cutils/log.h>
 
 #define LOG_BUF_SIZE	1024
 
@@ -41,21 +42,13 @@
 #define log_close(filedes) close(filedes)
 #endif
 
-typedef enum {
-    LOG_ID_MAIN = 0,
-    LOG_ID_RADIO,
-    LOG_ID_EVENTS,
-    LOG_ID_MAX
-} log_id_t;
-
 static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
-static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) =
-    __write_to_log_init;
+static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
 #ifdef HAVE_PTHREADS
 static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
 #endif
 
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1 };
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
 
 /*
  * This is used by the C++ code to decide if it should write logs through
@@ -110,6 +103,7 @@
         log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
         log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
         log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
+        log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
 
         write_to_log = __write_to_log_kernel;
 
@@ -123,6 +117,10 @@
             log_fds[LOG_ID_EVENTS] = -1;
             write_to_log = __write_to_log_null;
         }
+
+        if (log_fds[LOG_ID_SYSTEM] < 0) {
+            log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
+        }
     }
 
 #ifdef HAVE_PTHREADS
@@ -161,6 +159,34 @@
     return write_to_log(log_id, vec, 3);
 }
 
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
+{
+    struct iovec vec[3];
+
+    if (!tag)
+        tag = "";
+
+    /* XXX: This needs to go! */
+    if (!strcmp(tag, "HTC_RIL") ||
+        !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+        !strcmp(tag, "AT") ||
+        !strcmp(tag, "GSM") ||
+        !strcmp(tag, "STK") ||
+        !strcmp(tag, "CDMA") ||
+        !strcmp(tag, "PHONE") ||
+        !strcmp(tag, "SMS"))
+            bufID = LOG_ID_RADIO;
+
+    vec[0].iov_base   = (unsigned char *) &prio;
+    vec[0].iov_len    = 1;
+    vec[1].iov_base   = (void *) tag;
+    vec[1].iov_len    = strlen(tag) + 1;
+    vec[2].iov_base   = (void *) msg;
+    vec[2].iov_len    = strlen(msg) + 1;
+
+    return write_to_log(bufID, vec, 3);
+}
+
 int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)
 {
     char buf[LOG_BUF_SIZE];    
@@ -173,7 +199,7 @@
 int __android_log_print(int prio, const char *tag, const char *fmt, ...)
 {
     va_list ap;
-    char buf[LOG_BUF_SIZE];    
+    char buf[LOG_BUF_SIZE];
 
     va_start(ap, fmt);
     vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
@@ -182,6 +208,18 @@
     return __android_log_write(prio, tag, buf);
 }
 
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+
+    va_start(ap, fmt);
+    vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+    va_end(ap);
+
+    return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
 void __android_log_assert(const char *cond, const char *tag,
 			  const char *fmt, ...)
 {
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 080f9e3..4c5b3e5 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -753,6 +753,16 @@
             suffixLen = 1;
             break;
     }
+    /* snprintf has a weird return value.   It returns what would have been
+     * written given a large enough buffer.  In the case that the prefix is
+     * longer then our buffer(128), it messes up the calculations below
+     * possibly causing heap corruption.  To avoid this we double check and
+     * set the length at the maximum (size minus null byte)
+     */
+    if(prefixLen >= sizeof(prefixBuf))
+        prefixLen = sizeof(prefixBuf) - 1;
+    if(suffixLen >= sizeof(suffixBuf))
+        suffixLen = sizeof(suffixBuf) - 1;
 
     /* the following code is tragically unreadable */
 
@@ -840,7 +850,7 @@
  * Returns count bytes written
  */
 
-int android_log_filterAndPrintLogLine(
+int android_log_printLogLine(
     AndroidLogFormat *p_format,
     int fd,
     const AndroidLogEntry *entry)
@@ -850,11 +860,6 @@
     char *outBuffer = NULL;
     size_t totalLen;
 
-    if (0 == android_log_shouldPrintLine(p_format, entry->tag,
-            entry->priority)) {
-        return 0;
-    }
-
     outBuffer = android_log_formatLogLine(p_format, defaultBuffer,
             sizeof(defaultBuffer), entry, &totalLen);
 
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 1b38f4c..5e6c256 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -111,8 +111,6 @@
 75003 sqlite_mem_released (Memory released|1|2)
 75004 sqlite_db_corrupt (Database file corrupt|3)
 
-40000 checkin (Check in time|2|3)
-
 50000 menu_item_selected (Menu type where 0 is options and 1 is context|1|5),(Menu item title|3)
 50001 menu_opened (Menu type where 0 is options and 1 is context|1|5)
 
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 3130a1c..670408c 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -24,12 +24,64 @@
 #define DEFAULT_MAX_ROTATED_LOGS 4
 
 static AndroidLogFormat * g_logformat;
+static bool g_nonblock = false;
 
 /* logd prefixes records with a length field */
 #define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
 
 #define LOG_FILE_DIR    "/dev/log/"
 
+struct queued_entry_t {
+    union {
+        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
+        struct logger_entry entry __attribute__((aligned(4)));
+    };
+    queued_entry_t* next;
+
+    queued_entry_t() {
+        next = NULL;
+    }
+};
+
+static int cmp(queued_entry_t* a, queued_entry_t* b) {
+    int n = a->entry.sec - b->entry.sec;
+    if (n != 0) {
+        return n;
+    }
+    return a->entry.nsec - b->entry.nsec;
+}
+
+struct log_device_t {
+    char* device;
+    bool binary;
+    int fd;
+    bool printed;
+    char label;
+
+    queued_entry_t* queue;
+    log_device_t* next;
+
+    log_device_t(char* d, bool b, char l) {
+        device = d;
+        binary = b;
+        label = l;
+        next = NULL;
+        printed = false;
+    }
+
+    void enqueue(queued_entry_t* entry) {
+        if (this->queue == NULL) {
+            this->queue = entry;
+        } else {
+            queued_entry_t** e = &this->queue;
+            while (*e && cmp(entry, *e) >= 0) {
+                e = &((*e)->next);
+            }
+            entry->next = *e;
+            *e = entry;
+        }
+    }
+};
 
 namespace android {
 
@@ -40,8 +92,8 @@
 static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
 static int g_outFD = -1;
 static off_t g_outByteCount = 0;
-static int g_isBinary = 0;
 static int g_printBinary = 0;
+static int g_devCount = 0;
 
 static EventTagMap* g_eventTagMap = NULL;
 
@@ -103,14 +155,27 @@
     } while (ret < 0 && errno == EINTR);
 }
 
-static void processBuffer(struct logger_entry *buf)
+static void processBuffer(log_device_t* dev, struct logger_entry *buf)
 {
     int bytesWritten;
     int err;
     AndroidLogEntry entry;
     char binaryMsgBuf[1024];
 
-    if (g_isBinary) {
+    if (!dev->printed) {
+        dev->printed = true;
+        if (g_devCount > 1) {
+            snprintf(binaryMsgBuf, sizeof(binaryMsgBuf), "--------- beginning of %s\n",
+                    dev->device);
+            bytesWritten = write(g_outFD, binaryMsgBuf, strlen(binaryMsgBuf));
+            if (bytesWritten < 0) {
+                perror("output error");
+                exit(-1);
+            }
+        }
+    }
+
+    if (dev->binary) {
         err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
                 binaryMsgBuf, sizeof(binaryMsgBuf));
         //printf(">>> pri=%d len=%d msg='%s'\n",
@@ -118,15 +183,27 @@
     } else {
         err = android_log_processLogBuffer(buf, &entry);
     }
-    if (err < 0)
+    if (err < 0) {
         goto error;
+    }
 
-    bytesWritten = android_log_filterAndPrintLogLine(
-                        g_logformat, g_outFD, &entry);
+    if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.priority)) {
+        if (false && g_devCount > 1) {
+            binaryMsgBuf[0] = dev->label;
+            binaryMsgBuf[1] = ' ';
+            bytesWritten = write(g_outFD, binaryMsgBuf, 2);
+            if (bytesWritten < 0) {
+                perror("output error");
+                exit(-1);
+            }
+        }
 
-    if (bytesWritten < 0) {
-        perror("output error");
-        exit(-1);
+        bytesWritten = android_log_printLogLine(g_logformat, g_outFD, &entry);
+
+        if (bytesWritten < 0) {
+            perror("output error");
+            exit(-1);
+        }
     }
 
     g_outByteCount += bytesWritten;
@@ -142,36 +219,129 @@
     return;
 }
 
-static void readLogLines(int logfd)
+static void chooseFirst(log_device_t* dev, log_device_t** firstdev, queued_entry_t** firstentry) {
+    *firstdev = NULL;
+    *firstentry = NULL;
+    int i=0;
+    for (; dev; dev=dev->next) {
+        i++;
+        if (dev->queue) {
+            if ((*firstentry) == NULL || cmp(dev->queue, *firstentry) < 0) {
+                (*firstentry) = dev->queue;
+                *firstdev = dev;
+            }
+        }
+    }
+}
+
+static void printEntry(log_device_t* dev, queued_entry_t* entry) {
+    if (g_printBinary) {
+        printBinary(&entry->entry);
+    } else {
+        processBuffer(dev, &entry->entry);
+    }
+}
+
+static void eatEntry(log_device_t* dev, queued_entry_t* entry) {
+    if (dev->queue != entry) {
+        perror("assertion failed: entry isn't first in queue");
+        exit(1);
+    }
+    printEntry(dev, entry);
+    dev->queue = entry->next;
+    delete entry;
+}
+
+static void readLogLines(log_device_t* devices)
 {
+    log_device_t* dev;
+    int max = 0;
+    queued_entry_t* entry;
+    queued_entry_t* old;
+    int ret;
+    bool somethingForEveryone;
+    bool sleep = true;
+
+    int result;
+    fd_set readset;
+
+    for (dev=devices; dev; dev = dev->next) {
+        if (dev->fd > max) {
+            max = dev->fd;
+        }
+    }
+
     while (1) {
-        unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
-        struct logger_entry *entry = (struct logger_entry *) buf;
-        int ret;
+        do {
+            timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.
+            FD_ZERO(&readset);
+            for (dev=devices; dev; dev = dev->next) {
+                FD_SET(dev->fd, &readset);
+            }
+            result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
+        } while (result == -1 && errno == EINTR);
 
-        ret = read(logfd, entry, LOGGER_ENTRY_MAX_LEN);
-        if (ret < 0) {
-            if (errno == EINTR)
-                continue;
-            if (errno == EAGAIN)
-                break;
-            perror("logcat read");
-            exit(EXIT_FAILURE);
+        if (result >= 0) {
+            for (dev=devices; dev; dev = dev->next) {
+                if (FD_ISSET(dev->fd, &readset)) {
+                    entry = new queued_entry_t;
+                    /* NOTE: driver guarantees we read exactly one full entry */
+                    ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
+                    if (ret < 0) {
+                        if (errno == EINTR) {
+                            delete entry;
+                            goto next;
+                        }
+                        if (errno == EAGAIN) {
+                            delete entry;
+                            break;
+                        }
+                        perror("logcat read");
+                        exit(EXIT_FAILURE);
+                    }
+                    else if (!ret) {
+                        fprintf(stderr, "read: Unexpected EOF!\n");
+                        exit(EXIT_FAILURE);
+                    }
+
+                    entry->entry.msg[entry->entry.len] = '\0';
+
+                    dev->enqueue(entry);
+                }
+            }
+
+            if (result == 0) {
+                // we did our short timeout trick and there's nothing new
+                // print all that aren't the last in their list
+                sleep = true;
+                while (true) {
+                    chooseFirst(devices, &dev, &entry);
+                    if (!entry) {
+                        break;
+                    }
+                    eatEntry(dev, entry);
+                }
+                // They requested to just dump the log
+                if (g_nonblock) {
+                    exit(0);
+                }
+            } else {
+                // print all that aren't the last in their list
+                while (true) {
+                    chooseFirst(devices, &dev, &entry);
+                    if (!entry) {
+                        sleep = false;
+                        break;
+                    } else if (entry->next == NULL) {
+                        sleep = false;
+                        break;
+                    }
+                    eatEntry(dev, entry);
+                }
+            }
         }
-        else if (!ret) {
-            fprintf(stderr, "read: Unexpected EOF!\n");
-            exit(EXIT_FAILURE);
-        }
-
-        /* NOTE: driver guarantees we read exactly one full entry */
-
-        entry->msg[entry->len] = '\0';
-
-        if (g_printBinary) {
-            printBinary(entry);
-        } else {
-            (void) processBuffer(entry);
-        }
+next:
+        ;
     }
 }
 
@@ -275,16 +445,17 @@
 
 extern "C" void logprint_run_tests(void);
 
-int main (int argc, char **argv)
+int main(int argc, char **argv)
 {
-    int logfd;
     int err;
     int hasSetLogFormat = 0;
     int clearLog = 0;
     int getLogSize = 0;
     int mode = O_RDONLY;
-    char *log_device = strdup("/dev/"LOGGER_LOG_MAIN);
     const char *forceFilters = NULL;
+    log_device_t* devices = NULL;
+    log_device_t* dev;
+    bool needBinary = false;
 
     g_logformat = android_log_format_new();
 
@@ -319,21 +490,34 @@
             break;
 
             case 'd':
-                mode |= O_NONBLOCK;
+                g_nonblock = true;
             break;
 
             case 'g':
                 getLogSize = 1;
             break;
 
-            case 'b':
-                free(log_device);
-                log_device =
-                    (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
-                strcpy(log_device, LOG_FILE_DIR);
-                strcat(log_device, optarg);
+            case 'b': {
+                char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
+                strcpy(buf, LOG_FILE_DIR);
+                strcat(buf, optarg);
 
-                android::g_isBinary = (strcmp(optarg, "events") == 0);
+                bool binary = strcmp(optarg, "events") == 0;
+                if (binary) {
+                    needBinary = true;
+                }
+
+                if (devices) {
+                    dev = devices;
+                    while (dev->next) {
+                        dev = dev->next;
+                    }
+                    dev->next = new log_device_t(buf, binary, optarg[0]);
+                } else {
+                    devices = new log_device_t(buf, binary, optarg[0]);
+                }
+                android::g_devCount++;
+            }
             break;
 
             case 'B':
@@ -460,6 +644,19 @@
         }
     }
 
+    if (!devices) {
+        devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, 'm');
+        android::g_devCount = 1;
+        int accessmode =
+                  (mode & O_RDONLY) ? R_OK : 0
+                | (mode & O_WRONLY) ? W_OK : 0;
+        // only add this if it's available
+        if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) {
+            devices->next = new log_device_t(strdup("/dev/"LOGGER_LOG_SYSTEM), false, 's');
+            android::g_devCount++;
+        }
+    }
+
     if (android::g_logRotateSizeKBytes != 0 
         && android::g_outputFileName == NULL
     ) {
@@ -516,42 +713,52 @@
         }
     }
 
-    logfd = open(log_device, mode);
-    if (logfd < 0) {
-        fprintf(stderr, "Unable to open log device '%s': %s\n",
-            log_device, strerror(errno));
-        exit(EXIT_FAILURE);
-    }
-
-    if (clearLog) {
-        int ret;
-        ret = android::clearLog(logfd);
-        if (ret) {
-            perror("ioctl");
+    dev = devices;
+    while (dev) {
+        dev->fd = open(dev->device, mode);
+        if (dev->fd < 0) {
+            fprintf(stderr, "Unable to open log device '%s': %s\n",
+                dev->device, strerror(errno));
             exit(EXIT_FAILURE);
         }
-        return 0;
+
+        if (clearLog) {
+            int ret;
+            ret = android::clearLog(dev->fd);
+            if (ret) {
+                perror("ioctl");
+                exit(EXIT_FAILURE);
+            }
+        }
+
+        if (getLogSize) {
+            int size, readable;
+
+            size = android::getLogSize(dev->fd);
+            if (size < 0) {
+                perror("ioctl");
+                exit(EXIT_FAILURE);
+            }
+
+            readable = android::getLogReadableSize(dev->fd);
+            if (readable < 0) {
+                perror("ioctl");
+                exit(EXIT_FAILURE);
+            }
+
+            printf("%s: ring buffer is %dKb (%dKb consumed), "
+                   "max entry is %db, max payload is %db\n", dev->device,
+                   size / 1024, readable / 1024,
+                   (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
+        }
+
+        dev = dev->next;
     }
 
     if (getLogSize) {
-        int size, readable;
-
-        size = android::getLogSize(logfd);
-        if (size < 0) {
-            perror("ioctl");
-            exit(EXIT_FAILURE);
-        }
-
-        readable = android::getLogReadableSize(logfd);
-        if (readable < 0) {
-            perror("ioctl");
-            exit(EXIT_FAILURE);
-        }
-
-        printf("ring buffer is %dKb (%dKb consumed), "
-               "max entry is %db, max payload is %db\n",
-               size / 1024, readable / 1024,
-               (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
+        return 0;
+    }
+    if (clearLog) {
         return 0;
     }
 
@@ -559,10 +766,10 @@
     //LOG_EVENT_LONG(11, 0x1122334455667788LL);
     //LOG_EVENT_STRING(0, "whassup, doc?");
 
-    if (android::g_isBinary)
+    if (needBinary)
         android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
 
-    android::readLogLines(logfd);
+    android::readLogLines(devices);
 
     return 0;
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0e52e54..4a67011 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -24,6 +24,11 @@
     mkdir /mnt 0775 root system
     mkdir /mnt/sdcard 0000 system system
 
+# Create cgroup mount point for cpu accounting
+    mkdir /acct
+    mount cgroup none /acct cpuacct
+    mkdir /acct/uid
+
 # Backwards Compat - XXX: Going away in G*
     symlink /mnt/sdcard /sdcard
 
@@ -120,6 +125,7 @@
 # create basic filesystem structure
     mkdir /data/misc 01771 system misc
     mkdir /data/misc/bluetoothd 0770 bluetooth bluetooth
+    mkdir /data/misc/bluetooth 0770 system system
     mkdir /data/misc/keystore 0700 keystore keystore
     mkdir /data/misc/vpn 0770 system system
     mkdir /data/misc/systemkeys 0700 system system
@@ -280,6 +286,7 @@
 
 service vold /system/bin/vold
     socket vold stream 0660 root mount
+    ioprio be 2
 
 service netd /system/bin/netd
     socket netd stream 0660 root system
@@ -301,6 +308,7 @@
 service media /system/bin/mediaserver
     user media
     group system audio camera graphics inet net_bt net_bt_admin
+    ioprio rt 4
 
 service bootanim /system/bin/bootanimation
     user graphics
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 122a544..a6114ac 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -51,7 +51,8 @@
 	iftop \
 	id \
 	vmstat \
-	nandread
+	nandread \
+        ionice
 
 LOCAL_SRC_FILES:= \
 	toolbox.c \
diff --git a/toolbox/ionice.c b/toolbox/ionice.c
new file mode 100644
index 0000000..4a182f2
--- /dev/null
+++ b/toolbox/ionice.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <cutils/iosched_policy.h>
+
+static char *classes[] = {"none", "rt", "be", "idle", NULL};
+
+int ionice_main(int argc, char *argv[])
+{
+    IoSchedClass clazz = IoSchedClass_NONE;
+    int ioprio = 0;
+    int pid;
+
+    if(argc != 2 && argc != 4) {
+        fprintf(stderr, "usage: ionice <pid> [none|rt|be|idle] [prio]\n");
+        return 1;
+    }
+
+    if (!(pid = atoi(argv[1]))) {
+        fprintf(stderr, "Invalid pid specified\n");
+        return 1;
+    }
+
+    if (argc == 2) {
+        if (android_get_ioprio(pid, &clazz, &ioprio)) {
+            fprintf(stderr, "Failed to read priority (%s)\n", strerror(errno));
+            return 1;
+        }
+        fprintf(stdout, "Pid %d, class %s (%d), prio %d\n", pid, classes[clazz], clazz, ioprio);
+        return 0;
+    }
+
+    if (!strcmp(argv[2], "none")) {
+        clazz = IoSchedClass_NONE;
+    } else if (!strcmp(argv[2], "rt")) {
+        clazz = IoSchedClass_RT;
+    } else if (!strcmp(argv[2], "be")) {
+        clazz = IoSchedClass_BE;
+    } else if (!strcmp(argv[2], "idle")) {
+        clazz = IoSchedClass_IDLE;
+    } else {
+        fprintf(stderr, "Unsupported class '%s'\n", argv[2]);
+        return 1;
+    }
+
+    ioprio = atoi(argv[3]);
+
+    printf("Setting pid %d i/o class to %d, prio %d\n", pid, clazz, ioprio);
+    if (android_set_ioprio(pid, clazz, ioprio)) {
+        fprintf(stderr, "Failed to set priority (%s)\n", strerror(errno));
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
index aacccdb..9644973 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -8,7 +8,7 @@
 #include <mtd/mtd-user.h>
 #include <sys/ioctl.h>
 
-int test_empty(const char *buf, size_t size)
+static int test_empty(const char *buf, size_t size)
 {
     while(size--) {
         if (*buf++ != 0xff)
@@ -29,12 +29,14 @@
     int ret;
     int verbose = 0;
     void *buffer;
-    loff_t pos, opos;
+    loff_t pos, opos, end, bpos;
+    loff_t start = 0, len = 0;
     int c;
     int i;
     int empty_pages = 0;
     int page_count = 0;
     int bad_block;
+    int rawmode = 0;
     uint32_t *oob_data;
     uint8_t *oob_fixed;
     size_t spare_size = 64;
@@ -44,7 +46,7 @@
     struct nand_ecclayout ecclayout;
 
     do {
-        c = getopt(argc, argv, "d:f:s:hv");
+        c = getopt(argc, argv, "d:f:s:S:L:Rhv");
         if (c == EOF)
             break;
         switch (c) {
@@ -57,6 +59,15 @@
         case 's':
             spare_size = atoi(optarg);
             break;
+        case 'S':
+            start = strtoll(optarg, NULL, 0);
+            break;
+        case 'L':
+            len = strtoll(optarg, NULL, 0);
+            break;
+        case 'R':
+            rawmode = 1;
+            break;
         case 'v':
             verbose++;
             break;
@@ -65,6 +76,9 @@
                     "  -d <dev>   Read from <dev>\n"
                     "  -f <file>  Write to <file>\n"
                     "  -s <size>  Number of spare bytes in file (default 64)\n"
+                    "  -R         Raw mode\n"
+                    "  -S <start> Start offset (default 0)\n"
+                    "  -L <len>   Length (default 0)\n"
                     "  -v         Print info\n"
                     "  -h         Print help\n", argv[0]);
             return -1;
@@ -129,7 +143,7 @@
 
     oobbuf.length = mtdinfo.oobsize;
     oob_data = (uint32_t *)((uint8_t *)buffer + mtdinfo.writesize);
-    memset(oob_data, 0xff, spare_size);
+    memset(oob_data, 0xff, mtdinfo.oobsize + spare_size);
     oobbuf.ptr = (uint8_t *)oob_data + spare_size;
 
     ret = ioctl(fd, ECCGETLAYOUT, &ecclayout);
@@ -160,21 +174,34 @@
         printf("initial ecc bbtblocks: %u\n", initial_ecc.bbtblocks);
     }
 
-    for (pos = 0, opos = 0; pos < mtdinfo.size; pos += mtdinfo.writesize) {
+    if (rawmode) {
+        rawmode = mtdinfo.oobsize;
+        ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
+        if (ret) {
+            fprintf(stderr, "failed set raw mode for %s, %s\n",
+                    devname, strerror(errno));
+            return 1;
+        }
+    }
+
+    end = len ? (start + len) : mtdinfo.size;
+    for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
         bad_block = 0;
         if (verbose > 3)
             printf("reading at %llx\n", pos);
         lseek64(fd, pos, SEEK_SET);
-        ret = read(fd, buffer, mtdinfo.writesize);
+        ret = read(fd, buffer, mtdinfo.writesize + rawmode);
         if (ret < (int)mtdinfo.writesize) {
             fprintf(stderr, "short read at %llx, %d\n", pos, ret);
             bad_block = 2;
         }
-        oobbuf.start = pos;
-        ret = ioctl(fd, MEMREADOOB, &oobbuf);
-        if (ret) {
-            fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
-            bad_block = 2;
+        if (!rawmode) {
+            oobbuf.start = pos;
+            ret = ioctl(fd, MEMREADOOB, &oobbuf);
+            if (ret) {
+                fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
+                bad_block = 2;
+            }
         }
         ret = ioctl(fd, ECCGETSTATS, &ecc);
         if (ret) {
@@ -182,7 +209,8 @@
                     devname, strerror(errno));
             return 1;
         }
-        ret = ioctl(fd, MEMGETBADBLOCK, &pos);
+        bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
+        ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
         if (ret && errno != EOPNOTSUPP) {
             printf("badblock at %llx\n", pos);
             bad_block = 1;
@@ -196,14 +224,16 @@
         if (ecc.bbtblocks != last_ecc.bbtblocks)
             printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
 
-        oob_fixed = (uint8_t *)oob_data;
-        for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
-            int len = ecclayout.oobfree[i].length;
-            if (oob_fixed + len > oobbuf.ptr)
-                len = oobbuf.ptr - oob_fixed;
-            if (len) {
-                memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len);
-                oob_fixed += len;
+        if (!rawmode) {
+            oob_fixed = (uint8_t *)oob_data;
+            for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
+                int len = ecclayout.oobfree[i].length;
+                if (oob_fixed + len > oobbuf.ptr)
+                    len = oobbuf.ptr - oob_fixed;
+                if (len) {
+                    memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len);
+                    oob_fixed += len;
+                }
             }
         }
 
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 8e611c6..ff9e844 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -414,11 +414,14 @@
     if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
 	off_t delta;
 	getdiskinfo(fd, fname, dtype, oflag, &bpb);
+        if (opt_s) {
+            bpb.bsec = opt_s;
+        }
 	bpb.bsec -= (opt_ofs / bpb.bps);
 	delta = bpb.bsec % bpb.spt;
 	if (delta != 0) {
-	    warnx("trim %d sectors to adjust to a multiple of %d",
-		(int)delta, bpb.spt);
+	    warnx("trim %d sectors from %d to adjust to a multiple of %d",
+		(int)delta, bpb.bsec, bpb.spt);
 	    bpb.bsec -= delta;
 	}
 	if (bpb.spc == 0) {	/* set defaults */