am 1d6279ee: am 038975a5: Merge "lmkd: pass uid from ActivityManager to lmkd"

* commit '1d6279ee3d0771687a56a22e70dc1e7aa5ac3078':
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 0254bd2..e78fc88 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -53,3 +53,4 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
diff --git a/adb/sockets.c b/adb/sockets.c
index de14a22..faa9564 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -23,6 +23,10 @@
 
 #include "sysdeps.h"
 
+#if !ADB_HOST
+#include <cutils/properties.h>
+#endif
+
 #define  TRACE_TAG  TRACE_SOCKETS
 #include "adb.h"
 
@@ -428,6 +432,9 @@
 {
     asocket *s;
     int fd;
+#if !ADB_HOST
+    char debug[PROPERTY_VALUE_MAX];
+#endif
 
 #if !ADB_HOST
     if (!strcmp(name,"jdwp")) {
@@ -444,7 +451,11 @@
     D("LS(%d): bound to '%s' via %d\n", s->id, name, fd);
 
 #if !ADB_HOST
-    if ((!strncmp(name, "root:", 5) && getuid() != 0)
+    if (!strncmp(name, "root:", 5))
+        property_get("ro.debuggable", debug, "");
+
+    if ((!strncmp(name, "root:", 5) && getuid() != 0
+        && strcmp(debug, "1") == 0)
         || !strncmp(name, "usb:", 4)
         || !strncmp(name, "tcpip:", 6)) {
         D("LS(%d): enabling exit_on_close\n", s->id);
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index e4d7ecc..c33b263 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -22,13 +22,6 @@
     -Wunused \
     -Werror \
 
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP
-endif # ARCH_ARM_HAVE_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
-
 LOCAL_SHARED_LIBRARIES := \
     libbacktrace \
     libcutils \
@@ -45,6 +38,8 @@
 
 include $(BUILD_EXECUTABLE)
 
+
+
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := crasher.c
 LOCAL_SRC_FILES_arm    := arm/crashglue.S
@@ -59,36 +54,14 @@
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SHARED_LIBRARIES := libcutils liblog libc
 
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
 LOCAL_MODULE := crasher
 LOCAL_MODULE_STEM_32 := crasher
 LOCAL_MODULE_STEM_64 := crasher64
 LOCAL_MULTILIB := both
 
 include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_MODULE_TARGET_ARCH += arm
-LOCAL_SRC_FILES_arm := arm/vfp.S
-LOCAL_CFLAGS_arm += -DWITH_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
-endif # ARCH_ARM_HAVE_VFP == true
-LOCAL_CFLAGS += -Werror
-
-LOCAL_SRC_FILES_arm64 := arm64/vfp.S
-LOCAL_MODULE_TARGET_ARCH += arm64
-
-LOCAL_SRC_FILES := vfp-crasher.c
-LOCAL_MODULE := vfp-crasher
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-
-LOCAL_MODULE_STEM_32 := vfp-crasher
-LOCAL_MODULE_STEM_64 := vfp-crasher64
-LOCAL_MULTILIB := both
-
-include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/arm/crashglue.S b/debuggerd/arm/crashglue.S
index eb9d0e3..4fbfd6e 100644
--- a/debuggerd/arm/crashglue.S
+++ b/debuggerd/arm/crashglue.S
@@ -1,8 +1,5 @@
 .globl crash1
 .type crash1, %function
-.globl crashnostack
-.type crashnostack, %function
-
 crash1:
 	ldr r0, =0xa5a50000
 	ldr r1, =0xa5a50001
@@ -18,11 +15,48 @@
 	ldr r11, =0xa5a50011
 	ldr r12, =0xa5a50012
 
+
+	fconstd   d0, #0
+	fconstd   d1, #1
+	fconstd   d2, #2
+	fconstd   d3, #3
+	fconstd   d4, #4
+	fconstd   d5, #5
+	fconstd   d6, #6
+	fconstd   d7, #7
+	fconstd   d8, #8
+	fconstd   d9, #9
+	fconstd   d10, #10
+	fconstd   d11, #11
+	fconstd   d12, #12
+	fconstd   d13, #13
+	fconstd   d14, #14
+	fconstd   d15, #15
+#if defined(HAS_VFP_D32)
+	fconstd   d16, #16
+	fconstd   d17, #17
+	fconstd   d18, #18
+	fconstd   d19, #19
+	fconstd   d20, #20
+	fconstd   d21, #21
+	fconstd   d22, #22
+	fconstd   d23, #23
+	fconstd   d24, #24
+	fconstd   d25, #25
+	fconstd   d26, #26
+	fconstd   d27, #27
+	fconstd   d28, #28
+	fconstd   d29, #29
+	fconstd   d30, #30
+	fconstd   d31, #31
+#endif
+
 	mov lr, #0
 	ldr lr, [lr]
 	b .
 
-
+.globl crashnostack
+.type crashnostack, %function
 crashnostack:
 	mov sp, #0
 	mov r0, #0
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 839d47a..8270066 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -27,21 +27,8 @@
 #include "../utility.h"
 #include "../machine.h"
 
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-#ifdef WITH_VFP
-#ifdef WITH_VFP_D32
-#define NUM_VFP_REGS 32
-#else
-#define NUM_VFP_REGS 16
-#endif
-#endif
-
-// If configured to do so, dump memory around *all* registers
-// for the crashing thread.
 void dump_memory_and_code(log_t* log, pid_t tid) {
-  struct pt_regs regs;
+  pt_regs regs;
   if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
     return;
   }
@@ -73,7 +60,7 @@
 }
 
 void dump_registers(log_t* log, pid_t tid) {
-  struct pt_regs r;
+  pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
     _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
     return;
@@ -93,19 +80,15 @@
        static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
        static_cast<uint32_t>(r.ARM_cpsr));
 
-#ifdef WITH_VFP
-  struct user_vfp vfp_regs;
-  int i;
-
+  user_vfp vfp_regs;
   if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
     _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
     return;
   }
 
-  for (i = 0; i < NUM_VFP_REGS; i += 2) {
+  for (size_t i = 0; i < 32; i += 2) {
     _LOG(log, logtype::REGISTERS, "    d%-2d %016llx  d%-2d %016llx\n",
          i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
   }
   _LOG(log, logtype::REGISTERS, "    scr %08lx\n", vfp_regs.fpscr);
-#endif
 }
diff --git a/debuggerd/arm/vfp.S b/debuggerd/arm/vfp.S
deleted file mode 100644
index 9744f6f..0000000
--- a/debuggerd/arm/vfp.S
+++ /dev/null
@@ -1,43 +0,0 @@
-    .text
-    .align 2
-    .global crash
-    .type crash, %function
-crash:
-    fconstd   d0, #0
-    fconstd   d1, #1
-    fconstd   d2, #2
-    fconstd   d3, #3
-    fconstd   d4, #4
-    fconstd   d5, #5
-    fconstd   d6, #6
-    fconstd   d7, #7
-    fconstd   d8, #8
-    fconstd   d9, #9
-    fconstd   d10, #10
-    fconstd   d11, #11
-    fconstd   d12, #12
-    fconstd   d13, #13
-    fconstd   d14, #14
-    fconstd   d15, #15
-#ifdef WITH_VFP_D32
-    fconstd   d16, #16
-    fconstd   d17, #17
-    fconstd   d18, #18
-    fconstd   d19, #19
-    fconstd   d20, #20
-    fconstd   d21, #21
-    fconstd   d22, #22
-    fconstd   d23, #23
-    fconstd   d24, #24
-    fconstd   d25, #25
-    fconstd   d26, #26
-    fconstd   d27, #27
-    fconstd   d28, #28
-    fconstd   d29, #29
-    fconstd   d30, #30
-    fconstd   d31, #31
-#endif
-    mov       r0, #0
-    str       r0, [r0]
-    bx        lr
-
diff --git a/debuggerd/arm64/crashglue.S b/debuggerd/arm64/crashglue.S
index b06b67c..e58b542 100644
--- a/debuggerd/arm64/crashglue.S
+++ b/debuggerd/arm64/crashglue.S
@@ -1,8 +1,5 @@
 .globl crash1
 .type crash1, %function
-.globl crashnostack
-.type crashnostack, %function
-
 crash1:
 	ldr x0, =0xa5a50000
 	ldr x1, =0xa5a50001
@@ -35,11 +32,46 @@
 	ldr x28, =0xa5a50028
 	ldr x29, =0xa5a50029
 
+	fmov   d0, -1.0  // -1 is more convincing than 0.
+	fmov   d1, 1.0
+	fmov   d2, 2.0
+	fmov   d3, 3.0
+	fmov   d4, 4.0
+	fmov   d5, 5.0
+	fmov   d6, 6.0
+	fmov   d7, 7.0
+	fmov   d8, 8.0
+	fmov   d9, 9.0
+	fmov   d10, 10.0
+	fmov   d11, 11.0
+	fmov   d12, 12.0
+	fmov   d13, 13.0
+	fmov   d14, 14.0
+	fmov   d15, 15.0
+	fmov   d16, 16.0
+	fmov   d17, 17.0
+	fmov   d18, 18.0
+	fmov   d19, 19.0
+	fmov   d20, 20.0
+	fmov   d21, 21.0
+	fmov   d22, 22.0
+	fmov   d23, 23.0
+	fmov   d24, 24.0
+	fmov   d25, 25.0
+	fmov   d26, 26.0
+	fmov   d27, 27.0
+	fmov   d28, 28.0
+	fmov   d29, 29.0
+	fmov   d30, 30.0
+	fmov   d31, 31.0
+
 	mov x30, xzr
 	ldr x30, [x30]
 	b .
 
 
+.globl crashnostack
+.type crashnostack, %function
 crashnostack:
 	mov x0, xzr
 	add sp, x0, xzr
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 48308c3..ec664bd 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -30,13 +30,6 @@
 #include "../utility.h"
 #include "../machine.h"
 
-/* enable to dump memory pointed to by every register */
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-/*
- * If configured to do so, dump memory around *all* registers
- * for the crashing thread.
- */
 void dump_memory_and_code(log_t* log, pid_t tid) {
     struct user_pt_regs regs;
     struct iovec io;
diff --git a/debuggerd/arm64/vfp.S b/debuggerd/arm64/vfp.S
deleted file mode 100644
index bf12c22..0000000
--- a/debuggerd/arm64/vfp.S
+++ /dev/null
@@ -1,42 +0,0 @@
-    .text
-    .align 2
-    .global crash
-    .type crash, %function
-crash:
-    fmov   d0, XZR
-    fmov   d1, 1.0
-    fmov   d2, 2.0
-    fmov   d3, 3.0
-    fmov   d4, 4.0
-    fmov   d5, 5.0
-    fmov   d6, 6.0
-    fmov   d7, 7.0
-    fmov   d8, 8.0
-    fmov   d9, 9.0
-    fmov   d10, 10.0
-    fmov   d11, 11.0
-    fmov   d12, 12.0
-    fmov   d13, 13.0
-    fmov   d14, 14.0
-    fmov   d15, 15.0
-    fmov   d16, 16.0
-    fmov   d17, 17.0
-    fmov   d18, 18.0
-    fmov   d19, 19.0
-    fmov   d20, 20.0
-    fmov   d21, 21.0
-    fmov   d22, 22.0
-    fmov   d23, 23.0
-    fmov   d24, 24.0
-    fmov   d25, 25.0
-    fmov   d26, 26.0
-    fmov   d27, 27.0
-    fmov   d28, 28.0
-    fmov   d29, 29.0
-    fmov   d30, 30.0
-    fmov   d31, 31.0
-
-    mov       x0, xzr
-    str       x0, [x0]
-    br        x30
-
diff --git a/debuggerd/vfp-crasher.c b/debuggerd/vfp-crasher.c
deleted file mode 100644
index 7a19cdd..0000000
--- a/debuggerd/vfp-crasher.c
+++ /dev/null
@@ -1,7 +0,0 @@
-int main()
-{
-  extern void crash(void);
-
-  crash();
-  return 0;
-}
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 8388629..8444081 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -1,5 +1,5 @@
 #ifndef _FS_H_
-#define _FH_H_
+#define _FS_H_
 
 #include <stdint.h>
 
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 1ee33a1..4a6b702 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -35,6 +35,8 @@
 
 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
+#define FAKE_BATTERY_CAPACITY 42
+#define FAKE_BATTERY_TEMPERATURE 424
 
 namespace android {
 
@@ -530,11 +532,11 @@
             KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
     }
 
-    if (property_get("persist.sys.battery.capacity", pval, NULL) > 0)
-        mBatteryFixedCapacity = (int) strtol(pval, NULL, 10);
-
-    if (property_get("persist.sys.battery.temperature", pval, NULL) > 0)
-        mBatteryFixedTemperature = (int) strtol(pval, NULL, 10);
+    if (property_get("ro.boot.fake_battery", pval, NULL) > 0
+                                               && strtol(pval, NULL, 10) != 0) {
+        mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
+        mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
+    }
 }
 
 }; // namespace android
diff --git a/include/system/audio.h b/include/system/audio.h
index 8530efa..f42c640 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -52,7 +52,9 @@
     AUDIO_STREAM_ALARM            = 4,
     AUDIO_STREAM_NOTIFICATION     = 5,
     AUDIO_STREAM_BLUETOOTH_SCO    = 6,
-    AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */
+    AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user
+                                        * and must be routed to speaker
+                                        */
     AUDIO_STREAM_DTMF             = 8,
     AUDIO_STREAM_TTS              = 9,
 
@@ -200,7 +202,16 @@
 
 /* AAC sub format field definition: specify profile or bitrate for recording... */
 typedef enum {
-    AUDIO_FORMAT_AAC_SUB_NONE            = 0x0,
+    AUDIO_FORMAT_AAC_SUB_MAIN            = 0x1,
+    AUDIO_FORMAT_AAC_SUB_LC              = 0x2,
+    AUDIO_FORMAT_AAC_SUB_SSR             = 0x4,
+    AUDIO_FORMAT_AAC_SUB_LTP             = 0x8,
+    AUDIO_FORMAT_AAC_SUB_HE_V1           = 0x10,
+    AUDIO_FORMAT_AAC_SUB_SCALABLE        = 0x20,
+    AUDIO_FORMAT_AAC_SUB_ERLC            = 0x40,
+    AUDIO_FORMAT_AAC_SUB_LD              = 0x80,
+    AUDIO_FORMAT_AAC_SUB_HE_V2           = 0x100,
+    AUDIO_FORMAT_AAC_SUB_ELD             = 0x200,
 } audio_format_aac_sub_fmt_t;
 
 /* VORBIS sub format field definition: specify quality for recording... */
@@ -225,8 +236,8 @@
     AUDIO_FORMAT_AMR_NB              = 0x02000000UL,
     AUDIO_FORMAT_AMR_WB              = 0x03000000UL,
     AUDIO_FORMAT_AAC                 = 0x04000000UL,
-    AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL,
-    AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL,
+    AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V1*/
+    AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V2*/
     AUDIO_FORMAT_VORBIS              = 0x07000000UL,
     AUDIO_FORMAT_OPUS                = 0x08000000UL,
     AUDIO_FORMAT_AC3                 = 0x09000000UL,
@@ -249,10 +260,41 @@
                                         AUDIO_FORMAT_PCM_SUB_FLOAT),
     AUDIO_FORMAT_PCM_24_BIT_PACKED   = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED),
+    AUDIO_FORMAT_AAC_MAIN            = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_MAIN),
+    AUDIO_FORMAT_AAC_LC              = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_LC),
+    AUDIO_FORMAT_AAC_SSR             = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_SSR),
+    AUDIO_FORMAT_AAC_LTP             = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_LTP),
+    AUDIO_FORMAT_AAC_HE_V1           = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_HE_V1),
+    AUDIO_FORMAT_AAC_SCALABLE        = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_SCALABLE),
+    AUDIO_FORMAT_AAC_ERLC            = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_ERLC),
+    AUDIO_FORMAT_AAC_LD              = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_LD),
+    AUDIO_FORMAT_AAC_HE_V2           = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_HE_V2),
+    AUDIO_FORMAT_AAC_ELD             = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_ELD),
 } audio_format_t;
 
+/* For the channel mask for position assignment representation */
 enum {
+
+/* These can be a complete audio_channel_mask_t. */
+
     AUDIO_CHANNEL_NONE                      = 0x0,
+    AUDIO_CHANNEL_INVALID                   = 0xC0000000,
+
+/* These can be the bits portion of an audio_channel_mask_t
+ * with representation AUDIO_CHANNEL_REPRESENTATION_POSITION.
+ * Using these bits as a complete audio_channel_mask_t is deprecated.
+ */
+
     /* output channels */
     AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1,
     AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2,
@@ -273,6 +315,8 @@
     AUDIO_CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000,
     AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000,
 
+/* TODO: should these be considered complete channel masks, or only bits? */
+
     AUDIO_CHANNEL_OUT_MONO     = AUDIO_CHANNEL_OUT_FRONT_LEFT,
     AUDIO_CHANNEL_OUT_STEREO   = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT),
@@ -328,6 +372,8 @@
                                   AUDIO_CHANNEL_OUT_TOP_BACK_CENTER|
                                   AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
 
+/* These are bits only, not complete values */
+
     /* input channels */
     AUDIO_CHANNEL_IN_LEFT            = 0x4,
     AUDIO_CHANNEL_IN_RIGHT           = 0x8,
@@ -344,6 +390,8 @@
     AUDIO_CHANNEL_IN_VOICE_UPLINK    = 0x4000,
     AUDIO_CHANNEL_IN_VOICE_DNLINK    = 0x8000,
 
+/* TODO: should these be considered complete channel masks, or only bits, or deprecated? */
+
     AUDIO_CHANNEL_IN_MONO   = AUDIO_CHANNEL_IN_FRONT,
     AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
     AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK),
@@ -365,9 +413,95 @@
 
 /* A channel mask per se only defines the presence or absence of a channel, not the order.
  * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
+ *
+ * audio_channel_mask_t is an opaque type and its internal layout should not
+ * be assumed as it may change in the future.
+ * Instead, always use the functions declared in this header to examine.
+ *
+ * These are the current representations:
+ *
+ *   AUDIO_CHANNEL_REPRESENTATION_POSITION
+ *     is a channel mask representation for position assignment.
+ *     Each low-order bit corresponds to the spatial position of a transducer (output),
+ *     or interpretation of channel (input).
+ *     The user of a channel mask needs to know the context of whether it is for output or input.
+ *     The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion.
+ *     It is not permitted for no bits to be set.
+ *
+ *   AUDIO_CHANNEL_REPRESENTATION_INDEX
+ *     is a channel mask representation for index assignment.
+ *     Each low-order bit corresponds to a selected channel.
+ *     There is no platform interpretation of the various bits.
+ *     There is no concept of output or input.
+ *     It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but this will not the be
+ * case in future revisions of the platform. Wherever there is an ambiguity between input and output
+ * that is currently resolved by checking the channel mask, the implementer should look for ways to
+ * fix it with additional information outside of the mask.
  */
 typedef uint32_t audio_channel_mask_t;
 
+/* Maximum number of channels for all representations */
+#define AUDIO_CHANNEL_COUNT_MAX             30
+
+/* log(2) of maximum number of representations, not part of public API */
+#define AUDIO_CHANNEL_REPRESENTATION_LOG2   2
+
+/* Representations */
+typedef enum {
+    AUDIO_CHANNEL_REPRESENTATION_POSITION    = 0,    // must be zero for compatibility
+    // 1 is reserved for future use
+    AUDIO_CHANNEL_REPRESENTATION_INDEX       = 2,
+    // 3 is reserved for future use
+} audio_channel_representation_t;
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel)
+{
+    return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1);
+}
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline audio_channel_representation_t audio_channel_mask_get_representation(
+        audio_channel_mask_t channel)
+{
+    // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits
+    return (audio_channel_representation_t)
+            ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1));
+}
+
+/* Returns true if the channel mask is valid,
+ * or returns false for AUDIO_CHANNEL_NONE, AUDIO_CHANNEL_INVALID, and other invalid values.
+ * This function is unable to determine whether a channel mask for position assignment
+ * is invalid because an output mask has an invalid output bit set,
+ * or because an input mask has an invalid input bit set.
+ * All other APIs that take a channel mask assume that it is valid.
+ */
+static inline bool audio_channel_mask_is_valid(audio_channel_mask_t channel)
+{
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    audio_channel_representation_t representation = audio_channel_mask_get_representation(channel);
+    switch (representation) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        break;
+    default:
+        bits = 0;
+        break;
+    }
+    return bits != 0;
+}
+
+/* Not part of public API */
+static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
+        audio_channel_representation_t representation, uint32_t bits)
+{
+    return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
+}
+
 /* Expresses the convention when stereo audio samples are stored interleaved
  * in an array.  This should improve readability by allowing code to use
  * symbolic indices instead of hard-coded [0] and [1].
@@ -645,10 +779,10 @@
     audio_gain_mode_t    mode;              /* mode requested for this command */
     audio_channel_mask_t channel_mask;      /* channels which gain value follows.
                                                N/A in joint mode */
-    int                  values[sizeof(audio_channel_mask_t)]; /* gain values in millibels for each
-                                               channel ordered from LSb to MSb in channel mask.
-                                               The number of values is 1 in joint mode or
-                                               popcount(channel_mask) */
+    int                  values[sizeof(audio_channel_mask_t) * 8]; /* gain values in millibels
+                                               for each channel ordered from LSb to MSb in
+                                               channel mask. The number of values is 1 in joint
+                                               mode or popcount(channel_mask) */
     unsigned int         ramp_duration_ms; /* ramp duration in ms */
 };
 
@@ -913,81 +1047,182 @@
         return false;
 }
 
+/* Returns true if:
+ *  representation is valid, and
+ *  there is at least one channel bit set which _could_ correspond to an input channel, and
+ *  there are no channel bits set which could _not_ correspond to an input channel.
+ * Otherwise returns false.
+ */
 static inline bool audio_is_input_channel(audio_channel_mask_t channel)
 {
-    if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
-        return channel != 0;
-    else
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        if (bits & ~AUDIO_CHANNEL_IN_ALL) {
+            bits = 0;
+        }
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return bits != 0;
+    default:
         return false;
+    }
 }
 
+/* Returns true if:
+ *  representation is valid, and
+ *  there is at least one channel bit set which _could_ correspond to an output channel, and
+ *  there are no channel bits set which could _not_ correspond to an output channel.
+ * Otherwise returns false.
+ */
 static inline bool audio_is_output_channel(audio_channel_mask_t channel)
 {
-    if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0)
-        return channel != 0;
-    else
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        if (bits & ~AUDIO_CHANNEL_OUT_ALL) {
+            bits = 0;
+        }
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return bits != 0;
+    default:
         return false;
+    }
 }
 
 /* Returns the number of channels from an input channel mask,
  * used in the context of audio input or recording.
+ * If a channel bit is set which could _not_ correspond to an input channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
  */
 static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
 {
-    return popcount(channel & AUDIO_CHANNEL_IN_ALL);
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        // TODO: We can now merge with from_out_mask and remove anding
+        bits &= AUDIO_CHANNEL_IN_ALL;
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return popcount(bits);
+    default:
+        return 0;
+    }
 }
 
 /* Returns the number of channels from an output channel mask,
  * used in the context of audio output or playback.
+ * If a channel bit is set which could _not_ correspond to an output channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
  */
 static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
 {
-    return popcount(channel & AUDIO_CHANNEL_OUT_ALL);
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        // TODO: We can now merge with from_in_mask and remove anding
+        bits &= AUDIO_CHANNEL_OUT_ALL;
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return popcount(bits);
+    default:
+        return 0;
+    }
 }
 
-/* Derive an output channel mask from a channel count.
+/* Derive an output channel mask for position assignment from a channel count.
  * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
  * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
  * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
  * for continuity with stereo.
- * Returns the matching channel mask, or 0 if the number of channels exceeds that of the
- * configurations for which a default channel mask is defined.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default output channel mask is defined.
  */
 static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
 {
+    uint32_t bits;
     switch (channel_count) {
+    case 0:
+        return AUDIO_CHANNEL_NONE;
     case 1:
-        return AUDIO_CHANNEL_OUT_MONO;
+        bits = AUDIO_CHANNEL_OUT_MONO;
+        break;
     case 2:
-        return AUDIO_CHANNEL_OUT_STEREO;
+        bits = AUDIO_CHANNEL_OUT_STEREO;
+        break;
     case 3:
-        return (AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER);
+        bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+        break;
     case 4: // 4.0
-        return AUDIO_CHANNEL_OUT_QUAD;
+        bits = AUDIO_CHANNEL_OUT_QUAD;
+        break;
     case 5: // 5.0
-        return (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER);
+        bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+        break;
     case 6: // 5.1
-        return AUDIO_CHANNEL_OUT_5POINT1;
+        bits = AUDIO_CHANNEL_OUT_5POINT1;
+        break;
     case 7: // 6.1
-        return (AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER);
+        bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
+        break;
     case 8:
-        return AUDIO_CHANNEL_OUT_7POINT1;
+        bits = AUDIO_CHANNEL_OUT_7POINT1;
+        break;
     default:
-        return 0;
+        return AUDIO_CHANNEL_INVALID;
     }
+    return audio_channel_mask_from_representation_and_bits(
+            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
 }
 
-/* Similar to above, but for input.  Currently handles only mono and stereo. */
+/* Derive an input channel mask for position assignment from a channel count.
+ * Currently handles only mono and stereo.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default input channel mask is defined.
+ */
 static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
 {
+    uint32_t bits;
     switch (channel_count) {
+    case 0:
+        return AUDIO_CHANNEL_NONE;
     case 1:
-        return AUDIO_CHANNEL_IN_MONO;
+        bits = AUDIO_CHANNEL_IN_MONO;
+        break;
     case 2:
-        return AUDIO_CHANNEL_IN_STEREO;
+        bits = AUDIO_CHANNEL_IN_STEREO;
+        break;
     default:
-        return 0;
+        return AUDIO_CHANNEL_INVALID;
     }
+    return audio_channel_mask_from_representation_and_bits(
+            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
+}
+
+/* Derive a channel mask for index assignment from a channel count.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX.
+ */
+static inline audio_channel_mask_t audio_channel_mask_for_index_assignment_from_count(
+        uint32_t channel_count)
+{
+    if (channel_count == 0) {
+        return AUDIO_CHANNEL_NONE;
+    }
+    if (channel_count > AUDIO_CHANNEL_COUNT_MAX) {
+        return AUDIO_CHANNEL_INVALID;
+    }
+    uint32_t bits = (1 << channel_count) - 1;
+    return audio_channel_mask_from_representation_and_bits(
+            AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
 }
 
 static inline bool audio_is_valid_format(audio_format_t format)
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
index 3085830..a6554de 100644
--- a/include/system/audio_policy.h
+++ b/include/system/audio_policy.h
@@ -44,9 +44,6 @@
     AUDIO_POLICY_FORCE_DIGITAL_DOCK,
     AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
     AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
-    AUDIO_POLICY_FORCE_SYSTEM_AUDIO_HDMI_ARC,
-    AUDIO_POLICY_FORCE_SYSTEM_AUDIO_SPDIF,
-    AUDIO_POLICY_FORCE_SYSTEM_AUDIO_LINE,
 
     AUDIO_POLICY_FORCE_CFG_CNT,
     AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
diff --git a/init/builtins.c b/init/builtins.c
index f7bd8a9..6032184 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -48,7 +48,7 @@
 
 #include <private/android_filesystem_config.h>
 
-void add_environment(const char *name, const char *value);
+int add_environment(const char *name, const char *value);
 
 extern int init_module(void *, unsigned long, const char *);
 
@@ -261,8 +261,7 @@
 
 int do_export(int nargs, char **args)
 {
-    add_environment(args[1], args[2]);
-    return 0;
+    return add_environment(args[1], args[2]);
 }
 
 int do_hostname(int nargs, char **args)
diff --git a/init/init.c b/init/init.c
index e4ac1cf..74c0308 100644
--- a/init/init.c
+++ b/init/init.c
@@ -96,11 +96,24 @@
 /* add_environment - add "key=value" to the current environment */
 int add_environment(const char *key, const char *val)
 {
-    int n;
+    size_t n;
+    size_t key_len = strlen(key);
 
-    for (n = 0; n < 31; n++) {
-        if (!ENV[n]) {
-            size_t len = strlen(key) + strlen(val) + 2;
+    /* The last environment entry is reserved to terminate the list */
+    for (n = 0; n < (ARRAY_SIZE(ENV) - 1); n++) {
+
+        /* Delete any existing entry for this key */
+        if (ENV[n] != NULL) {
+            size_t entry_key_len = strcspn(ENV[n], "=");
+            if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
+                free((char*)ENV[n]);
+                ENV[n] = NULL;
+            }
+        }
+
+        /* Add entry if a free slot is available */
+        if (ENV[n] == NULL) {
+            size_t len = key_len + strlen(val) + 2;
             char *entry = malloc(len);
             snprintf(entry, len, "%s=%s", key, val);
             ENV[n] = entry;
@@ -108,7 +121,9 @@
         }
     }
 
-    return 1;
+    ERROR("No env. room to store: '%s':'%s'\n", key, val);
+
+    return -1;
 }
 
 static void zap_stdio(void)
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index fa0792f..f8ffb1d 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -39,17 +39,9 @@
 
 #if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
 
-#include <linux/prctl.h>
-#include <sched.h>
 #include <pthread.h>
-
-#ifndef SCHED_NORMAL
-  #define SCHED_NORMAL 0
-#endif
-
-#ifndef SCHED_BATCH
-  #define SCHED_BATCH 3
-#endif
+#include <sched.h>
+#include <sys/prctl.h>
 
 #define POLICY_DEBUG 0
 
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
new file mode 100644
index 0000000..501321f
--- /dev/null
+++ b/libprocessgroup/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := processgroup.cpp
+LOCAL_MODULE := libprocessgroup
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_REQUIRED_MODULE := processgroup_cleanup
+include external/libcxx/libcxx.mk
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := cleanup.cpp
+LOCAL_MODULE := processgroup_cleanup
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc libcutils
+include $(BUILD_EXECUTABLE)
diff --git a/libprocessgroup/cleanup.cpp b/libprocessgroup/cleanup.cpp
new file mode 100644
index 0000000..cca8dc4
--- /dev/null
+++ b/libprocessgroup/cleanup.cpp
@@ -0,0 +1,31 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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 <string.h>
+#include <unistd.h>
+#include <sys/syslimits.h>
+
+#include "processgroup_priv.h"
+
+int main(int argc, char **argv)
+{
+    char buf[PATH_MAX];
+    if (argc != 2)
+        return -1;
+
+    memcpy(buf, PROCESSGROUP_CGROUP_PATH, sizeof(PROCESSGROUP_CGROUP_PATH));
+    strlcat(buf, argv[1], sizeof(buf));
+    return rmdir(buf);
+}
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
new file mode 100644
index 0000000..11bd8cc
--- /dev/null
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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 _PROCESSGROUP_H_
+#define _PROCESSGROUP_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+int killProcessGroup(uid_t uid, int initialPid, int signal);
+
+int createProcessGroup(uid_t uid, int initialPid);
+
+void removeAllProcessGroups(void);
+
+__END_DECLS
+
+#endif
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
new file mode 100644
index 0000000..c32e741
--- /dev/null
+++ b/libprocessgroup/processgroup.cpp
@@ -0,0 +1,316 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "libprocessgroup"
+
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <private/android_filesystem_config.h>
+
+#include <processgroup/processgroup.h>
+#include "processgroup_priv.h"
+
+struct ctx {
+    bool initialized;
+    int fd;
+    char buf[128];
+    char *buf_ptr;
+    size_t buf_len;
+};
+
+static int convertUidToPath(char *path, size_t size, uid_t uid)
+{
+    return snprintf(path, size, "%s/%s%d",
+            PROCESSGROUP_CGROUP_PATH,
+            PROCESSGROUP_UID_PREFIX,
+            uid);
+}
+
+static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
+{
+    return snprintf(path, size, "%s/%s%d/%s%d",
+            PROCESSGROUP_CGROUP_PATH,
+            PROCESSGROUP_UID_PREFIX,
+            uid,
+            PROCESSGROUP_PID_PREFIX,
+            pid);
+}
+
+static int initCtx(uid_t uid, int pid, struct ctx *ctx)
+{
+    int ret;
+    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+    convertUidPidToPath(path, sizeof(path), uid, pid);
+    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
+
+    int fd = open(path, O_RDONLY);
+    if (fd < 0) {
+        ret = -errno;
+        SLOGV("failed to open %s: %s", path, strerror(errno));
+        return ret;
+    }
+
+    ctx->fd = fd;
+    ctx->buf_ptr = ctx->buf;
+    ctx->buf_len = 0;
+    ctx->initialized = true;
+
+    return 0;
+}
+
+static int refillBuffer(struct ctx *ctx)
+{
+    memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
+    ctx->buf_ptr = ctx->buf;
+
+    ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
+                sizeof(ctx->buf) - ctx->buf_len);
+    if (ret < 0) {
+        return -errno;
+    } else if (ret == 0) {
+        return 0;
+    }
+
+    ctx->buf_len += ret;
+    assert(ctx->buf_len <= sizeof(ctx->buf));
+
+    return ret;
+}
+
+static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
+{
+    if (!ctx->initialized) {
+        int ret = initCtx(uid, appProcessPid, ctx);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    char *eptr;
+    while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
+        int ret = refillBuffer(ctx);
+        if (ret == 0) {
+            return -ERANGE;
+        }
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    *eptr = '\0';
+    char *pid_eptr = NULL;
+    errno = 0;
+    long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
+    if (errno != 0) {
+        return -errno;
+    }
+    if (pid_eptr != eptr) {
+        return -EINVAL;
+    }
+
+    ctx->buf_ptr = eptr + 1;
+
+    return (pid_t)pid;
+}
+
+static int removeProcessGroup(uid_t uid, int pid)
+{
+    int ret;
+    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+
+    convertUidPidToPath(path, sizeof(path), uid, pid);
+    ret = rmdir(path);
+
+    convertUidToPath(path, sizeof(path), uid);
+    rmdir(path);
+
+    return ret;
+}
+
+static void removeUidProcessGroups(const char *uid_path)
+{
+    DIR *uid = opendir(uid_path);
+    if (uid != NULL) {
+        struct dirent cur;
+        struct dirent *dir;
+        while ((readdir_r(uid, &cur, &dir) == 0) && dir) {
+            char path[PROCESSGROUP_MAX_PATH_LEN];
+
+            if (dir->d_type != DT_DIR) {
+                continue;
+            }
+
+            if (strncmp(dir->d_name, PROCESSGROUP_PID_PREFIX, strlen(PROCESSGROUP_PID_PREFIX))) {
+                continue;
+            }
+
+            snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
+            SLOGV("removing %s\n", path);
+            rmdir(path);
+        }
+    }
+}
+
+void removeAllProcessGroups()
+{
+    SLOGV("removeAllProcessGroups()");
+    DIR *root = opendir(PROCESSGROUP_CGROUP_PATH);
+    if (root == NULL) {
+        SLOGE("failed to open %s: %s", PROCESSGROUP_CGROUP_PATH, strerror(errno));
+    }
+    if (root != NULL) {
+        struct dirent cur;
+        struct dirent *dir;
+        while ((readdir_r(root, &cur, &dir) == 0) && dir) {
+            char path[PROCESSGROUP_MAX_PATH_LEN];
+
+            if (dir->d_type != DT_DIR) {
+                continue;
+            }
+            if (strncmp(dir->d_name, PROCESSGROUP_UID_PREFIX, strlen(PROCESSGROUP_UID_PREFIX))) {
+                continue;
+            }
+
+            snprintf(path, sizeof(path), "%s/%s", PROCESSGROUP_CGROUP_PATH, dir->d_name);
+            removeUidProcessGroups(path);
+            SLOGV("removing %s\n", path);
+            rmdir(path);
+        }
+    }
+}
+
+static int killProcessGroupOnce(uid_t uid, int initialPid, int signal)
+{
+    int processes = 0;
+    struct ctx ctx;
+    pid_t pid;
+
+    ctx.initialized = false;
+
+    while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
+        processes++;
+        SLOGV("sending processgroup kill to pid %d\n", pid);
+        int ret = kill(pid, signal);
+        if (ret == -1) {
+            SLOGV("failed to kill pid %d: %s", pid, strerror(errno));
+        }
+    }
+
+    if (ctx.initialized) {
+        close(ctx.fd);
+    }
+
+    return processes;
+}
+
+int killProcessGroup(uid_t uid, int initialPid, int signal)
+{
+    int processes;
+    int sleep_us = 100;
+
+    while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
+        SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
+        if (sleep_us < 128000) {
+            usleep(sleep_us);
+            sleep_us *= 2;
+        } else {
+            SLOGE("failed to kill %d processes for processgroup %d\n",
+                    processes, initialPid);
+            break;
+        }
+    }
+
+    if (processes == 0) {
+        return removeProcessGroup(uid, initialPid);
+    } else {
+        return -1;
+    }
+}
+
+static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+    int ret;
+
+    ret = mkdir(path, 0750);
+    if (ret < 0 && errno != EEXIST) {
+        return -errno;
+    }
+
+    ret = chown(path, AID_SYSTEM, AID_SYSTEM);
+    if (ret < 0) {
+        ret = -errno;
+        rmdir(path);
+        return ret;
+    }
+
+    return 0;
+}
+
+int createProcessGroup(uid_t uid, int initialPid)
+{
+    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+    int ret;
+
+    convertUidToPath(path, sizeof(path), uid);
+
+    ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
+    if (ret < 0) {
+        SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
+        return ret;
+    }
+
+    convertUidPidToPath(path, sizeof(path), uid, initialPid);
+
+    ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
+    if (ret < 0) {
+        SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
+        return ret;
+    }
+
+    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
+
+    int fd = open(path, O_WRONLY);
+    if (fd < 0) {
+        ret = -errno;
+        SLOGE("failed to open %s: %s", path, strerror(errno));
+        return ret;
+    }
+
+    char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
+    int len = snprintf(pid, sizeof(pid), "%d", initialPid);
+
+    ret = write(fd, pid, len);
+    if (ret < 0) {
+        ret = -errno;
+        SLOGE("failed to write '%s' to %s: %s", pid, path, strerror(errno));
+    } else {
+        ret = 0;
+    }
+
+    close(fd);
+    return ret;
+}
+
diff --git a/libprocessgroup/processgroup_priv.h b/libprocessgroup/processgroup_priv.h
new file mode 100644
index 0000000..1895bf9
--- /dev/null
+++ b/libprocessgroup/processgroup_priv.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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 _PROCESSGROUP_PRIV_H_
+#define _PROCESSGROUP_PRIV_H_
+
+#define PROCESSGROUP_CGROUP_PATH "/acct"
+#define PROCESSGROUP_UID_PREFIX "uid_"
+#define PROCESSGROUP_PID_PREFIX "pid_"
+#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
+#define PROCESSGROUP_MAX_UID_LEN 11
+#define PROCESSGROUP_MAX_PID_LEN 11
+#define PROCESSGROUP_MAX_PATH_LEN \
+        (sizeof(PROCESSGROUP_CGROUP_PATH) + \
+         sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
+         PROCESSGROUP_MAX_UID_LEN + \
+         sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
+         PROCESSGROUP_MAX_PID_LEN + \
+         sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
+         1)
+
+#endif
diff --git a/lmkd/Android.mk b/lmkd/Android.mk
index 2dd8af2..043a085 100644
--- a/lmkd/Android.mk
+++ b/lmkd/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := lmkd.c
-LOCAL_SHARED_LIBRARIES := libcutils liblog libm libc
+LOCAL_SHARED_LIBRARIES := libcutils liblog libm libc libprocessgroup
 LOCAL_CFLAGS := -Werror
 
 LOCAL_MODULE := lmkd
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 369b5ad..1aeb182 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -32,6 +32,7 @@
 
 #include <cutils/sockets.h>
 #include <log/log.h>
+#include <processgroup/processgroup.h>
 
 #ifndef __unused
 #define __unused __attribute__((__unused__))
@@ -591,6 +592,7 @@
                   other_file * page_k, minfree * page_k, min_score_adj,
                   other_free * page_k, other_free >= 0 ? "above" : "below");
             r = kill(pid, SIGKILL);
+            killProcessGroup(uid, pid, SIGKILL);
             pid_remove(pid);
 
             if (r) {
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 957fdb5..4bea4be 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -503,13 +503,11 @@
             (user_logger_content)     ? yes : no,
             (kernel_logger_available) ? yes : no,
             (kernel_logger_content)   ? yes : no,
-            (user_logger_available && kernel_logger_available) ? "WARNING" : "ok",
+            (user_logger_available && kernel_logger_available) ? "ERROR" : "ok",
             (user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
 
-    if (user_logger_available && kernel_logger_available) {
-        printf("WARNING: kernel & user logger; both consuming resources!!!\n");
-    }
-
+    EXPECT_EQ(0, user_logger_available && kernel_logger_available);
+    EXPECT_EQ(0, !user_logger_available && !kernel_logger_available);
     EXPECT_EQ(0, user_logger_content && kernel_logger_content);
     EXPECT_EQ(0, !user_logger_content && !kernel_logger_content);
 }
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
index a304631..abc3064 100644
--- a/toolbox/bsd-compatibility.h
+++ b/toolbox/bsd-compatibility.h
@@ -31,6 +31,9 @@
 /* We want chown to support user.group as well as user:group. */
 #define SUPPORT_DOT
 
+/* We don't localize /system/bin! */
+#define WITHOUT_NLS
+
 __BEGIN_DECLS
 
 extern int uid_from_user(const char* name, uid_t* uid);
diff --git a/toolbox/grep/grep.c b/toolbox/grep/grep.c
index 7b2c487..7314e13 100644
--- a/toolbox/grep/grep.c
+++ b/toolbox/grep/grep.c
@@ -159,7 +159,6 @@
 {
 	fprintf(stderr, getstr(4), __progname);
 	fprintf(stderr, "%s", getstr(5));
-	fprintf(stderr, "%s", getstr(5));
 	fprintf(stderr, "%s", getstr(6));
 	fprintf(stderr, "%s", getstr(7));
 	exit(2);
@@ -403,7 +402,7 @@
 				Aflag = 0;
 			else if (Aflag > LLONG_MAX / 10) {
 				errno = ERANGE;
-				err(2, "%llu", Aflag);
+				err(2, NULL);
 			}
 			Aflag = Bflag = (Aflag * 10) + (c - '0');
 			break;
@@ -420,10 +419,10 @@
 			l = strtoull(optarg, &ep, 10);
 			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
 			    ((errno == EINVAL) && (l == 0)))
-				err(2, "strtoull");
+				err(2, NULL);
 			else if (ep[0] != '\0') {
 				errno = EINVAL;
-				err(2, "empty");
+				err(2, NULL);
 			}
 			if (c == 'A')
 				Aflag = l;
@@ -509,10 +508,10 @@
 			mcount = strtoull(optarg, &ep, 10);
 			if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
 			    ((errno == EINVAL) && (mcount == 0)))
-				err(2, "strtoull");
+				err(2, NULL);
 			else if (ep[0] != '\0') {
 				errno = EINVAL;
-				err(2, "empty");
+				err(2, NULL);
 			}
 			break;
 		case 'n':
diff --git a/toolbox/grep/grep.h b/toolbox/grep/grep.h
index 6454f93..eafb00e 100644
--- a/toolbox/grep/grep.h
+++ b/toolbox/grep/grep.h
@@ -29,10 +29,6 @@
  * SUCH DAMAGE.
  */
 
-#ifdef ANDROID
-#define WITHOUT_NLS
-#endif
-
 #ifndef ANDROID
 #include <bzlib.h>
 #endif
diff --git a/toolbox/grep/util.c b/toolbox/grep/util.c
index 5712fee..ecd948d 100644
--- a/toolbox/grep/util.c
+++ b/toolbox/grep/util.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $	*/
+/*	$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $	*/
 /*	$FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $	*/
 /*	$OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $	*/
 
@@ -34,7 +34,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $");
+__RCSID("$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $");
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -74,9 +74,10 @@
 	for (i = 0; i < fpatterns; ++i) {
 		if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
 		    fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
-			if (fpattern[i].mode == EXCL_PAT)
+			if (fpattern[i].mode == EXCL_PAT) {
+				free(fname_copy);
 				return (false);
-			else
+			} else
 				ret = true;
 		}
 	}
@@ -128,7 +129,7 @@
 		break;
 	default:
 		fts_flags = FTS_LOGICAL;
-
+			
 	}
 
 	fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
@@ -273,7 +274,7 @@
 	return (c);
 }
 
-#define iswword(x)	(iswalnum((wint_t)(x)) || (x) == L'_')
+#define iswword(x)	(iswalnum((x)) || (x) == L'_')
 
 /*
  * Processes a line comparing it with the specified patterns.  Each pattern
@@ -474,13 +475,13 @@
 			if (!oflag)
 				fwrite(line->dat + a, matches[i].rm_so - a, 1,
 				    stdout);
-			if (color)
+			if (color) 
 				fprintf(stdout, "\33[%sm\33[K", color);
 
-				fwrite(line->dat + matches[i].rm_so,
+				fwrite(line->dat + matches[i].rm_so, 
 				    matches[i].rm_eo - matches[i].rm_so, 1,
 				    stdout);
-			if (color)
+			if (color) 
 				fprintf(stdout, "\33[m\33[K");
 			a = matches[i].rm_eo;
 			if (oflag)