Merge "AArch64: Use negative values in error enumeration"
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 4c2f247..dcda005 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -116,15 +116,24 @@
             umount(target);
         }
 
-        INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
+        /*
+         * Some system images do not have e2fsck for licensing reasons
+         * (e.g. recent SDK system images). Detect these and skip the check.
+         */
+        if (access(E2FSCK_BIN, X_OK)) {
+            INFO("Not running %s on %s (executable not in system image)\n",
+                 E2FSCK_BIN, blk_device);
+        } else {
+            INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
 
-        ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
-                                      &status, true, LOG_KLOG | LOG_FILE,
-                                      true, FSCK_LOG_FILE);
+            ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
+                                        &status, true, LOG_KLOG | LOG_FILE,
+                                        true, FSCK_LOG_FILE);
 
-        if (ret < 0) {
-            /* No need to check for error in fork, we can't really handle it now */
-            ERROR("Failed trying to run %s\n", E2FSCK_BIN);
+            if (ret < 0) {
+                /* No need to check for error in fork, we can't really handle it now */
+                ERROR("Failed trying to run %s\n", E2FSCK_BIN);
+            }
         }
     }
 
diff --git a/include/log/log_read.h b/include/log/log_read.h
index 861c192..2601622 100644
--- a/include/log/log_read.h
+++ b/include/log/log_read.h
@@ -23,12 +23,12 @@
 #ifdef __cplusplus
 struct log_time : public timespec {
 public:
-    log_time(timespec &T)
+    log_time(const timespec &T)
     {
         tv_sec = T.tv_sec;
         tv_nsec = T.tv_nsec;
     }
-    log_time(void)
+    log_time()
     {
     }
     log_time(clockid_t id)
@@ -67,7 +67,7 @@
     {
         return !(*this > T);
     }
-    uint64_t nsec(void) const
+    uint64_t nsec() const
     {
         return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
     }
diff --git a/include/log/logger.h b/include/log/logger.h
index 966397a..6414d84 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -35,7 +35,7 @@
 /*
  * The userspace structure for version 2 of the logger_entry ABI.
  * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version==2
+ * is called with version==2; or used with the user space log daemon.
  */
 struct logger_entry_v2 {
     uint16_t    len;       /* length of the payload */
@@ -48,6 +48,17 @@
     char        msg[0];    /* the entry's payload */
 };
 
+struct logger_entry_v3 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v2) */
+    int32_t     pid;       /* generating process's pid */
+    int32_t     tid;       /* generating process's tid */
+    int32_t     sec;       /* seconds since Epoch */
+    int32_t     nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload */
+    char        msg[0];    /* the entry's payload */
+};
+
 /*
  * The maximum size of the log entry payload that can be
  * written to the kernel logger driver. An attempt to write
@@ -69,6 +80,7 @@
     union {
         unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
         struct logger_entry_v2 entry;
+        struct logger_entry_v3 entry_v3;
         struct logger_entry_v2 entry_v2;
         struct logger_entry    entry_v1;
         struct {
@@ -106,21 +118,21 @@
     {
         return !(*this > T);
     }
-    uint64_t nsec(void) const
+    uint64_t nsec() const
     {
         return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
     }
 
     /* packet methods */
-    log_id_t id(void)
+    log_id_t id()
     {
         return extra.id;
     }
-    char *msg(void)
+    char *msg()
     {
         return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
     }
-    unsigned int len(void)
+    unsigned int len()
     {
         return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
     }
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 0ed0d78..9c26baf 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -76,6 +76,7 @@
 #define AID_SDCARD_PICS   1033  /* external storage photos access */
 #define AID_SDCARD_AV     1034  /* external storage audio/video access */
 #define AID_SDCARD_ALL    1035  /* access all users external storage */
+#define AID_LOGD          1036  /* log daemon */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -151,6 +152,7 @@
     { "sdcard_pics",   AID_SDCARD_PICS, },
     { "sdcard_av",     AID_SDCARD_AV, },
     { "sdcard_all",    AID_SDCARD_ALL, },
+    { "logd",          AID_LOGD, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/init/devices.c b/init/devices.c
index f7df453..a70c61d 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -37,7 +37,6 @@
 
 #include <private/android_filesystem_config.h>
 #include <sys/time.h>
-#include <asm/page.h>
 #include <sys/wait.h>
 
 #include <cutils/list.h>
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 33af0a3..2e56756 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -47,7 +47,7 @@
 	libgccdemangle \
 
 # To enable using libunwind on each arch, add it to this list.
-libunwind_architectures := arm arm64 x86 x86_64
+libunwind_architectures := arm arm64 mips x86 x86_64
 
 ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
 libbacktrace_src_files += \
diff --git a/libcutils/socket_local_server.c b/libcutils/socket_local_server.c
index 4971b1b..7628fe4 100644
--- a/libcutils/socket_local_server.c
+++ b/libcutils/socket_local_server.c
@@ -43,6 +43,8 @@
 
 #define LISTEN_BACKLOG 4
 
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
 
 /**
  * Binds a pre-created socket(AF_LOCAL) 's' to 'name'
@@ -107,7 +109,7 @@
         return -1;
     }
 
-    if (type == SOCK_STREAM) {
+    if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
         int ret;
 
         ret = listen(s, LISTEN_BACKLOG);
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
deleted file mode 100644
index 6571161..0000000
--- a/libcutils/tests/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(all-subdir-makefiles)
diff --git a/libcutils/tests/memset_mips/Android.mk b/libcutils/tests/memset_mips/Android.mk
deleted file mode 100644
index c22fca9..0000000
--- a/libcutils/tests/memset_mips/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-
-ifeq ($(TARGET_ARCH),mips)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	test_memset.c \
-	android_memset_dumb.S \
-	android_memset_test.S \
-	memset_cmips.S \
-	memset_omips.S
-
-LOCAL_MODULE:= test_memset
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_STATIC_LIBRARIES := libcutils libc
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/libcutils/tests/memset_mips/android_memset_dumb.S b/libcutils/tests/memset_mips/android_memset_dumb.S
deleted file mode 100644
index c8a1a37..0000000
--- a/libcutils/tests/memset_mips/android_memset_dumb.S
+++ /dev/null
@@ -1,36 +0,0 @@
-	.global	android_memset16_dumb
-	.type   android_memset16_dumb, @function
-android_memset16_dumb:
-        .ent	android_memset16_dumb
-
-	.set	noreorder
-	beqz	$a2,9f
-	 srl	$a2,1
-
-1:	sh	$a1,($a0)
-	subu	$a2,1
-	bnez	$a2,1b
-	 addu	$a0,2
-	.set reorder
-
-9:	j	$ra
-        .end	android_memset16_dumb
-	.size	android_memset16_dumb,.-android_memset16_dumb
-
-	.global android_memset32_dumb
-	.type	android_memset32_dumb, @function
-android_memset32_dumb:
-        .ent	android_memset32_dumb
-	.set	noreorder
-	beqz	$a2,9f
-	 srl	$a2,2
-
-1:	sw	$a1,($a0)
-	subu	$a2,1
-	bnez	$a2,1b
-	 addu	$a0,4
-	.set reorder
-
-9:	j	$ra
-        .end	android_memset32_dumb
-	.size	android_memset32_dumb,.-android_memset32_dumb
diff --git a/libcutils/tests/memset_mips/android_memset_test.S b/libcutils/tests/memset_mips/android_memset_test.S
deleted file mode 100644
index e918843..0000000
--- a/libcutils/tests/memset_mips/android_memset_test.S
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-#ifdef NDEBUG
-#define DBG #
-#else
-#define DBG
-#endif
-
-	.text
-	.align
-
-        /*
-         * Optimized memset16 for MIPS
-         *
-         * void android_memset16_test(uint16_t* dst, uint16_t value, size_t size);
-         *
-         */
-
-	.global	android_memset16_test
-	.type   android_memset16_test, @function
-android_memset16_test:
-        .ent	android_memset16_test
-	.set	noreorder
-
-	/* Check parameters */
-DBG	andi	$t0,$a0,1	/* $a0 must be halfword aligned */
-DBG	tne	$t0
-DBG	lui	$t1,0xffff	/* $a1 must be 16bits */
-DBG	and	$t1,$a1
-DBG	tne	$t1
-DBG	andi	$t2,$a2,1	/* $a2 must be even */
-DBG	tne	$t2
-
-#if (__mips==32) && (__mips_isa_rev>=2)
-	ins	$a2,$0,0,1
-#else
-	li	$t0,~1
-	and	$a2,$t0
-#endif
-
-	move	$t8,$ra
-	blez	$a2,9f		/* Anything to do? */
-	 andi	$t0,$a0,2	/* Check dst alignment */
-	/* Expand value to 32 bits and check destination alignment */
-#if (__mips==32) && (__mips_isa_rev>=2)
-	beqz	$t0,.Laligned32	/* dst is 32 bit aligned */
-	 ins	$a1,$a1,16,16
-#else
-	sll	$t2,$a1,16
-	beqz	$t0,.Laligned32	/* dst is 32 bit aligned */
-	 or	$a1,$t2
-#endif
-	sh	$a1,($a0)	/* do one halfword to get aligned */
-	subu	$a2,2
-	addu	$a0,2
-
-.Laligned32:
-	and	$t1,$a2,63	/* is there enough left to do a full 64 byte loop? */
-	beq	$a2,$t1,1f
-	 subu	$t2,$a2,$t1	/* $t2 is the number of bytes to do in loop64 */
-	addu	$t3,$a0,$t2	/* $t3 is the end marker for loop64 */
-	subu	$a2,$t2
-.Lloop64:
-	addu	$a0,64
-	sw	$a1,-64($a0)
-	sw	$a1,-60($a0)
-	sw	$a1,-56($a0)
-	sw	$a1,-52($a0)
-	sw	$a1,-48($a0)
-	sw	$a1,-44($a0)
-	sw	$a1,-40($a0)
-	sw	$a1,-36($a0)
-	sw	$a1,-32($a0)
-	sw	$a1,-28($a0)
-	sw	$a1,-24($a0)
-	sw	$a1,-20($a0)
-	sw	$a1,-16($a0)
-	sw	$a1,-12($a0)
-	sw	$a1,-8($a0)
-	bne	$a0,$t3,.Lloop64
-	sw	$a1,-4($a0)
-
-	/* Do the last 0..62 bytes */
-1:	li	$t0,64+12
-	andi	$t1,$a2,0x3c	/* $t1 how many bytes to store using sw */
-	bal	1f
-	 subu	$t0,$t1		/* 64+12-$t0 is offset to jump from 1f */
-1:	addu	$ra,$t0
-	j	$ra
-	 subu	$a2,$t1
-2:	sw	$a1,60($a0)
-	sw	$a1,56($a0)
-	sw	$a1,52($a0)
-	sw	$a1,48($a0)
-	sw	$a1,44($a0)
-	sw	$a1,40($a0)
-	sw	$a1,36($a0)
-	sw	$a1,32($a0)
-	sw	$a1,28($a0)
-	sw	$a1,24($a0)
-	sw	$a1,20($a0)
-	sw	$a1,16($a0)
-	sw	$a1,12($a0)
-	sw	$a1,8($a0)
-	sw	$a1,4($a0)
-	sw	$a1,0($a0)
-
-	beqz	$a2,9f
-	 addu	$a0,$t1
-	sh	$a1,($a0)
-
-9:	j	$t8
-	 nop
-        .end	android_memset16_test
-	.size	android_memset16_test,.-android_memset16_test
-
-        /*
-         * Optimized memset32 for MIPS
-         *
-         * void android_memset32_test(uint32_t* dst, uint32_t value, size_t size);
-         *
-         */
-	.global android_memset32_test
-	.type	android_memset32_test, @function
-android_memset32_test:
-        .ent	android_memset32_test
-	.set	noreorder
-
-	/* Check parameters */
-DBG	andi	$t0,$a0,3	/* $a0 must be word aligned */
-DBG	tne	$t0
-DBG	andi	$t2,$a2,3	/* $a2 must be a multiple of 4 bytes */
-DBG	tne	$t2
-
-	b	.Laligned32
-	 move	$t8,$ra
-        .end	android_memset32_test
-	.size	android_memset32_test,.-android_memset32_test
diff --git a/libcutils/tests/memset_mips/memset_cmips.S b/libcutils/tests/memset_mips/memset_cmips.S
deleted file mode 100644
index f8f3a91..0000000
--- a/libcutils/tests/memset_mips/memset_cmips.S
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (c) 2009
- *      MIPS Technologies, Inc., California.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/************************************************************************
- *
- *  memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
- *  Version: "043009"
- *
- ************************************************************************/
-
-
-/************************************************************************
- *  Include files
- ************************************************************************/
-
-#include "machine/asm.h"
-
-/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
- */
-
-#if defined(__MIPSEB__)
-#  define SWHI	swl		/* high part is left in big-endian	*/
-#endif
-
-#if defined(__MIPSEL__)
-#  define SWHI	swr		/* high part is right in little-endian	*/
-#endif
-
-#if !(defined(XGPROF) || defined(XPROF))
-#undef SETUP_GP
-#define SETUP_GP
-#endif
-
-LEAF(memset_cmips,0)
-
-	.set	noreorder
-	.set	noat
-
-	addu	t0,a0,a2		# t0 is the "past the end" address
-	slti	AT,a2,4			# is a2 less than 4?
-	bne	AT,zero,.Llast4		# if yes, go to last4
-	move	v0,a0			# memset returns the dst pointer
-
-	beq	a1,zero,.Lset0
-	subu	v1,zero,a0
-
-	# smear byte into 32 bit word
-#if (__mips==32) && (__mips_isa_rev>=2)
-	ins     a1, a1, 8, 8        # Replicate fill byte into half-word.
-	ins     a1, a1, 16, 16      # Replicate fill byte into word.
-#else
-	and	a1,0xff
-	sll	AT,a1,8
-	or	a1,AT
-	sll	AT,a1,16
-	or	a1,AT
-#endif
-
-.Lset0:	andi	v1,v1,0x3		# word-unaligned address?
-	beq	v1,zero,.Laligned	# v1 is the unalignment count
-	subu	a2,a2,v1
-	SWHI	a1,0(a0)
-	addu	a0,a0,v1
-
-# Here we have the "word-aligned" a0 (until the "last4")
-.Laligned:
-	andi	t8,a2,0x3f	# any 64-byte chunks?
-				# t8 is the byte count past 64-byte chunks
-	beq	a2,t8,.Lchk8w	# when a2==t8, no 64-byte chunks
-				# There will be at most 1 32-byte chunk then
-	subu	a3,a2,t8	# subtract from a2 the reminder
-				# Here a3 counts bytes in 16w chunks
-	addu	a3,a0,a3	# Now a3 is the final dst after 64-byte chunks
-
-# Find out, if there are any 64-byte chunks after which will be still at least
-# 96 bytes left. The value "96" is calculated as needed buffer for
-# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
-# incrementing "a0" by 64.
-# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
-#
-	sltiu	v1,a2,160
-	bgtz	v1,.Lloop16w_nopref30	# skip "pref 30,0(a0)"
-	subu	t7,a2,96	# subtract "pref 30 unsafe" region
-		# below we have at least 1 64-byte chunk which is "pref 30 safe"
-	andi	t6,t7,0x3f	# t6 is past "64-byte safe chunks" reminder
-	subu	t5,t7,t6	# subtract from t7 the reminder
-				# Here t5 counts bytes in 16w "safe" chunks
-	addu	t4,a0,t5	# Now t4 is the dst after 64-byte "safe" chunks
-
-# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
-#	pref	30,0(a0)
-# Here we are in the region, where it is safe to use "pref 30,64(a0)"
-.Lloop16w:
-	addiu	a0,a0,64
-	pref	30,-32(a0)	# continue setting up the dest, addr 64-32
-	sw	a1,-64(a0)
-	sw	a1,-60(a0)
-	sw	a1,-56(a0)
-	sw	a1,-52(a0)
-	sw	a1,-48(a0)
-	sw	a1,-44(a0)
-	sw	a1,-40(a0)
-	sw	a1,-36(a0)
-	nop
-	nop			# the extra nop instructions help to balance
-	nop			# cycles needed for "store" + "fill" + "evict"
-	nop			# For 64byte store there are needed 8 fill
-	nop			# and 8 evict cycles, i.e. at least 32 instr.
-	nop
-	nop
-	pref	30,0(a0)	# continue setting up the dest, addr 64-0
-	sw	a1,-32(a0)
-	sw	a1,-28(a0)
-	sw	a1,-24(a0)
-	sw	a1,-20(a0)
-	sw	a1,-16(a0)
-	sw	a1,-12(a0)
-	sw	a1,-8(a0)
-	sw	a1,-4(a0)
-	nop
-	nop
-	nop
-	nop			# NOTE: adding 14 nop-s instead of 12 nop-s
-	nop			# gives better results for "fast" memory
-	nop
-	bne	a0,t4,.Lloop16w
-	nop
-
-	beq	a0,a3,.Lchk8w	# maybe no more 64-byte chunks?
-	nop			# this "delayed slot" is useless ...
-
-.Lloop16w_nopref30:	# there could be up to 3 "64-byte nopref30" chunks
-	addiu	a0,a0,64
-	sw	a1,-64(a0)
-	sw	a1,-60(a0)
-	sw	a1,-56(a0)
-	sw	a1,-52(a0)
-	sw	a1,-48(a0)
-	sw	a1,-44(a0)
-	sw	a1,-40(a0)
-	sw	a1,-36(a0)
-	sw	a1,-32(a0)
-	sw	a1,-28(a0)
-	sw	a1,-24(a0)
-	sw	a1,-20(a0)
-	sw	a1,-16(a0)
-	sw	a1,-12(a0)
-	sw	a1,-8(a0)
-	bne	a0,a3,.Lloop16w_nopref30
-	sw	a1,-4(a0)
-
-.Lchk8w:		# t8 here is the byte count past 64-byte chunks
-
-	andi	t7,t8,0x1f	# is there a 32-byte chunk?
-				# the t7 is the reminder count past 32-bytes
-	beq	t8,t7,.Lchk1w	# when t8==t7, no 32-byte chunk
-	move	a2,t7
-
-	sw	a1,0(a0)
-	sw	a1,4(a0)
-	sw	a1,8(a0)
-	sw	a1,12(a0)
-	sw	a1,16(a0)
-	sw	a1,20(a0)
-	sw	a1,24(a0)
-	sw	a1,28(a0)
-	addiu	a0,a0,32
-
-.Lchk1w:
-	andi	t8,a2,0x3	# now t8 is the reminder past 1w chunks
-	beq	a2,t8,.Llast4
-	subu	a3,a2,t8	# a3 is the count of bytes in 1w chunks
-	addu	a3,a0,a3	# now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
-	addiu	a0,a0,4
-	bne	a0,a3,.LwordCopy_loop
-	sw	a1,-4(a0)
-
-.Llast4:beq	a0,t0,.Llast4e
-.Llast4l:addiu	a0,a0,1
-	bne	a0,t0,.Llast4l
-	sb	a1,-1(a0)
-
-.Llast4e:
-	j	ra
-	nop
-
-	.set	at
-	.set	reorder
-
-END(memset_cmips)
-
-
-/************************************************************************
- *  Implementation : Static functions
- ************************************************************************/
-
diff --git a/libcutils/tests/memset_mips/memset_omips.S b/libcutils/tests/memset_mips/memset_omips.S
deleted file mode 100644
index 4c47001..0000000
--- a/libcutils/tests/memset_mips/memset_omips.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-/* void *memset_omips(void *s, int c, size_t n).  */
-
-#include "machine/asm.h"
-
-#ifdef __mips64
-#error mips32 code being compiled for mips64!
-#endif
-
-#if defined(__MIPSEB__)
-#error big-endian is not supported in Broadcom MIPS Android platform
-# define SWHI	swl		/* high part is left in big-endian	*/
-#else
-# define SWHI	swr		/* high part is right in little-endian	*/
-#endif
-
-LEAF (memset_omips,0)
-	.set	noreorder
-
-	slti	t1, a2, 8		# Less than 8?
-	bne	t1, zero, .Llast8
-	move	v0, a0			# Setup exit value before too late
-
-	beq	a1, zero, .Lueven	# If zero pattern, no need to extend
-	andi	a1, 0xff		# Avoid problems with bogus arguments
-	sll	t0, a1, 8
-	or	a1, t0
-	sll	t0, a1, 16
-	or	a1, t0			# a1 is now pattern in full word
-
-.Lueven:
-	subu	t0, zero, a0		# Unaligned address?
-	andi	t0, 0x3
-	beq	t0, zero, .Lchkw
-	subu	a2, t0
-	SWHI	a1, 0(a0)		# Yes, handle first unaligned part
-	addu	a0, t0			# Now both a0 and a2 are updated
-
-.Lchkw:
-	andi	t0, a2, 0x7		# Enough left for one loop iteration?
-	beq	t0, a2, .Lchkl
-	subu	a3, a2, t0
-	addu	a3, a0			# a3 is last loop address +1
-	move	a2, t0			# a2 is now # of bytes left after loop
-.Lloopw:
-	addiu	a0, 8			# Handle 2 words pr. iteration
-	sw	a1, -8(a0)
-	bne	a0, a3, .Lloopw
-	sw	a1, -4(a0)
-
-.Lchkl:
-	andi	t0, a2, 0x4		# Check if there is at least a full
-	beq	t0, zero, .Llast8	#  word remaining after the loop
-	subu	a2, t0
-	sw	a1, 0(a0)		# Yes...
-	addiu	a0, 4
-
-.Llast8:
-	blez	a2, .Lexit		# Handle last 8 bytes (if cnt>0)
-	addu	a3, a2, a0		# a3 is last address +1
-.Llst8l:
-	addiu	a0, 1
-	bne	a0, a3, .Llst8l
-	sb	a1, -1(a0)
-.Lexit:
-	j	ra			# Bye, bye
-	nop
-
-	.set	reorder
-END (memset_omips)
-
-
diff --git a/libcutils/tests/memset_mips/test_memset.c b/libcutils/tests/memset_mips/test_memset.c
deleted file mode 100644
index 9705c65..0000000
--- a/libcutils/tests/memset_mips/test_memset.c
+++ /dev/null
@@ -1,235 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <cutils/memory.h>
-#include <time.h>
-
-/*
- * All systems must implement or emulate the rdhwr instruction to read
- * the userlocal register. Systems that emulate also return teh count register
- * when accessing register $2 so this should work on most systems
- */
-#define USE_RDHWR
-
-#ifdef USE_RDHWR
-#define UNITS "cycles"
-#define SCALE 2			/* Most CPU's */
-static inline uint32_t
-get_count(void)
-{
-  uint32_t res;
-  asm volatile (".set push; .set mips32r2; rdhwr %[res],$2; .set pop" : [res] "=r" (res) : : "memory");
-  return res;
-}
-#else
-#define UNITS "ns"
-#define SCALE 1
-static inline uint32_t
-get_count(void)
-{
-  struct timespec now;
-  uint32_t res;
-  clock_gettime(CLOCK_REALTIME, &now);
-  res = (uint32_t)(now.tv_sec * 1000000000LL + now.tv_nsec);
-  // printf ("now=%d.%09d res=%d\n", (int)now.tv_sec, (int)now.tv_nsec, res);
-  return res;
-}
-#endif
-
-uint32_t overhead;
-void
-measure_overhead(void)
-{
-  int i;
-  uint32_t start, stop, delta;
-  for (i = 0; i < 32; i++) {
-    start = get_count();
-    stop = get_count();
-    delta = stop - start;
-    if (overhead == 0 || delta < overhead)
-      overhead = delta;
-  }
-  printf("overhead is %d"UNITS"\n", overhead);
-}
-
-uint32_t
-timeone(void (*fn)(), void *d, uint32_t val, uint32_t bytes)
-{
-  uint32_t start, stop, delta;
-  start = get_count();
-  (*fn)(d, val, bytes);
-  stop = get_count();
-  delta = stop - start - overhead;
-  // printf ("start=0x%08x stop=0x%08x delta=0x%08x\n", start, stop, delta);
-  return delta * SCALE;
-}
-
-/* define VERIFY to check that memset only touches the bytes it's supposed to */
-/*#define VERIFY*/
-
-/*
- * Using a big arena means that memset will most likely miss in the cache
- * NB Enabling verification effectively warms up the cache...
- */
-#define ARENASIZE 0x1000000
-#ifdef VERIFY
-char arena[ARENASIZE+8];	/* Allow space for guard words */
-#else
-char arena[ARENASIZE];
-#endif
-
-void
-testone(char *tag, void (*fn)(), int trials, int minbytes, int maxbytes, int size, int threshold)
-{
-  int offset;
-  void *d;
-  void *p;
-  uint32_t v, notv = 0;
-  uint32_t n;
-  int i, units;
-  int totalunits = 0, totalbytes = 0, samples = 0;
-
-  /* Reset RNG to ensure each test uses same random values */
-  srand(0);			/* FIXME should be able to use some other seed than 0 */
-
-  for (i = 0; i < trials; i++) {
-    n = minbytes + (rand() % (maxbytes-minbytes));	/* How many bytes to do */
-    offset = ((rand() % (ARENASIZE-n)));		/* Where to start */
-
-#ifdef VERIFY
-    offset += 4;		/* Allow space for guard word at beginning */
-#endif
-    v = rand();
-
-    /* Adjust alignment and sizes based on transfer size */
-    switch (size) {
-    case 1:
-      v &= 0xff;
-      notv = ~v & 0xff;
-      break;
-    case 2:
-      v &= 0xffff;
-      notv = ~v & 0xffff;
-      offset &= ~1;
-      n &= ~1;
-      break;
-    case 4:
-      notv = ~v;
-      offset &= ~3;
-      n &= ~3;
-      break;
-    }
-
-    d = &arena[offset];
-
-#ifdef VERIFY
-    /* Initialise the area and guard words */
-    for (p = &arena[offset-4]; p < (void *)&arena[offset+n+4]; p = (void *)((uint32_t)p + size)) {
-      if (size == 1)
-	*(uint8_t *)p = notv;
-      else if (size == 2)
-	*(uint16_t *)p = notv;
-      else if (size == 4)
-	*(uint32_t *)p = notv;
-    }
-#endif
-    units = timeone(fn, d, v, n);
-#ifdef VERIFY
-    /* Check the area and guard words */
-    for (p = &arena[offset-4]; p < (void *)&arena[offset+n+4]; p = (void *)((uint32_t)p + size)) {
-      uint32_t got = 0;
-      if (size == 1)
-	got = *(uint8_t *)p;
-      else if (size == 2)
-	got = *(uint16_t *)p;
-      else if (size == 4)
-	got = *(uint32_t *)p;
-      if (p < (void *)&arena[offset]) {
-	if (got != notv)
-	  printf ("%s: verify failure: preguard:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, got, n);
-      }
-      else if (p < (void *)&arena[offset+n]) {
-	if (got != v)
-	  printf ("%s: verify failure: arena:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, n);
-      }
-      else {
-	if (got != notv)
-	  printf ("%s: verify failure: postguard:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, n);
-      }
-    }
-#endif
-
-    /* If the cycle count looks reasonable include it in the statistics */
-    if (units < threshold) {
-      totalbytes += n;
-      totalunits += units;
-      samples++;
-    }
-  }
-
-  printf("%s: samples=%d avglen=%d avg" UNITS "=%d bp"UNITS"=%g\n",
-	 tag, samples, totalbytes/samples, totalunits/samples, (double)totalbytes/(double)totalunits);
-}
-
-extern void android_memset32_dumb(uint32_t* dst, uint32_t value, size_t size);
-extern void android_memset16_dumb(uint32_t* dst, uint16_t value, size_t size);
-extern void android_memset32_test(uint32_t* dst, uint32_t value, size_t size);
-extern void android_memset16_test(uint32_t* dst, uint16_t value, size_t size);
-extern void memset_cmips(void* dst, int value, size_t size);
-extern void memset_omips(void* dst, int value, size_t size);
-
-int
-main(int argc, char **argv)
-{
-  int i;
-  struct {
-    char *type;
-    int trials;
-    int minbytes, maxbytes;
-  } *pp, params[] = {
-    {"small",  10000,   0,   64},
-    {"medium", 10000,  64,  512},
-    {"large",  10000, 512, 1280},
-    {"varied", 10000,   0, 1280},
-  };
-#define NPARAMS (sizeof(params)/sizeof(params[0]))
-  struct {
-    char *name;
-    void (*fn)();
-    int size;
-  } *fp, functions[] = {
-    {"dmemset16", (void (*)())android_memset16_dumb, 2},
-    {"tmemset16", (void (*)())android_memset16_test, 2},
-    {"lmemset16", (void (*)())android_memset16,      2},
-
-    {"dmemset32", (void (*)())android_memset32_dumb, 4},
-    {"tmemset32", (void (*)())android_memset32_test, 4},
-    {"lmemset32", (void (*)())android_memset32,      4},
-
-    {"cmemset",    (void (*)())memset_cmips,         1},
-    {"omemset",    (void (*)())memset_omips,         1},
-    {"lmemset",    (void (*)())memset,               1},
-  };
-#define NFUNCTIONS (sizeof(functions)/sizeof(functions[0]))
-  char tag[40];
-  int threshold;
-
-  measure_overhead();
-
-  /* Warm up the page cache */
-  memset(arena, 0xff, ARENASIZE); /* use 0xff now to avoid COW later */
-
-  for (fp = functions; fp < &functions[NFUNCTIONS]; fp++) {
-    (fp->fn)(arena, 0xffffffff, ARENASIZE);	/* one call to get the code into Icache */
-    for (pp = params; pp < &params[NPARAMS]; pp++) {
-      sprintf(tag, "%10s: %7s %4d-%4d", fp->name, pp->type, pp->minbytes, pp->maxbytes);
-
-      /* Set the cycle threshold */
-      threshold = pp->maxbytes * 4 * 10;	/* reasonable for cycles and ns */
-      testone(tag, fp->fn, pp->trials, pp->minbytes, pp->maxbytes, fp->size, threshold);
-    }
-    printf ("\n");
-  }
-
-  return 0;
-}
diff --git a/libpixelflinger/buffer.cpp b/libpixelflinger/buffer.cpp
index cbdab5a..dcb95c5 100644
--- a/libpixelflinger/buffer.cpp
+++ b/libpixelflinger/buffer.cpp
@@ -130,7 +130,7 @@
     }
 }
 
-void readRGB565(const surface_t* s, context_t* c,
+void readRGB565(const surface_t* s, context_t* /*c*/,
         uint32_t x, uint32_t y, pixel_t* pixel)
 {
     uint16_t v = *(reinterpret_cast<uint16_t*>(s->data) + (x + (s->stride * y)));
@@ -144,7 +144,7 @@
     pixel->s[3] = 5;
 }
 
-void readABGR8888(const surface_t* s, context_t* c,
+void readABGR8888(const surface_t* s, context_t* /*c*/,
         uint32_t x, uint32_t y, pixel_t* pixel)
 {
     uint32_t v = *(reinterpret_cast<uint32_t*>(s->data) + (x + (s->stride * y)));
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index f37072a..bd11818 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -273,7 +273,7 @@
     *mPC++ = (0x54 << 24) | cc;
 }
 
-void ArmToArm64Assembler::BL(int cc, const char* label)
+void ArmToArm64Assembler::BL(int /*cc*/, const char* /*label*/)
 {
     NOT_IMPLEMENTED(); //Not Required
 }
@@ -289,7 +289,7 @@
     *mPC++ = A64_MOVZ_X(mZeroReg,0,0);
 }
 
-void ArmToArm64Assembler::epilog(uint32_t touched)
+void ArmToArm64Assembler::epilog(uint32_t /*touched*/)
 {
     // write epilog code
     static const int XLR = 30;
@@ -530,23 +530,23 @@
     if(s  != 0) { NOT_IMPLEMENTED(); return;} //Not required
     *mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
 }
-void ArmToArm64Assembler::UMULL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::UMULL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::UMUAL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::UMUAL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SMULL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::SMULL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SMUAL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::SMUAL(int /*cc*/, int /*s*/,
+        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -554,15 +554,15 @@
 // ----------------------------------------------------------------------------
 // branches relative to PC...
 // ----------------------------------------------------------------------------
-void ArmToArm64Assembler::B(int cc, uint32_t* pc){
+void ArmToArm64Assembler::B(int /*cc*/, uint32_t* /*pc*/){
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::BL(int cc, uint32_t* pc){
+void ArmToArm64Assembler::BL(int /*cc*/, uint32_t* /*pc*/){
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::BX(int cc, int Rn){
+void ArmToArm64Assembler::BX(int /*cc*/, int /*Rn*/){
     NOT_IMPLEMENTED(); //Not required
 }
 
@@ -661,11 +661,11 @@
 {
     return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
 }
-void ArmToArm64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSB(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSH(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -723,15 +723,15 @@
 // ----------------------------------------------------------------------------
 // special...
 // ----------------------------------------------------------------------------
-void ArmToArm64Assembler::SWP(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWP(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SWPB(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWPB(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
-void ArmToArm64Assembler::SWI(int cc, uint32_t comment)
+void ArmToArm64Assembler::SWI(int /*cc*/, uint32_t /*comment*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -739,31 +739,31 @@
 // ----------------------------------------------------------------------------
 // DSP instructions...
 // ----------------------------------------------------------------------------
-void ArmToArm64Assembler::PLD(int Rn, uint32_t offset) {
+void ArmToArm64Assembler::PLD(int /*Rn*/, uint32_t /*offset*/) {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::CLZ(int cc, int Rd, int Rm)
+void ArmToArm64Assembler::CLZ(int /*cc*/, int /*Rd*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QADD(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QDADD(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QSUB(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
 
-void ArmToArm64Assembler::QDSUB(int cc,  int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
 }
@@ -817,15 +817,15 @@
     *mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
 }
 
-void ArmToArm64Assembler::SMLAL(int cc, int xy,
-                int RdHi, int RdLo, int Rs, int Rm)
+void ArmToArm64Assembler::SMLAL(int /*cc*/, int /*xy*/,
+                int /*RdHi*/, int /*RdLo*/, int /*Rs*/, int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return;
 }
 
-void ArmToArm64Assembler::SMLAW(int cc, int y,
-                int Rd, int Rm, int Rs, int Rn)
+void ArmToArm64Assembler::SMLAW(int /*cc*/, int /*y*/,
+                int /*Rd*/, int /*Rm*/, int /*Rs*/, int /*Rn*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return;
@@ -890,13 +890,13 @@
     return OPERAND_REG_IMM;
 }
 
-uint32_t ArmToArm64Assembler::reg_rrx(int Rm)
+uint32_t ArmToArm64Assembler::reg_rrx(int /*Rm*/)
 {
     NOT_IMPLEMENTED();
     return OPERAND_UNSUPPORTED;
 }
 
-uint32_t ArmToArm64Assembler::reg_reg(int Rm, int type, int Rs)
+uint32_t ArmToArm64Assembler::reg_reg(int /*Rm*/, int /*type*/, int /*Rs*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return OPERAND_UNSUPPORTED;
@@ -937,7 +937,7 @@
     }
 }
 
-uint32_t ArmToArm64Assembler::reg_scale_post(int Rm, int type, uint32_t shift)
+uint32_t ArmToArm64Assembler::reg_scale_post(int /*Rm*/, int /*type*/, uint32_t /*shift*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return OPERAND_UNSUPPORTED;
@@ -975,7 +975,7 @@
     }
 }
 
-uint32_t ArmToArm64Assembler::reg_post(int Rm)
+uint32_t ArmToArm64Assembler::reg_post(int /*Rm*/)
 {
     NOT_IMPLEMENTED(); //Not required
     return OPERAND_UNSUPPORTED;
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 2422d7b..325caba 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -694,7 +694,7 @@
 // ---------------------------------------------------------------------------
 
 void GGLAssembler::build_alpha_test(component_t& fragment,
-                                    const fragment_parts_t& parts)
+                                    const fragment_parts_t& /*parts*/)
 {
     if (mAlphaTest != GGL_ALWAYS) {
         comment("Alpha Test");
@@ -796,7 +796,7 @@
     }
 }
 
-void GGLAssembler::build_iterate_f(const fragment_parts_t& parts)
+void GGLAssembler::build_iterate_f(const fragment_parts_t& /*parts*/)
 {
     const needs_t& needs = mBuilderContext.needs;
     if (GGL_READ_NEEDS(P_FOG, needs.p)) {
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index b2cfbb3..81950bf 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -694,7 +694,7 @@
 }
 
 void GGLAssembler::filter8(
-        const fragment_parts_t& parts,
+        const fragment_parts_t& /*parts*/,
         pixel_t& texel, const texture_unit_t& tmu,
         int U, int V, pointer_t& txPtr,
         int FRAC_BITS)
@@ -761,7 +761,7 @@
 }
 
 void GGLAssembler::filter16(
-        const fragment_parts_t& parts,
+        const fragment_parts_t& /*parts*/,
         pixel_t& texel, const texture_unit_t& tmu,
         int U, int V, pointer_t& txPtr,
         int FRAC_BITS)
@@ -879,10 +879,10 @@
 }
 
 void GGLAssembler::filter24(
-        const fragment_parts_t& parts,
-        pixel_t& texel, const texture_unit_t& tmu,
-        int U, int V, pointer_t& txPtr,
-        int FRAC_BITS)
+        const fragment_parts_t& /*parts*/,
+        pixel_t& texel, const texture_unit_t& /*tmu*/,
+        int /*U*/, int /*V*/, pointer_t& txPtr,
+        int /*FRAC_BITS*/)
 {
     // not supported yet (currently disabled)
     load(txPtr, texel, 0);
@@ -989,8 +989,8 @@
 }
 #else
 void GGLAssembler::filter32(
-        const fragment_parts_t& parts,
-        pixel_t& texel, const texture_unit_t& tmu,
+        const fragment_parts_t& /*parts*/,
+        pixel_t& texel, const texture_unit_t& /*tmu*/,
         int U, int V, pointer_t& txPtr,
         int FRAC_BITS)
 {
diff --git a/libpixelflinger/picker.cpp b/libpixelflinger/picker.cpp
index 030ef19..aa55229 100644
--- a/libpixelflinger/picker.cpp
+++ b/libpixelflinger/picker.cpp
@@ -26,7 +26,7 @@
 
 // ----------------------------------------------------------------------------
 
-void ggl_init_picker(context_t* c)
+void ggl_init_picker(context_t* /*c*/)
 {
 }
 
diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp
index 84e584e..ea5bc8e 100644
--- a/libpixelflinger/pixelflinger.cpp
+++ b/libpixelflinger/pixelflinger.cpp
@@ -662,7 +662,7 @@
     }
 }
 
-void ggl_enable_stencil_test(context_t* c, int enable)
+void ggl_enable_stencil_test(context_t* /*c*/, int /*enable*/)
 {
 }
 
diff --git a/libpixelflinger/raster.cpp b/libpixelflinger/raster.cpp
index 32b2a97..26d8e45 100644
--- a/libpixelflinger/raster.cpp
+++ b/libpixelflinger/raster.cpp
@@ -51,7 +51,7 @@
 }
 
 void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
-        GGLsizei width, GGLsizei height, GGLenum type)
+        GGLsizei width, GGLsizei height, GGLenum /*type*/)
 {
     GGL_CONTEXT(c, con);
 
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index aa23ca6..cd78713 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -534,7 +534,7 @@
     return x;
 }
 
-void blend_factor(context_t* c, pixel_t* r, 
+void blend_factor(context_t* /*c*/, pixel_t* r, 
         uint32_t factor, const pixel_t* src, const pixel_t* dst)
 {
     switch (factor) {
@@ -1161,7 +1161,7 @@
  *   blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
  */
 struct blender_32to16 {
-    blender_32to16(context_t* c) { }
+    blender_32to16(context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (s == 0)
             return;
@@ -1218,7 +1218,7 @@
  * where dstFactor=srcA*(1-srcA) srcFactor=srcA
  */
 struct blender_32to16_srcA {
-    blender_32to16_srcA(const context_t* c) { }
+    blender_32to16_srcA(const context_t* /*c*/) { }
     void write(uint32_t s, uint16_t* dst) {
         if (!s) {
             return;
@@ -2317,7 +2317,7 @@
     memset(dst, 0xFF, size);
 }
 
-void scanline_noop(context_t* c)
+void scanline_noop(context_t* /*c*/)
 {
 }
 
diff --git a/libpixelflinger/tests/gglmul/gglmul_test.cpp b/libpixelflinger/tests/gglmul/gglmul_test.cpp
index 073368e..5d460d6 100644
--- a/libpixelflinger/tests/gglmul/gglmul_test.cpp
+++ b/libpixelflinger/tests/gglmul/gglmul_test.cpp
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdint.h>
+#include <inttypes.h>
 
 #include "private/pixelflinger/ggl_fixed.h"
 
@@ -260,12 +261,12 @@
         if(actual == expected)
             printf(" Passed\n");
         else
-            printf(" Failed Actual(%ld) Expected(%ld)\n",
+            printf(" Failed Actual(%" PRId64 ") Expected(%" PRId64 ")\n",
                     actual, expected);
     }
 }
 
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
 {
     gglClampx_test();
     gglClz_test();
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index 9565cc5..acfc020 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-LOCAL_PATH := $(my-dir)
+LOCAL_PATH := $(call my-dir)
 
 # Static library for Linux host
 # ========================================================
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index e852d77..8acb4d4 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -323,8 +323,17 @@
 
 status_t String8::appendFormatV(const char* fmt, va_list args)
 {
-    int result = NO_ERROR;
-    int n = vsnprintf(NULL, 0, fmt, args);
+    int n, result = NO_ERROR;
+    va_list tmp_args;
+
+    /* args is undefined after vsnprintf.
+     * So we need a copy here to avoid the
+     * second vsnprintf access undefined args.
+     */
+    va_copy(tmp_args, args);
+    n = vsnprintf(NULL, 0, fmt, tmp_args);
+    va_end(tmp_args);
+
     if (n != 0) {
         size_t oldLength = length();
         char* buf = lockBuffer(oldLength + n);
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index f963a3a..fc696bb 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -319,12 +319,16 @@
 
 TEST(logcat, blocking) {
     FILE *fp;
-    unsigned long long v = 0xDEADBEEFA55A0000ULL;
+    unsigned long long v = 0xDEADBEEFA55F0000ULL;
 
     pid_t pid = getpid();
 
     v += pid & 0xFFFF;
 
+    LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+
+    v &= 0xFFFFFFFFFFFAFFFFULL;
+
     ASSERT_EQ(0, NULL == (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events 2>&1",
@@ -341,12 +345,12 @@
     while (fgets(buffer, sizeof(buffer), fp)) {
         alarm(2);
 
-        ++count;
-
         if (!strncmp(buffer, "DONE", 4)) {
             break;
         }
 
+        ++count;
+
         int p;
         unsigned long long l;
 
@@ -369,7 +373,7 @@
 
     pclose(fp);
 
-    ASSERT_LT(10, count);
+    ASSERT_LE(2, count);
 
     ASSERT_EQ(1, signals);
 }
@@ -385,12 +389,16 @@
 
 TEST(logcat, blocking_tail) {
     FILE *fp;
-    unsigned long long v = 0xA55ADEADBEEF0000ULL;
+    unsigned long long v = 0xA55FDEADBEEF0000ULL;
 
     pid_t pid = getpid();
 
     v += pid & 0xFFFF;
 
+    LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+
+    v &= 0xFFFAFFFFFFFFFFFFULL;
+
     ASSERT_EQ(0, NULL == (fp = popen(
       "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
       " logcat -b events -T 5 2>&1",
@@ -407,12 +415,12 @@
     while (fgets(buffer, sizeof(buffer), fp)) {
         alarm(2);
 
-        ++count;
-
         if (!strncmp(buffer, "DONE", 4)) {
             break;
         }
 
+        ++count;
+
         int p;
         unsigned long long l;
 
@@ -431,13 +439,91 @@
     alarm(0);
     signal(SIGALRM, SIG_DFL);
 
-    /* Generate SIGPIPE */
+    // Generate SIGPIPE
     fclose(fp);
     caught_blocking_tail(0);
 
     pclose(fp);
 
-    ASSERT_LT(5, count);
+    ASSERT_LE(2, count);
+
+    ASSERT_EQ(1, signals);
+}
+
+static void caught_blocking_clear(int signum)
+{
+    unsigned long long v = 0xDEADBEEFA55C0000ULL;
+
+    v += getpid() & 0xFFFF;
+
+    LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+}
+
+TEST(logcat, blocking_clear) {
+    FILE *fp;
+    unsigned long long v = 0xDEADBEEFA55C0000ULL;
+
+    pid_t pid = getpid();
+
+    v += pid & 0xFFFF;
+
+    // This test is racey; an event occurs between clear and dump.
+    // We accept that we will get a false positive, but never a false negative.
+    ASSERT_EQ(0, NULL == (fp = popen(
+      "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
+      " logcat -b events -c 2>&1 ;"
+      " logcat -b events 2>&1",
+      "r")));
+
+    char buffer[5120];
+
+    int count = 0;
+
+    int signals = 0;
+
+    signal(SIGALRM, caught_blocking_clear);
+    alarm(2);
+    while (fgets(buffer, sizeof(buffer), fp)) {
+        alarm(2);
+
+        if (!strncmp(buffer, "clearLog: ", 10)) {
+            fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
+            count = signals = 1;
+            break;
+        }
+
+        if (!strncmp(buffer, "DONE", 4)) {
+            break;
+        }
+
+        ++count;
+
+        int p;
+        unsigned long long l;
+
+        if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
+         || (p != pid)) {
+            continue;
+        }
+
+        if (l == v) {
+            if (count > 1) {
+                fprintf(stderr, "WARNING: Possible false positive\n");
+            }
+            ++signals;
+            break;
+        }
+    }
+    alarm(0);
+    signal(SIGALRM, SIG_DFL);
+
+    // Generate SIGPIPE
+    fclose(fp);
+    caught_blocking_clear(0);
+
+    pclose(fp);
+
+    ASSERT_LE(1, count);
 
     ASSERT_EQ(1, signals);
 }
diff --git a/logd/Android.mk b/logd/Android.mk
new file mode 100644
index 0000000..f536dad
--- /dev/null
+++ b/logd/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= logd
+
+LOCAL_SRC_FILES := \
+    main.cpp \
+    LogCommand.cpp \
+    CommandListener.cpp \
+    LogListener.cpp \
+    LogReader.cpp \
+    FlushCommand.cpp \
+    LogBuffer.cpp \
+    LogBufferElement.cpp \
+    LogTimes.cpp
+
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
+
+LOCAL_SHARED_LIBRARIES := \
+    libsysutils \
+    liblog \
+    libcutils
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
new file mode 100644
index 0000000..f5cb8dc
--- /dev/null
+++ b/logd/CommandListener.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012-2013 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 <arpa/inet.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <sysutils/SocketClient.h>
+#include <private/android_filesystem_config.h>
+
+#include "CommandListener.h"
+
+CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
+                                 LogListener * /*swl*/)
+        : FrameworkListener("logd")
+        , mBuf(*buf) {
+    // registerCmd(new ShutdownCmd(buf, writer, swl));
+    registerCmd(new ClearCmd(buf));
+    registerCmd(new GetBufSizeCmd(buf));
+    registerCmd(new GetBufSizeUsedCmd(buf));
+}
+
+CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
+                                          LogListener *swl)
+        : LogCommand("shutdown")
+        , mBuf(*buf)
+        , mReader(*reader)
+        , mSwl(*swl)
+{ }
+
+int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
+                                             int /*argc*/,
+                                             char ** /*argv*/) {
+    mSwl.stopListener();
+    mReader.stopListener();
+    exit(0);
+}
+
+CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
+        : LogCommand("clear")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::ClearCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    if ((cli->getUid() != AID_ROOT)
+            && (cli->getGid() != AID_ROOT)
+            && (cli->getGid() != AID_LOG)) {
+        cli->sendMsg("Permission Denied");
+        return 0;
+    }
+
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if ((id < LOG_ID_MIN) || (id >= LOG_ID_MAX)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    mBuf.clear((log_id_t) id);
+    cli->sendMsg("success");
+    return 0;
+}
+
+
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
+        : LogCommand("getLogSize")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if ((id < LOG_ID_MIN) || (id >= LOG_ID_MAX)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    unsigned long size = mBuf.getSize((log_id_t) id);
+    char buf[512];
+    snprintf(buf, sizeof(buf), "%lu", size);
+    cli->sendMsg(buf);
+    return 0;
+}
+
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
+        : LogCommand("getLogSizeUsed")
+        , mBuf(*buf)
+{ }
+
+int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
+                                         int argc, char **argv) {
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int id = atoi(argv[1]);
+    if ((id < LOG_ID_MIN) || (id >= LOG_ID_MAX)) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    unsigned long size = mBuf.getSizeUsed((log_id_t) id);
+    char buf[512];
+    snprintf(buf, sizeof(buf), "%lu", size);
+    cli->sendMsg(buf);
+    return 0;
+}
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
new file mode 100644
index 0000000..861abbf
--- /dev/null
+++ b/logd/CommandListener.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012-2014 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 _COMMANDLISTENER_H__
+#define _COMMANDLISTENER_H__
+
+#include <sysutils/FrameworkListener.h>
+#include "LogCommand.h"
+#include "LogBuffer.h"
+#include "LogReader.h"
+#include "LogListener.h"
+
+class CommandListener : public FrameworkListener {
+    LogBuffer &mBuf;
+
+public:
+    CommandListener(LogBuffer *buf, LogReader *reader, LogListener *swl);
+    virtual ~CommandListener() {}
+
+private:
+    class ShutdownCmd : public LogCommand {
+        LogBuffer &mBuf;
+        LogReader &mReader;
+        LogListener &mSwl;
+
+    public:
+        ShutdownCmd(LogBuffer *buf, LogReader *reader, LogListener *swl);
+        virtual ~ShutdownCmd() {}
+        int runCommand(SocketClient *c, int argc, char ** argv);
+    };
+
+#define LogBufferCmd(name)                                       \
+    class name##Cmd : public LogCommand {                        \
+        LogBuffer &mBuf;                                         \
+    public:                                                      \
+        name##Cmd(LogBuffer *buf);                               \
+        virtual ~name##Cmd() {}                                  \
+        int runCommand(SocketClient *c, int argc, char ** argv); \
+    };
+
+    LogBufferCmd(Clear)
+    LogBufferCmd(GetBufSize)
+    LogBufferCmd(GetBufSizeUsed)
+};
+
+#endif
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
new file mode 100644
index 0000000..f6f8cb8
--- /dev/null
+++ b/logd/FlushCommand.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012-2013 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 <stdlib.h>
+#include <private/android_filesystem_config.h>
+#include "FlushCommand.h"
+#include "LogBufferElement.h"
+#include "LogTimes.h"
+#include "LogReader.h"
+
+FlushCommand::FlushCommand(LogReader &reader,
+                           bool nonBlock,
+                           unsigned long tail,
+                           unsigned int logMask,
+                           pid_t pid)
+        : mReader(reader)
+        , mNonBlock(nonBlock)
+        , mTail(tail)
+        , mLogMask(logMask)
+        , mPid(pid)
+{ }
+
+// runSocketCommand is called once for every open client on the
+// log reader socket. Here we manage and associated the reader
+// client tracking and log region locks LastLogTimes list of
+// LogTimeEntrys, and spawn a transitory per-client thread to
+// work at filing data to the  socket.
+//
+// global LogTimeEntry::lock() is used to protect access,
+// reference counts are used to ensure that individual
+// LogTimeEntry lifetime is managed when not protected.
+void FlushCommand::runSocketCommand(SocketClient *client) {
+    LogTimeEntry *entry = NULL;
+    LastLogTimes &times = mReader.logbuf().mTimes;
+
+    LogTimeEntry::lock();
+    LastLogTimes::iterator it = times.begin();
+    while(it != times.end()) {
+        entry = (*it);
+        if (entry->mClient == client) {
+            entry->triggerReader_Locked();
+            if (entry->runningReader_Locked()) {
+                LogTimeEntry::unlock();
+                return;
+            }
+            entry->incRef_Locked();
+            break;
+        }
+        it++;
+    }
+
+    if (it == times.end()) {
+        // Create LogTimeEntry in notifyNewLog() ?
+        if (mTail == (unsigned long) -1) {
+            LogTimeEntry::unlock();
+            return;
+        }
+        entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid);
+        times.push_back(entry);
+    }
+
+    client->incRef();
+
+    // release client and entry reference counts once done
+    entry->startReader_Locked();
+    LogTimeEntry::unlock();
+}
+
+bool FlushCommand::hasReadLogs(SocketClient *client) {
+    return (client->getUid() == AID_ROOT)
+            || (client->getGid() == AID_ROOT)
+            || (client->getGid() == AID_LOG);
+}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
new file mode 100644
index 0000000..715daac
--- /dev/null
+++ b/logd/FlushCommand.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012-2013 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 _FLUSH_COMMAND_H
+#define _FLUSH_COMMAND_H
+
+#include <sysutils/SocketClientCommand.h>
+
+class LogReader;
+
+class FlushCommand : public SocketClientCommand {
+    LogReader &mReader;
+    bool mNonBlock;
+    unsigned long mTail;
+    unsigned int mLogMask;
+    pid_t mPid;
+
+public:
+    FlushCommand(LogReader &mReader,
+                 bool nonBlock = false,
+                 unsigned long tail = -1,
+                 unsigned int logMask = -1,
+                 pid_t pid = 0);
+    virtual void runSocketCommand(SocketClient *client);
+
+    static bool hasReadLogs(SocketClient *client);
+};
+
+#endif
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
new file mode 100644
index 0000000..7340a36
--- /dev/null
+++ b/logd/LogBuffer.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2012-2014 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 <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <log/logger.h>
+
+#include "LogBuffer.h"
+#include "LogReader.h"
+
+#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
+
+LogBuffer::LogBuffer(LastLogTimes *times)
+        : mTimes(*times) {
+    int i;
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        mSizes[i] = 0;
+        mElements[i] = 0;
+    }
+    pthread_mutex_init(&mLogElementsLock, NULL);
+}
+
+void LogBuffer::log(log_id_t log_id, struct timespec realtime,
+                    uid_t uid, pid_t pid, const char *msg,
+                    unsigned short len) {
+    if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
+        return;
+    }
+    LogBufferElement *elem = new LogBufferElement(log_id, realtime,
+                                                  uid, pid, msg, len);
+
+    pthread_mutex_lock(&mLogElementsLock);
+
+    // Insert elements in time sorted order if possible
+    //  NB: if end is region locked, place element at end of list
+    LogBufferElementCollection::iterator it = mLogElements.end();
+    LogBufferElementCollection::iterator last = it;
+    while (--it != mLogElements.begin()) {
+        if ((*it)->getRealTime() <= realtime) {
+            break;
+        }
+        last = it;
+    }
+
+    if (last == mLogElements.end()) {
+        mLogElements.push_back(elem);
+    } else {
+        log_time end;
+        bool end_set = false;
+        bool end_always = false;
+
+        LogTimeEntry::lock();
+
+        LastLogTimes::iterator t = mTimes.begin();
+        while(t != mTimes.end()) {
+            LogTimeEntry *entry = (*t);
+            if (entry->owned_Locked()) {
+                if (!entry->mNonBlock) {
+                    end_always = true;
+                    break;
+                }
+                if (!end_set || (end <= entry->mEnd)) {
+                    end = entry->mEnd;
+                    end_set = true;
+                }
+            }
+            t++;
+        }
+
+        if (end_always
+                || (end_set && (end >= (*last)->getMonotonicTime()))) {
+            mLogElements.push_back(elem);
+        } else {
+            mLogElements.insert(last,elem);
+        }
+
+        LogTimeEntry::unlock();
+    }
+
+    mSizes[log_id] += len;
+    mElements[log_id]++;
+    maybePrune(log_id);
+    pthread_mutex_unlock(&mLogElementsLock);
+}
+
+// If we're using more than 256K of memory for log entries, prune
+// at least 10% of the log entries.
+//
+// mLogElementsLock must be held when this function is called.
+void LogBuffer::maybePrune(log_id_t id) {
+    unsigned long sizes = mSizes[id];
+    if (sizes > LOG_BUFFER_SIZE) {
+        unsigned long sizeOver90Percent = sizes - ((LOG_BUFFER_SIZE * 9) / 10);
+        unsigned long elements = mElements[id];
+        unsigned long pruneRows = elements * sizeOver90Percent / sizes;
+        elements /= 10;
+        if (pruneRows <= elements) {
+            pruneRows = elements;
+        }
+        prune(id, pruneRows);
+    }
+}
+
+// prune "pruneRows" of type "id" from the buffer.
+//
+// mLogElementsLock must be held when this function is called.
+void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
+    LogTimeEntry *oldest = NULL;
+
+    LogTimeEntry::lock();
+
+    // Region locked?
+    LastLogTimes::iterator t = mTimes.begin();
+    while(t != mTimes.end()) {
+        LogTimeEntry *entry = (*t);
+        if (entry->owned_Locked()
+                && (!oldest || (oldest->mStart > entry->mStart))) {
+            oldest = entry;
+        }
+        t++;
+    }
+
+    LogBufferElementCollection::iterator it = mLogElements.begin();
+    while((pruneRows > 0) && (it != mLogElements.end())) {
+        LogBufferElement *e = *it;
+        if (e->getLogId() == id) {
+            if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+                if (mSizes[id] > (2 * LOG_BUFFER_SIZE)) {
+                    // kick a misbehaving log reader client off the island
+                    oldest->release_Locked();
+                } else {
+                    oldest->triggerSkip_Locked(pruneRows);
+                }
+                break;
+            }
+            it = mLogElements.erase(it);
+            mSizes[id] -= e->getMsgLen();
+            mElements[id]--;
+            delete e;
+            pruneRows--;
+        } else {
+            it++;
+        }
+    }
+
+    LogTimeEntry::unlock();
+}
+
+// clear all rows of type "id" from the buffer.
+void LogBuffer::clear(log_id_t id) {
+    pthread_mutex_lock(&mLogElementsLock);
+    prune(id, ULONG_MAX);
+    pthread_mutex_unlock(&mLogElementsLock);
+}
+
+// get the used space associated with "id".
+unsigned long LogBuffer::getSizeUsed(log_id_t id) {
+    pthread_mutex_lock(&mLogElementsLock);
+    unsigned long retval = mSizes[id];
+    pthread_mutex_unlock(&mLogElementsLock);
+    return retval;
+}
+
+// get the total space allocated to "id"
+unsigned long LogBuffer::getSize(log_id_t /*id*/) {
+    return LOG_BUFFER_SIZE;
+}
+
+struct timespec LogBuffer::flushTo(
+        SocketClient *reader, const struct timespec start, bool privileged,
+        bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
+    LogBufferElementCollection::iterator it;
+    log_time max = start;
+    uid_t uid = reader->getUid();
+
+    pthread_mutex_lock(&mLogElementsLock);
+    for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
+        LogBufferElement *element = *it;
+
+        if (!privileged && (element->getUid() != uid)) {
+            continue;
+        }
+
+        if (element->getMonotonicTime() <= start) {
+            continue;
+        }
+
+        // NB: calling out to another object with mLogElementsLock held (safe)
+        if (filter && !(*filter)(element, arg)) {
+            continue;
+        }
+
+        pthread_mutex_unlock(&mLogElementsLock);
+
+        // range locking in LastLogTimes looks after us
+        max = element->flushTo(reader);
+
+        if (max == element->FLUSH_ERROR) {
+            return max;
+        }
+
+        pthread_mutex_lock(&mLogElementsLock);
+    }
+    pthread_mutex_unlock(&mLogElementsLock);
+
+    return max;
+}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
new file mode 100644
index 0000000..7c69f1b
--- /dev/null
+++ b/logd/LogBuffer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012-2014 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 _LOGD_LOG_BUFFER_H__
+#define _LOGD_LOG_BUFFER_H__
+
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <sysutils/SocketClient.h>
+#include <utils/List.h>
+
+#include "LogBufferElement.h"
+#include "LogTimes.h"
+
+typedef android::List<LogBufferElement *> LogBufferElementCollection;
+
+class LogBuffer {
+    LogBufferElementCollection mLogElements;
+    pthread_mutex_t mLogElementsLock;
+
+    unsigned long mSizes[LOG_ID_MAX];
+    unsigned long mElements[LOG_ID_MAX];
+
+public:
+    LastLogTimes &mTimes;
+
+    LogBuffer(LastLogTimes *times);
+
+    void log(log_id_t log_id, struct timespec realtime,
+             uid_t uid, pid_t pid, const char *msg, unsigned short len);
+    struct timespec flushTo(SocketClient *writer, const struct timespec start,
+                            bool privileged,
+                            bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
+                            void *arg = NULL);
+
+    void clear(log_id_t id);
+    unsigned long getSize(log_id_t id);
+    unsigned long getSizeUsed(log_id_t id);
+
+private:
+    void maybePrune(log_id_t id);
+    void prune(log_id_t id, unsigned long pruneRows);
+
+};
+
+#endif
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
new file mode 100644
index 0000000..1c55623
--- /dev/null
+++ b/logd/LogBufferElement.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012-2014 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 <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <log/logger.h>
+
+#include "LogBufferElement.h"
+#include "LogReader.h"
+
+const struct timespec LogBufferElement::FLUSH_ERROR = { 0, 0 };
+
+LogBufferElement::LogBufferElement(log_id_t log_id, struct timespec realtime, uid_t uid, pid_t pid, const char *msg, unsigned short len)
+        : mLogId(log_id)
+        , mUid(uid)
+        , mPid(pid)
+        , mMsgLen(len)
+        , mMonotonicTime(CLOCK_MONOTONIC)
+        , mRealTime(realtime) {
+    mMsg = new char[len];
+    memcpy(mMsg, msg, len);
+}
+
+LogBufferElement::~LogBufferElement() {
+    delete [] mMsg;
+}
+
+struct timespec LogBufferElement::flushTo(SocketClient *reader) {
+    struct logger_entry_v3 entry;
+    memset(&entry, 0, sizeof(struct logger_entry_v3));
+    entry.hdr_size = sizeof(struct logger_entry_v3);
+    entry.len = mMsgLen;
+    entry.lid = mLogId;
+    entry.pid = mPid;
+    entry.sec = mRealTime.tv_sec;
+    entry.nsec = mRealTime.tv_nsec;
+
+    struct iovec iovec[2];
+    iovec[0].iov_base = &entry;
+    iovec[0].iov_len = sizeof(struct logger_entry_v3);
+    iovec[1].iov_base = mMsg;
+    iovec[1].iov_len = mMsgLen;
+    if (reader->sendDatav(iovec, 2)) {
+        return FLUSH_ERROR;
+    }
+
+    return mMonotonicTime;
+}
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
new file mode 100644
index 0000000..390c97c
--- /dev/null
+++ b/logd/LogBufferElement.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012-2014 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 _LOGD_LOG_BUFFER_ELEMENT_H__
+#define _LOGD_LOG_BUFFER_ELEMENT_H__
+
+#include <sys/types.h>
+#include <sysutils/SocketClient.h>
+#include <log/log.h>
+#include <log/log_read.h>
+
+class LogBufferElement {
+    const log_id_t mLogId;
+    const uid_t mUid;
+    const pid_t mPid;
+    char *mMsg;
+    const unsigned short mMsgLen;
+    const log_time mMonotonicTime;
+    const log_time mRealTime;
+
+public:
+    LogBufferElement(log_id_t log_id, struct timespec realtime,
+                     uid_t uid, pid_t pid, const char *msg, unsigned short len);
+    virtual ~LogBufferElement();
+
+    log_id_t getLogId() const { return mLogId; }
+    uid_t getUid(void) const { return mUid; }
+    pid_t getPid(void) const { return mPid; }
+    unsigned short getMsgLen() const { return mMsgLen; }
+    log_time getMonotonicTime(void) const { return mMonotonicTime; }
+    log_time getRealTime(void) const { return mRealTime; }
+
+    static const struct timespec FLUSH_ERROR;
+    struct timespec flushTo(SocketClient *writer);
+};
+
+#endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
new file mode 100644
index 0000000..6ccc93e
--- /dev/null
+++ b/logd/LogCommand.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012-2013 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 "LogCommand.h"
+
+LogCommand::LogCommand(const char *cmd)
+        : FrameworkCommand(cmd) {
+}
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
new file mode 100644
index 0000000..aef6706
--- /dev/null
+++ b/logd/LogCommand.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012-2013 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 _LOGD_COMMAND_H
+#define _LOGD_COMMAND_H
+
+#include <sysutils/FrameworkCommand.h>
+
+class LogCommand : public FrameworkCommand {
+public:
+    LogCommand(const char *cmd);
+    virtual ~LogCommand() {}
+};
+
+#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
new file mode 100644
index 0000000..c6b248b
--- /dev/null
+++ b/logd/LogListener.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012-2014 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 <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/logger.h>
+
+#include "LogListener.h"
+
+LogListener::LogListener(LogBuffer *buf, LogReader *reader)
+        : SocketListener(getLogSocket(), false)
+        , logbuf(buf)
+        , reader(reader)
+{  }
+
+bool LogListener::onDataAvailable(SocketClient *cli) {
+    char buffer[1024];
+    struct iovec iov = { buffer, sizeof(buffer) };
+    memset(buffer, 0, sizeof(buffer));
+
+    char control[CMSG_SPACE(sizeof(struct ucred))];
+    struct msghdr hdr = {
+        NULL,
+        0,
+        &iov,
+        1,
+        control,
+        sizeof(control),
+        0,
+    };
+
+    int socket = cli->getSocket();
+
+    ssize_t n = recvmsg(socket, &hdr, 0);
+    if (n <= (ssize_t) sizeof_log_id_t) {
+        return false;
+    }
+
+    struct ucred *cred = NULL;
+
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+    while (cmsg != NULL) {
+        if (cmsg->cmsg_level == SOL_SOCKET
+                && cmsg->cmsg_type  == SCM_CREDENTIALS) {
+            cred = (struct ucred *)CMSG_DATA(cmsg);
+            break;
+        }
+        cmsg = CMSG_NXTHDR(&hdr, cmsg);
+    }
+
+    if (cred == NULL) {
+        return false;
+    }
+
+    if (cred->uid == getuid()) {
+        // ignore log messages we send to ourself.
+        // Such log messages are often generated by libraries we depend on
+        // which use standard Android logging.
+        return false;
+    }
+
+    // First log element is always log_id.
+    log_id_t log_id = (log_id_t) *((typeof_log_id_t *) buffer);
+    if (log_id < 0 || log_id >= LOG_ID_MAX) {
+        return false;
+    }
+
+    char *msg = ((char *)buffer) + sizeof_log_id_t;
+    n -= sizeof_log_id_t;
+
+    log_time realtime(msg);
+    msg += sizeof(log_time);
+    n -= sizeof(log_time);
+
+    unsigned short len = n;
+    if (len == n) {
+        logbuf->log(log_id, realtime, cred->uid, cred->pid, msg, len);
+        reader->notifyNewLog();
+    }
+
+    return true;
+}
+
+int LogListener::getLogSocket() {
+    int sock = android_get_control_socket("logdw");
+    int on = 1;
+    if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+        return -1;
+    }
+    return sock;
+}
diff --git a/logd/LogListener.h b/logd/LogListener.h
new file mode 100644
index 0000000..7099e13
--- /dev/null
+++ b/logd/LogListener.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-2013 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 _LOGD_LOG_LISTENER_H__
+#define _LOGD_LOG_LISTENER_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogReader.h"
+
+class LogListener : public SocketListener {
+    LogBuffer *logbuf;
+    LogReader *reader;
+
+public:
+    LogListener(LogBuffer *buf, LogReader *reader);
+
+protected:
+    virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+    static int getLogSocket();
+};
+
+#endif
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
new file mode 100644
index 0000000..5b540bf
--- /dev/null
+++ b/logd/LogReader.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012-2013 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 <poll.h>
+#include <sys/socket.h>
+#include <cutils/sockets.h>
+
+#include "LogReader.h"
+#include "FlushCommand.h"
+
+LogReader::LogReader(LogBuffer *logbuf)
+        : SocketListener("logdr", true)
+        , mLogbuf(*logbuf)
+{ }
+
+// When we are notified a new log entry is available, inform
+// all of our listening sockets.
+void LogReader::notifyNewLog() {
+    FlushCommand command(*this);
+    runOnEachSocket(&command);
+}
+
+bool LogReader::onDataAvailable(SocketClient *cli) {
+    char buffer[255];
+
+    int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
+    if (len <= 0) {
+        doSocketDelete(cli);
+        return false;
+    }
+    buffer[len] = '\0';
+
+    unsigned long tail = 0;
+    static const char _tail[] = " tail=";
+    char *cp = strstr(buffer, _tail);
+    if (cp) {
+        tail = atol(cp + sizeof(_tail) - 1);
+    }
+
+    unsigned int logMask = -1;
+    static const char _logIds[] = " lids=";
+    cp = strstr(buffer, _logIds);
+    if (cp) {
+        logMask = 0;
+        cp += sizeof(_logIds) - 1;
+        while (*cp && *cp != '\0') {
+            int val = 0;
+            while (('0' <= *cp) && (*cp <= '9')) {
+                val *= 10;
+                val += *cp - '0';
+                ++cp;
+            }
+            logMask |= 1 << val;
+            if (*cp != ',') {
+                break;
+            }
+            ++cp;
+        }
+    }
+
+    pid_t pid = 0;
+    static const char _pid[] = " pid=";
+    cp = strstr(buffer, _pid);
+    if (cp) {
+        pid = atol(cp + sizeof(_pid) - 1);
+    }
+
+    bool nonBlock = false;
+    if (strncmp(buffer, "dumpAndClose", 12) == 0) {
+        nonBlock = true;
+    }
+
+    FlushCommand command(*this, nonBlock, tail, logMask, pid);
+    command.runSocketCommand(cli);
+    return true;
+}
+
+void LogReader::doSocketDelete(SocketClient *cli) {
+    LastLogTimes &times = mLogbuf.mTimes;
+    LogTimeEntry::lock();
+    LastLogTimes::iterator it = times.begin();
+    while(it != times.end()) {
+        LogTimeEntry *entry = (*it);
+        if (entry->mClient == cli) {
+            times.erase(it);
+            entry->release_Locked();
+            break;
+        }
+        it++;
+    }
+    LogTimeEntry::unlock();
+}
diff --git a/logd/LogReader.h b/logd/LogReader.h
new file mode 100644
index 0000000..b267c75
--- /dev/null
+++ b/logd/LogReader.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012-2013 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 _LOGD_LOG_WRITER_H__
+#define _LOGD_LOG_WRITER_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogBuffer.h"
+#include "LogTimes.h"
+
+class LogReader : public SocketListener {
+    LogBuffer &mLogbuf;
+
+public:
+    LogReader(LogBuffer *logbuf);
+    void notifyNewLog();
+
+    LogBuffer &logbuf(void) const { return mLogbuf; }
+
+protected:
+    virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+    void doSocketDelete(SocketClient *cli);
+
+};
+
+#endif
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
new file mode 100644
index 0000000..67cc65e
--- /dev/null
+++ b/logd/LogTimes.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2014 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 "FlushCommand.h"
+#include "LogBuffer.h"
+#include "LogTimes.h"
+#include "LogReader.h"
+
+pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
+
+const struct timespec LogTimeEntry::EPOCH = { 0, 1 };
+
+LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
+                           bool nonBlock, unsigned long tail,
+                           unsigned int logMask, pid_t pid)
+        : mRefCount(1)
+        , mRelease(false)
+        , mError(false)
+        , threadRunning(false)
+        , threadTriggered(true)
+        , mReader(reader)
+        , mLogMask(logMask)
+        , mPid(pid)
+        , skipAhead(0)
+        , mCount(0)
+        , mTail(tail)
+        , mIndex(0)
+        , mClient(client)
+        , mStart(EPOCH)
+        , mNonBlock(nonBlock)
+        , mEnd(CLOCK_MONOTONIC)
+{ }
+
+void LogTimeEntry::startReader_Locked(void) {
+    threadRunning = true;
+    if (pthread_create(&mThread, NULL, LogTimeEntry::threadStart, this)) {
+        threadRunning = false;
+        if (mClient) {
+            mClient->decRef();
+        }
+        decRef_Locked();
+    }
+}
+
+void LogTimeEntry::threadStop(void *obj) {
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    lock();
+
+    me->threadRunning = false;
+    if (me->mNonBlock) {
+        me->error_Locked();
+    }
+
+    SocketClient *client = me->mClient;
+
+    if (me->isError_Locked()) {
+        LogReader &reader = me->mReader;
+        LastLogTimes &times = reader.logbuf().mTimes;
+
+        LastLogTimes::iterator it = times.begin();
+        while(it != times.end()) {
+            if (*it == me) {
+                times.erase(it);
+                me->release_Locked();
+                break;
+            }
+            it++;
+        }
+
+        me->mClient = NULL;
+        reader.release(client);
+    }
+
+    if (client) {
+        client->decRef();
+    }
+
+    me->decRef_Locked();
+
+    unlock();
+}
+
+void *LogTimeEntry::threadStart(void *obj) {
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    pthread_cleanup_push(threadStop, obj);
+
+    SocketClient *client = me->mClient;
+    if (!client) {
+        me->error();
+        pthread_exit(NULL);
+    }
+
+    LogBuffer &logbuf = me->mReader.logbuf();
+
+    bool privileged = FlushCommand::hasReadLogs(client);
+
+    lock();
+
+    me->threadTriggered = true;
+
+    while(me->threadTriggered && !me->isError_Locked()) {
+
+        me->threadTriggered = false;
+
+        log_time start = me->mStart;
+
+        unlock();
+
+        if (me->mTail) {
+            logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
+        }
+        start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
+
+        if (start == LogBufferElement::FLUSH_ERROR) {
+            me->error();
+        }
+
+        if (me->mNonBlock) {
+            lock();
+            break;
+        }
+
+        sched_yield();
+
+        lock();
+    }
+
+    unlock();
+
+    pthread_exit(NULL);
+
+    pthread_cleanup_pop(true);
+
+    return NULL;
+}
+
+// A first pass to count the number of elements
+bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    LogTimeEntry::lock();
+
+    if (me->mCount == 0) {
+        me->mStart = element->getMonotonicTime();
+    }
+
+    if ((!me->mPid || (me->mPid == element->getPid()))
+            && (me->mLogMask & (1 << element->getLogId()))) {
+        ++me->mCount;
+    }
+
+    LogTimeEntry::unlock();
+
+    return false;
+}
+
+// A second pass to send the selected elements
+bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
+    LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+    LogTimeEntry::lock();
+
+    if (me->skipAhead) {
+        me->skipAhead--;
+    }
+
+    me->mStart = element->getMonotonicTime();
+
+    // Truncate to close race between first and second pass
+    if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
+        goto skip;
+    }
+
+    if ((me->mLogMask & (1 << element->getLogId())) == 0) {
+        goto skip;
+    }
+
+    if (me->mPid && (me->mPid != element->getPid())) {
+        goto skip;
+    }
+
+    if (me->isError_Locked()) {
+        goto skip;
+    }
+
+    if (!me->mTail) {
+        goto ok;
+    }
+
+    ++me->mIndex;
+
+    if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) {
+        goto skip;
+    }
+
+    if (!me->mNonBlock) {
+        me->mTail = 0;
+    }
+
+ok:
+    if (!me->skipAhead) {
+        LogTimeEntry::unlock();
+        return true;
+    }
+    // FALLTHRU
+
+skip:
+    LogTimeEntry::unlock();
+    return false;
+}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
new file mode 100644
index 0000000..cb6f566
--- /dev/null
+++ b/logd/LogTimes.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012-2013 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 _LOGD_LOG_TIMES_H__
+#define _LOGD_LOG_TIMES_H__
+
+#include <pthread.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sysutils/SocketClient.h>
+#include <utils/List.h>
+
+class LogReader;
+
+class LogTimeEntry {
+    static pthread_mutex_t timesLock;
+    unsigned int mRefCount;
+    bool mRelease;
+    bool mError;
+    bool threadRunning;
+    bool threadTriggered;
+    pthread_t mThread;
+    LogReader &mReader;
+    static void *threadStart(void *me);
+    static void threadStop(void *me);
+    const unsigned int mLogMask;
+    const pid_t mPid;
+    unsigned int skipAhead;
+    unsigned long mCount;
+    unsigned long mTail;
+    unsigned long mIndex;
+
+public:
+    LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
+                 unsigned long tail, unsigned int logMask, pid_t pid);
+
+    SocketClient *mClient;
+    static const struct timespec EPOCH;
+    log_time mStart;
+    const bool mNonBlock;
+    const log_time mEnd; // only relevant if mNonBlock
+
+    // Protect List manipulations
+    static void lock(void) { pthread_mutex_lock(&timesLock); }
+    static void unlock(void) { pthread_mutex_unlock(&timesLock); }
+
+    void startReader_Locked(void);
+
+    bool runningReader_Locked(void) const {
+        return threadRunning || mRelease || mError || mNonBlock;
+    }
+    void triggerReader_Locked(void) { threadTriggered = true; }
+    void triggerSkip_Locked(unsigned int skip) { skipAhead = skip; }
+
+    // Called after LogTimeEntry removed from list, lock implicitly held
+    void release_Locked(void) {
+        mRelease = true;
+        if (mRefCount || threadRunning) {
+            return;
+        }
+        // No one else is holding a reference to this
+        delete this;
+    }
+
+    // Called to mark socket in jeopardy
+    void error_Locked(void) { mError = true; }
+    void error(void) { lock(); mError = true; unlock(); }
+
+    bool isError_Locked(void) const { return mRelease || mError; }
+
+    // Mark Used
+    //  Locking implied, grabbed when protection around loop iteration
+    void incRef_Locked(void) { ++mRefCount; }
+
+    bool owned_Locked(void) const { return mRefCount != 0; }
+
+    void decRef_Locked(void) {
+        if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
+            return;
+        }
+        // No one else is holding a reference to this
+        delete this;
+    }
+
+    // flushTo filter callbacks
+    static bool FilterFirstPass(const LogBufferElement *element, void *me);
+    static bool FilterSecondPass(const LogBufferElement *element, void *me);
+};
+
+typedef android::List<LogTimeEntry *> LastLogTimes;
+
+#endif
diff --git a/logd/main.cpp b/logd/main.cpp
new file mode 100644
index 0000000..1891206
--- /dev/null
+++ b/logd/main.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2012-2013 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/prctl.h>
+
+#include "private/android_filesystem_config.h"
+#include "CommandListener.h"
+#include "LogBuffer.h"
+#include "LogListener.h"
+
+static int drop_privs() {
+    struct sched_param param;
+    memset(&param, 0, sizeof(param));
+
+    if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
+        return -1;
+    }
+
+    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+        return -1;
+    }
+
+    if (setgid(AID_LOGD) != 0) {
+        return -1;
+    }
+
+    if (setuid(AID_LOGD) != 0) {
+        return -1;
+    }
+
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
+    capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
+    capdata[0].inheritable = 0;
+    capdata[1].inheritable = 0;
+
+    if (capset(&capheader, &capdata[0]) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+// Foreground waits for exit of the three main persistent threads that
+// are started here.  The three threads are created to manage UNIX
+// domain client sockets for writing, reading and controlling the user
+// space logger.  Additional transitory per-client threads are created
+// for each reader once they register.
+int main() {
+    if (drop_privs() != 0) {
+        return -1;
+    }
+
+    // Serves the purpose of managing the last logs times read on a
+    // socket connection, and as a reader lock on a range of log
+    // entries.
+
+    LastLogTimes *times = new LastLogTimes();
+
+    // LogBuffer is the object which is responsible for holding all
+    // log entries.
+
+    LogBuffer *logBuf = new LogBuffer(times);
+
+    // LogReader listens on /dev/socket/logdr. When a client
+    // connects, log entries in the LogBuffer are written to the client.
+
+    LogReader *reader = new LogReader(logBuf);
+    if (reader->startListener()) {
+        exit(1);
+    }
+
+    // LogListener listens on /dev/socket/logdw for client
+    // initiated log messages. New log entries are added to LogBuffer
+    // and LogReader is notified to send updates to connected clients.
+
+    LogListener *swl = new LogListener(logBuf, reader);
+    if (swl->startListener()) {
+        exit(1);
+    }
+
+    // Command listener listens on /dev/socket/logd for incoming logd
+    // administrative commands.
+
+    CommandListener *cl = new CommandListener(logBuf, reader, swl);
+    if (cl->startListener()) {
+        exit(1);
+    }
+
+    pause();
+    exit(0);
+}
+
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 46fb8bd..9975368 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -214,23 +214,16 @@
     mkdir /data/misc/radio 0770 system radio
     mkdir /data/misc/sms 0770 system radio
     mkdir /data/misc/zoneinfo 0775 system system
-    restorecon_recursive /data/misc/zoneinfo
     mkdir /data/misc/vpn 0770 system vpn
     mkdir /data/misc/systemkeys 0700 system system
     mkdir /data/misc/wifi 0770 wifi wifi
     mkdir /data/misc/wifi/sockets 0770 wifi wifi
-    restorecon_recursive /data/misc/wifi/sockets
     mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
     mkdir /data/misc/dhcp 0770 dhcp dhcp
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
     mkdir /data/local 0751 root root
     mkdir /data/misc/media 0700 media media
-    restorecon_recursive /data/misc/media
-
-    # Set security context of any pre-existing /data/misc/adb/adb_keys file.
-    restorecon /data/misc/adb
-    restorecon /data/misc/adb/adb_keys
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
@@ -262,7 +255,6 @@
     # create directory for MediaDrm plug-ins - give drm the read/write access to
     # the following directory.
     mkdir /data/mediadrm 0770 mediadrm mediadrm
-    restorecon_recursive /data/mediadrm
 
     # symlink to bugreport storage location
     symlink /data/data/com.android.shell/files/bugreports /data/bugreports
@@ -273,6 +265,9 @@
     # Reload policy from /data/security if present.
     setprop selinux.reload_policy 1
 
+    # Set SELinux security contexts on upgrade or policy update.
+    restorecon_recursive /data
+
     # If there is no fs-post-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
     # won't work.
@@ -456,6 +451,12 @@
 on property:ro.kernel.qemu=1
     start adbd
 
+service logd /system/bin/logd
+    class main
+    socket logd stream 0666 logd logd
+    socket logdr seqpacket 0666 logd logd
+    socket logdw dgram 0222 logd logd
+
 service servicemanager /system/bin/servicemanager
     class core
     user system
diff --git a/toolbox/mkswap.c b/toolbox/mkswap.c
index 1710ef6..0904152 100644
--- a/toolbox/mkswap.c
+++ b/toolbox/mkswap.c
@@ -1,6 +1,5 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <asm/page.h>
 #include <sys/swap.h>
 #include <sys/types.h>
 #include <sys/stat.h>
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
index 11532da..3568625 100644
--- a/toolbox/restorecon.c
+++ b/toolbox/restorecon.c
@@ -9,7 +9,7 @@
 
 static void usage(void)
 {
-    fprintf(stderr, "usage:  %s [-FnrRv] pathname...\n", progname);
+    fprintf(stderr, "usage:  %s [-DFnrRv] pathname...\n", progname);
     exit(1);
 }
 
@@ -21,10 +21,13 @@
     progname = argv[0];
 
     do {
-        ch = getopt(argc, argv, "FnrRv");
+        ch = getopt(argc, argv, "DFnrRv");
         if (ch == EOF)
             break;
         switch (ch) {
+        case 'D':
+            flags |= SELINUX_ANDROID_RESTORECON_DATADATA;
+            break;
         case 'F':
             flags |= SELINUX_ANDROID_RESTORECON_FORCE;
             break;
diff --git a/toolbox/swapoff.c b/toolbox/swapoff.c
index 8f14158..d8f6a00 100644
--- a/toolbox/swapoff.c
+++ b/toolbox/swapoff.c
@@ -1,6 +1,5 @@
 #include <stdio.h>
 #include <unistd.h>
-#include <asm/page.h>
 #include <sys/swap.h>
 
 int swapoff_main(int argc, char **argv)
diff --git a/toolbox/swapon.c b/toolbox/swapon.c
index a810b3d..21d2287 100644
--- a/toolbox/swapon.c
+++ b/toolbox/swapon.c
@@ -2,7 +2,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <getopt.h>
-#include <asm/page.h>
 #include <sys/swap.h>
 
 void usage(char *name)