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 < ¶ms[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 × = 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 × = 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 × = 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(×Lock); }
+ static void unlock(void) { pthread_mutex_unlock(×Lock); }
+
+ 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(¶m, 0, sizeof(param));
+
+ if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 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)