Merge "adb: win32: fix logging to adb.log"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index fee5361..9af1586 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -115,7 +115,7 @@
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
- adb_close(fd);
+ unix_close(fd);
}
#endif
@@ -190,6 +190,13 @@
}
void adb_trace_init(char** argv) {
+ // Don't open log file if no tracing, since this will block
+ // the crypto unmount of /data
+ const std::string trace_setting = get_trace_setting();
+ if (trace_setting.empty()) {
+ return;
+ }
+
#if !ADB_HOST
if (isatty(STDOUT_FILENO) == 0) {
start_device_log();
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 61a3777..e878f8b 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -420,6 +420,9 @@
strcat(path, ".pub");
// TODO(danalbert): ReadFileToString
+ // Note that on Windows, load_file() does not do CR/LF translation, but
+ // ReadFileToString() uses the C Runtime which uses CR/LF translation by
+ // default (by is overridable with _setmode()).
unsigned size;
char* file_data = reinterpret_cast<char*>(load_file(path, &size));
if (file_data == nullptr) {
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index c0612cd..78ab3f6 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -226,7 +226,7 @@
return;
}
dup2(fd, STDIN_FILENO);
- adb_close(fd);
+ unix_close(fd);
}
int main(int argc, char** argv) {
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 7a3b89a..3a4d2da 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -58,7 +58,7 @@
int OFF = 0;
bool result = (ioctl(fd, BLKROSET, &OFF) != -1);
- adb_close(fd);
+ unix_close(fd);
return result;
}
diff --git a/adb/services.cpp b/adb/services.cpp
index a9edbe5..2fd75ab 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -252,7 +252,7 @@
*pid = forkpty(&ptm, pts_name, nullptr, nullptr);
if (*pid == -1) {
printf("- fork failed: %s -\n", strerror(errno));
- adb_close(ptm);
+ unix_close(ptm);
return -1;
}
@@ -263,7 +263,7 @@
if (pts == -1) {
fprintf(stderr, "child failed to open pseudo-term slave %s: %s\n",
pts_name, strerror(errno));
- adb_close(ptm);
+ unix_close(ptm);
exit(-1);
}
@@ -272,16 +272,16 @@
termios tattr;
if (tcgetattr(pts, &tattr) == -1) {
fprintf(stderr, "tcgetattr failed: %s\n", strerror(errno));
- adb_close(pts);
- adb_close(ptm);
+ unix_close(pts);
+ unix_close(ptm);
exit(-1);
}
cfmakeraw(&tattr);
if (tcsetattr(pts, TCSADRAIN, &tattr) == -1) {
fprintf(stderr, "tcsetattr failed: %s\n", strerror(errno));
- adb_close(pts);
- adb_close(ptm);
+ unix_close(pts);
+ unix_close(ptm);
exit(-1);
}
}
@@ -290,8 +290,8 @@
dup2(pts, STDOUT_FILENO);
dup2(pts, STDERR_FILENO);
- adb_close(pts);
- adb_close(ptm);
+ unix_close(pts);
+ unix_close(ptm);
execl(cmd, cmd, arg0, arg1, nullptr);
fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 0aa1570..b7c16d9 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -125,6 +125,7 @@
#undef mkdir
#define mkdir ___xxx_mkdir
+// See the comments for the !defined(_WIN32) versions of adb_*().
extern int adb_open(const char* path, int options);
extern int adb_creat(const char* path, int mode);
extern int adb_read(int fd, void* buf, int len);
@@ -133,6 +134,7 @@
extern int adb_shutdown(int fd);
extern int adb_close(int fd);
+// See the comments for the !defined(_WIN32) version of unix_close().
static __inline__ int unix_close(int fd)
{
return close(fd);
@@ -140,11 +142,13 @@
#undef close
#define close ____xxx_close
+// See the comments for the !defined(_WIN32) version of unix_read().
extern int unix_read(int fd, void* buf, size_t len);
#undef read
#define read ___xxx_read
+// See the comments for the !defined(_WIN32) version of unix_write().
static __inline__ int unix_write(int fd, const void* buf, size_t len)
{
return write(fd, buf, len);
@@ -152,11 +156,13 @@
#undef write
#define write ___xxx_write
+// See the comments for the !defined(_WIN32) version of adb_open_mode().
static __inline__ int adb_open_mode(const char* path, int options, int mode)
{
return adb_open(path, options);
}
+// See the comments for the !defined(_WIN32) version of unix_open().
static __inline__ int unix_open(const char* path, int options,...)
{
if ((options & O_CREAT) == 0)
@@ -314,6 +320,15 @@
fcntl( fd, F_SETFD, FD_CLOEXEC );
}
+// Open a file and return a file descriptor that may be used with unix_read(),
+// unix_write(), unix_close(), but not adb_read(), adb_write(), adb_close().
+//
+// On Unix, this is based on open(), so the file descriptor is a real OS file
+// descriptor, but the Windows implementation (in sysdeps_win32.cpp) returns a
+// file descriptor that can only be used with C Runtime APIs (which are wrapped
+// by unix_read(), unix_write(), unix_close()). Also, the C Runtime has
+// configurable CR/LF translation which defaults to text mode, but is settable
+// with _setmode().
static __inline__ int unix_open(const char* path, int options,...)
{
if ((options & O_CREAT) == 0)
@@ -331,12 +346,21 @@
}
}
+// Similar to the two-argument adb_open(), but takes a mode parameter for file
+// creation. See adb_open() for more info.
static __inline__ int adb_open_mode( const char* pathname, int options, int mode )
{
return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
}
+// Open a file and return a file descriptor that may be used with adb_read(),
+// adb_write(), adb_close(), but not unix_read(), unix_write(), unix_close().
+//
+// On Unix, this is based on open(), but the Windows implementation (in
+// sysdeps_win32.cpp) uses Windows native file I/O and bypasses the C Runtime
+// and its CR/LF translation. The returned file descriptor should be used with
+// adb_read(), adb_write(), adb_close(), etc.
static __inline__ int adb_open( const char* pathname, int options )
{
int fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
@@ -355,6 +379,9 @@
#undef shutdown
#define shutdown ____xxx_shutdown
+// Closes a file descriptor that came from adb_open() or adb_open_mode(), but
+// not designed to take a file descriptor from unix_open(). See the comments
+// for adb_open() for more info.
static __inline__ int adb_close(int fd)
{
return close(fd);
@@ -419,6 +446,14 @@
#undef accept
#define accept ___xxx_accept
+// Operate on a file descriptor returned from unix_open() or a well-known file
+// descriptor such as STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
+//
+// On Unix, unix_read(), unix_write(), unix_close() map to adb_read(),
+// adb_write(), adb_close() (which all map to Unix system calls), but the
+// Windows implementations (in the ifdef above and in sysdeps_win32.cpp) call
+// into the C Runtime and its configurable CR/LF translation (which is settable
+// via _setmode()).
#define unix_read adb_read
#define unix_write adb_write
#define unix_close adb_close
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a21272f..50c99f1 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -172,14 +172,15 @@
static int _win32_fh_count;
static FH
-_fh_from_int( int fd )
+_fh_from_int( int fd, const char* func )
{
FH f;
fd -= WIN32_FH_BASE;
if (fd < 0 || fd >= _win32_fh_count) {
- D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
+ D( "_fh_from_int: invalid fd %d passed to %s\n", fd + WIN32_FH_BASE,
+ func );
errno = EBADF;
return NULL;
}
@@ -187,7 +188,8 @@
f = &_win32_fhs[fd];
if (f->used == 0) {
- D( "_fh_from_int: invalid fd %d\n", fd + WIN32_FH_BASE );
+ D( "_fh_from_int: invalid fd %d passed to %s\n", fd + WIN32_FH_BASE,
+ func );
errno = EBADF;
return NULL;
}
@@ -427,7 +429,7 @@
int adb_read(int fd, void* buf, int len)
{
- FH f = _fh_from_int(fd);
+ FH f = _fh_from_int(fd, __func__);
if (f == NULL) {
return -1;
@@ -439,7 +441,7 @@
int adb_write(int fd, const void* buf, int len)
{
- FH f = _fh_from_int(fd);
+ FH f = _fh_from_int(fd, __func__);
if (f == NULL) {
return -1;
@@ -451,7 +453,7 @@
int adb_lseek(int fd, int pos, int where)
{
- FH f = _fh_from_int(fd);
+ FH f = _fh_from_int(fd, __func__);
if (!f) {
return -1;
@@ -463,7 +465,7 @@
int adb_shutdown(int fd)
{
- FH f = _fh_from_int(fd);
+ FH f = _fh_from_int(fd, __func__);
if (!f || f->clazz != &_fh_socket_class) {
D("adb_shutdown: invalid fd %d\n", fd);
@@ -478,7 +480,7 @@
int adb_close(int fd)
{
- FH f = _fh_from_int(fd);
+ FH f = _fh_from_int(fd, __func__);
if (!f) {
return -1;
@@ -763,7 +765,7 @@
#undef accept
int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t *addrlen)
{
- FH serverfh = _fh_from_int(serverfd);
+ FH serverfh = _fh_from_int(serverfd, __func__);
FH fh;
if ( !serverfh || serverfh->clazz != &_fh_socket_class ) {
@@ -792,7 +794,7 @@
int adb_setsockopt( int fd, int level, int optname, const void* optval, socklen_t optlen )
{
- FH fh = _fh_from_int(fd);
+ FH fh = _fh_from_int(fd, __func__);
if ( !fh || fh->clazz != &_fh_socket_class ) {
D("adb_setsockopt: invalid fd %d\n", fd);
@@ -1386,7 +1388,7 @@
static void
event_looper_hook( EventLooper looper, int fd, int events )
{
- FH f = _fh_from_int(fd);
+ FH f = _fh_from_int(fd, __func__);
EventHook *pnode;
EventHook node;
@@ -1418,7 +1420,7 @@
static void
event_looper_unhook( EventLooper looper, int fd, int events )
{
- FH fh = _fh_from_int(fd);
+ FH fh = _fh_from_int(fd, __func__);
EventHook *pnode = event_looper_find_p( looper, fh );
EventHook node = *pnode;
@@ -3036,7 +3038,7 @@
}
}
-// Called by 'adb shell' command to read from stdin.
+// Called by 'adb shell' and 'adb exec-in' to read from stdin.
int unix_read(int fd, void* buf, size_t len) {
if ((fd == STDIN_FILENO) && (_console_handle != NULL)) {
// If it is a request to read from stdin, and stdin_raw_init() has been
@@ -3046,8 +3048,12 @@
return _console_read(_console_handle, buf, len);
} else {
// Just call into C Runtime which can read from pipes/files and which
- // can do LF/CR translation.
+ // can do LF/CR translation (which is overridable with _setmode()).
+ // Undefine the macro that is set in sysdeps.h which bans calls to
+ // plain read() in favor of unix_read() or adb_read().
+#pragma push_macro("read")
#undef read
return read(fd, buf, len);
+#pragma pop_macro("read")
}
}
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index 4eccc8c..730f668 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -7,6 +7,7 @@
import hashlib
import os
import pipes
+import posixpath
import random
import re
import shlex
@@ -98,7 +99,7 @@
def __init__(self, md5, full_path):
self.md5 = md5
self.full_path = full_path
- self.base_name = os.path.basename(self.full_path)
+ self.base_name = posixpath.basename(self.full_path)
def make_random_host_files(in_dir, num_files, rand_size=True):
@@ -108,7 +109,7 @@
fixed_size = min_size
for _ in range(num_files):
- file_handle = tempfile.NamedTemporaryFile(dir=in_dir)
+ file_handle = tempfile.NamedTemporaryFile(dir=in_dir, delete=False)
if rand_size:
size = random.randrange(min_size, max_size, 1024)
@@ -117,6 +118,7 @@
rand_str = os.urandom(size)
file_handle.write(rand_str)
file_handle.flush()
+ file_handle.close()
md5 = compute_md5(rand_str)
files[file_handle.name] = HostFile(file_handle, md5)
@@ -153,9 +155,9 @@
self.out_dir = out_dir
self.adb_cmd = "adb "
if self.device:
- self.adb_cmd += "-s {} ".format(device)
+ self.adb_cmd += "-s {} ".format(pipes.quote(device))
if self.out_dir:
- self.adb_cmd += "-p {} ".format(out_dir)
+ self.adb_cmd += "-p {} ".format(pipes.quote(out_dir))
def shell(self, cmd):
return call_checked(self.adb_cmd + "shell " + cmd)
@@ -168,13 +170,16 @@
self.adb_cmd + "install {}".format(pipes.quote(filename)))
def push(self, local, remote):
- return call_checked(self.adb_cmd + "push {} {}".format(local, remote))
+ return call_checked(self.adb_cmd + "push {} {}".format(
+ pipes.quote(local), pipes.quote(remote)))
def pull(self, remote, local):
- return call_checked(self.adb_cmd + "pull {} {}".format(remote, local))
+ return call_checked(self.adb_cmd + "pull {} {}".format(
+ pipes.quote(remote), pipes.quote(local)))
def sync(self, directory=""):
- return call_checked(self.adb_cmd + "sync {}".format(directory))
+ return call_checked(self.adb_cmd + "sync {}".format(
+ pipes.quote(directory) if directory else directory))
def forward(self, local, remote):
return call_checked(self.adb_cmd + "forward {} {}".format(local,
@@ -244,7 +249,8 @@
def _test_root(self):
adb = AdbWrapper()
- adb.root()
+ if "adbd cannot run as root in production builds" in adb.root():
+ return
adb.wait()
self.assertEqual("root", adb.shell("id -un").strip())
@@ -300,11 +306,11 @@
adb = AdbWrapper()
# http://b/20323053
- tf = tempfile.NamedTemporaryFile("w", suffix="-text;ls;1.apk")
+ tf = tempfile.NamedTemporaryFile("wb", suffix="-text;ls;1.apk")
self.assertIn("-text;ls;1.apk", adb.install(tf.name))
# http://b/3090932
- tf = tempfile.NamedTemporaryFile("w", suffix="-Live Hold'em.apk")
+ tf = tempfile.NamedTemporaryFile("wb", suffix="-Live Hold'em.apk")
self.assertIn("-Live Hold'em.apk", adb.install(tf.name))
def test_line_endings(self):
@@ -312,7 +318,13 @@
Bug: http://b/19735063
"""
- self.assertFalse(AdbWrapper().shell("uname").endswith("\r\n"))
+ output = AdbWrapper().shell("uname")
+ if sys.platform == 'win32':
+ # adb.exe running on Windows does translation to the Windows \r\n
+ # convention, so we should expect those chars.
+ self.assertEqual(output, "Linux\r\n")
+ else:
+ self.assertEqual(output, "Linux\n")
class AdbFile(unittest.TestCase):
@@ -324,20 +336,24 @@
"""Push a randomly generated file to specified device."""
kbytes = 512
adb = AdbWrapper()
- with tempfile.NamedTemporaryFile(mode="w") as tmp:
- rand_str = os.urandom(1024 * kbytes)
- tmp.write(rand_str)
- tmp.flush()
-
- host_md5 = compute_md5(rand_str)
- adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE))
+ with tempfile.NamedTemporaryFile(mode="wb", delete=False) as tmp:
try:
- adb.push(local=tmp.name, remote=AdbFile.DEVICE_TEMP_FILE)
- dev_md5, _ = adb.shell(
- "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split()
- self.assertEqual(host_md5, dev_md5)
+ rand_str = os.urandom(1024 * kbytes)
+ tmp.write(rand_str)
+ tmp.flush()
+ tmp.close()
+
+ host_md5 = compute_md5(rand_str)
+ adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_FILE))
+ try:
+ adb.push(local=tmp.name, remote=AdbFile.DEVICE_TEMP_FILE)
+ dev_md5, _ = adb.shell(
+ "md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split()
+ self.assertEqual(host_md5, dev_md5)
+ finally:
+ adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE))
finally:
- adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE))
+ os.remove(tmp.name)
# TODO: write push directory test.
@@ -352,12 +368,18 @@
dev_md5, _ = adb.shell(
"md5sum {}".format(AdbFile.DEVICE_TEMP_FILE)).split()
- with tempfile.NamedTemporaryFile(mode="w") as tmp_write:
- adb.pull(remote=AdbFile.DEVICE_TEMP_FILE, local=tmp_write.name)
- with open(tmp_write.name) as tmp_read:
- host_contents = tmp_read.read()
- host_md5 = compute_md5(host_contents)
- self.assertEqual(dev_md5, host_md5)
+ with tempfile.NamedTemporaryFile(mode="wb", delete=False) \
+ as tmp_write:
+ try:
+ tmp_write.close()
+ adb.pull(remote=AdbFile.DEVICE_TEMP_FILE,
+ local=tmp_write.name)
+ with open(tmp_write.name, "rb") as tmp_read:
+ host_contents = tmp_read.read()
+ host_md5 = compute_md5(host_contents)
+ self.assertEqual(dev_md5, host_md5)
+ finally:
+ os.remove(tmp_write.name)
finally:
adb.shell_nocheck("rm {}".format(AdbFile.DEVICE_TEMP_FILE))
@@ -383,7 +405,7 @@
for device_full_path in temp_files:
host_path = os.path.join(
host_dir, temp_files[device_full_path].base_name)
- with open(host_path) as host_file:
+ with open(host_path, "rb") as host_file:
host_md5 = compute_md5(host_file.read())
self.assertEqual(host_md5,
temp_files[device_full_path].md5)
@@ -421,7 +443,7 @@
# confirm that every file on the device mirrors that on the host
for host_full_path in temp_files.keys():
- device_full_path = os.path.join(
+ device_full_path = posixpath.join(
AdbFile.DEVICE_TEMP_DIR,
temp_files[host_full_path].base_name)
dev_md5, _ = adb.shell(
@@ -432,7 +454,7 @@
adb.shell_nocheck("rm -r {}".format(AdbFile.DEVICE_TEMP_DIR))
if temp_files:
for tf in temp_files.values():
- tf.handle.close()
+ os.remove(tf.full_path)
if base_dir:
os.removedirs(base_dir + AdbFile.DEVICE_TEMP_DIR)
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 1e5d5c8..c6f712b 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -168,13 +168,13 @@
continue;
}
- desclength = adb_read(fd, devdesc, sizeof(devdesc));
+ desclength = unix_read(fd, devdesc, sizeof(devdesc));
bufend = bufptr + desclength;
// should have device and configuration descriptors, and atleast two endpoints
if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
D("desclength %zu is too small\n", desclength);
- adb_close(fd);
+ unix_close(fd);
continue;
}
@@ -182,7 +182,7 @@
bufptr += USB_DT_DEVICE_SIZE;
if((device->bLength != USB_DT_DEVICE_SIZE) || (device->bDescriptorType != USB_DT_DEVICE)) {
- adb_close(fd);
+ unix_close(fd);
continue;
}
@@ -195,7 +195,7 @@
bufptr += USB_DT_CONFIG_SIZE;
if (config->bLength != USB_DT_CONFIG_SIZE || config->bDescriptorType != USB_DT_CONFIG) {
D("usb_config_descriptor not found\n");
- adb_close(fd);
+ unix_close(fd);
continue;
}
@@ -303,7 +303,7 @@
}
} // end of while
- adb_close(fd);
+ unix_close(fd);
} // end of devdir while
closedir(devdir);
} //end of busdir while
@@ -555,7 +555,7 @@
h->prev = 0;
h->next = 0;
- adb_close(h->desc);
+ unix_close(h->desc);
D("-- usb closed %p (fd = %d) --\n", h, h->desc);
adb_mutex_unlock(&usb_lock);
@@ -618,7 +618,7 @@
if (ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface) != 0) {
D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n",
usb->desc, strerror(errno));
- adb_close(usb->desc);
+ unix_close(usb->desc);
free(usb);
return;
}
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 63bb1c7..d34c454 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -201,7 +201,7 @@
int n;
D("about to write (fd=%d, len=%d)\n", h->fd, len);
- n = adb_write(h->fd, data, len);
+ n = unix_write(h->fd, data, len);
if(n != len) {
D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
h->fd, n, errno, strerror(errno));
@@ -216,7 +216,7 @@
int n;
D("about to read (fd=%d, len=%d)\n", h->fd, len);
- n = adb_read(h->fd, data, len);
+ n = unix_read(h->fd, data, len);
if(n != len) {
D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
h->fd, n, errno, strerror(errno));
@@ -230,7 +230,7 @@
{
D("usb_kick\n");
adb_mutex_lock(&h->lock);
- adb_close(h->fd);
+ unix_close(h->fd);
h->fd = -1;
// notify usb_adb_open_thread that we are disconnected
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 1a5f05e..6cfb541 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -75,46 +75,55 @@
include $(BUILD_EXECUTABLE)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
+debuggerd_test_src_files := \
utility.cpp \
+ test/dump_maps_test.cpp \
test/dump_memory_test.cpp \
+ test/elf_fake.cpp \
test/log_fake.cpp \
+ test/property_fake.cpp \
+ test/ptrace_fake.cpp \
+ test/selinux_fake.cpp \
-LOCAL_MODULE := debuggerd_test
-
-LOCAL_SHARED_LIBRARIES := \
+debuggerd_shared_libraries := \
libbacktrace \
libbase \
+ libcutils \
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
-LOCAL_CPPFLAGS := $(common_cppflags)
+debuggerd_c_includes := \
+ $(LOCAL_PATH)/test \
+
+debuggerd_cpp_flags := \
+ $(common_cppflags) \
+ -Wno-missing-field-initializers \
+
+# Only build the host tests on linux.
+ifeq ($(HOST_OS),linux)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := debuggerd_test
+LOCAL_SRC_FILES := $(debuggerd_test_src_files)
+LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries)
+LOCAL_C_INCLUDES := $(debuggerd_c_includes)
+LOCAL_CPPFLAGS := $(debuggerd_cpp_flags)
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_MULTILIB := both
-
include $(BUILD_HOST_NATIVE_TEST)
+endif
+
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- utility.cpp \
- test/dump_memory_test.cpp \
- test/log_fake.cpp \
-
LOCAL_MODULE := debuggerd_test
-
-LOCAL_SHARED_LIBRARIES := \
- libbacktrace \
- libbase \
-
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
-LOCAL_CPPFLAGS := $(common_cppflags)
+LOCAL_SRC_FILES := $(debuggerd_test_src_files)
+LOCAL_SHARED_LIBRARIES := $(debuggerd_shared_libraries)
+LOCAL_C_INCLUDES := $(debuggerd_c_includes)
+LOCAL_CPPFLAGS := $(debuggerd_cpp_flags)
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_MULTILIB := both
-
include $(BUILD_NATIVE_TEST)
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h
index 05ad12b..5c252ab 100644
--- a/debuggerd/test/BacktraceMock.h
+++ b/debuggerd/test/BacktraceMock.h
@@ -32,6 +32,10 @@
public:
BacktraceMapMock() : BacktraceMap(0) {}
virtual ~BacktraceMapMock() {}
+
+ void AddMap(backtrace_map_t& map) {
+ maps_.push_back(map);
+ }
};
diff --git a/debuggerd/test/dump_maps_test.cpp b/debuggerd/test/dump_maps_test.cpp
new file mode 100644
index 0000000..230f4f5
--- /dev/null
+++ b/debuggerd/test/dump_maps_test.cpp
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <base/file.h>
+
+#include "utility.h"
+
+#include "BacktraceMock.h"
+#include "elf_fake.h"
+#include "host_signal_fixup.h"
+#include "log_fake.h"
+#include "ptrace_fake.h"
+
+// In order to test this code, we need to include the tombstone.cpp code.
+// Including it, also allows us to override the ptrace function.
+#define ptrace ptrace_fake
+
+#include "tombstone.cpp"
+
+void dump_registers(log_t*, pid_t) {
+}
+
+void dump_memory_and_code(log_t*, Backtrace*) {
+}
+
+void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
+}
+
+class DumpMapsTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ map_mock_.reset(new BacktraceMapMock());
+ backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
+
+ char tmp_file[256];
+ const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, data_template, sizeof(data_template));
+ int tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, tmp_template, sizeof(tmp_template));
+ tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ abort();
+ }
+ }
+ if (unlink(tmp_file) == -1) {
+ abort();
+ }
+
+ log_.tfd = tombstone_fd;
+ log_.amfd = -1;
+ log_.crashed_tid = 12;
+ log_.current_tid = 12;
+ log_.should_retrieve_logcat = false;
+
+ resetLogs();
+ elf_set_fake_build_id("");
+ siginfo_t si;
+ si.si_signo = SIGPIPE;
+ ptrace_set_fake_getsiginfo(si);
+ }
+
+ virtual void TearDown() {
+ if (log_.tfd >= 0) {
+ close(log_.tfd);
+ }
+ }
+
+ std::unique_ptr<BacktraceMapMock> map_mock_;
+ std::unique_ptr<BacktraceMock> backtrace_mock_;
+
+ log_t log_;
+};
+
+TEST_F(DumpMapsTest, single_map) {
+ backtrace_map_t map;
+#if defined(__LP64__)
+ map.start = 0x123456789abcd000UL;
+ map.end = 0x123456789abdf000UL;
+#else
+ map.start = 0x1234000;
+ map.end = 0x1235000;
+#endif
+ map_mock_->AddMap(map);
+
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+" 12345678'9abcd000-12345678'9abdefff --- 0 12000\n";
+#else
+" 01234000-01234fff --- 0 1000\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, single_map_elf_build_id) {
+ backtrace_map_t map;
+#if defined(__LP64__)
+ map.start = 0x123456789abcd000UL;
+ map.end = 0x123456789abdf000UL;
+#else
+ map.start = 0x1234000;
+ map.end = 0x1235000;
+#endif
+ map.flags = PROT_READ;
+ map.name = "/system/lib/libfake.so";
+ map_mock_->AddMap(map);
+
+ elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+" 12345678'9abcd000-12345678'9abdefff r-- 0 12000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
+#else
+" 01234000-01234fff r-- 0 1000 /system/lib/libfake.so (BuildId: abcdef1234567890abcdef1234567890)\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+// Even though build id is present, it should not be printed in either of
+// these cases.
+TEST_F(DumpMapsTest, single_map_no_build_id) {
+ backtrace_map_t map;
+#if defined(__LP64__)
+ map.start = 0x123456789abcd000UL;
+ map.end = 0x123456789abdf000UL;
+#else
+ map.start = 0x1234000;
+ map.end = 0x1235000;
+#endif
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ map.name = "/system/lib/libfake.so";
+ map_mock_->AddMap(map);
+
+ elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+" 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n"
+" 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n";
+#else
+" 01234000-01234fff -w- 0 1000\n"
+" 01234000-01234fff -w- 0 1000 /system/lib/libfake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps) {
+ backtrace_map_t map;
+
+ map.start = 0xa234000;
+ map.end = 0xa235000;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa334000;
+ map.end = 0xa335000;
+ map.offset = 0xf000;
+ map.flags = PROT_READ;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa434000;
+ map.end = 0xa435000;
+ map.offset = 0x1000;
+ map.load_base = 0xd000;
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa534000;
+ map.end = 0xa535000;
+ map.offset = 0x3000;
+ map.load_base = 0x2000;
+ map.flags = PROT_EXEC;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa634000;
+ map.end = 0xa635000;
+ map.offset = 0;
+ map.load_base = 0;
+ map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+ map.name = "/system/lib/fake.so";
+ map_mock_->AddMap(map);
+
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+" 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
+" 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
+" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
+" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+" 0a234000-0a234fff --- 0 1000\n"
+" 0a334000-0a334fff r-- f000 1000\n"
+" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
+" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_before) {
+ backtrace_map_t map;
+
+ map.start = 0xa434000;
+ map.end = 0xa435000;
+ map.offset = 0x1000;
+ map.load_base = 0xd000;
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa534000;
+ map.end = 0xa535000;
+ map.offset = 0x3000;
+ map.load_base = 0x2000;
+ map.flags = PROT_EXEC;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa634000;
+ map.end = 0xa635000;
+ map.offset = 0;
+ map.load_base = 0;
+ map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+ map.name = "/system/lib/fake.so";
+ map_mock_->AddMap(map);
+
+ siginfo_t si;
+ si.si_signo = SIGBUS;
+ si.si_addr = reinterpret_cast<void*>(0x1000);
+ ptrace_set_fake_getsiginfo(si);
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
+" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
+" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+"--->Fault address falls at 00001000 before any mapped regions\n"
+" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
+" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_between) {
+ backtrace_map_t map;
+
+ map.start = 0xa434000;
+ map.end = 0xa435000;
+ map.offset = 0x1000;
+ map.load_base = 0xd000;
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa534000;
+ map.end = 0xa535000;
+ map.offset = 0x3000;
+ map.load_base = 0x2000;
+ map.flags = PROT_EXEC;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa634000;
+ map.end = 0xa635000;
+ map.offset = 0;
+ map.load_base = 0;
+ map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+ map.name = "/system/lib/fake.so";
+ map_mock_->AddMap(map);
+
+ siginfo_t si;
+ si.si_signo = SIGBUS;
+ si.si_addr = reinterpret_cast<void*>(0xa533000);
+ ptrace_set_fake_getsiginfo(si);
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
+"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
+" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
+"--->Fault address falls at 0a533000 between mapped regions\n"
+" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_in_map) {
+ backtrace_map_t map;
+
+ map.start = 0xa434000;
+ map.end = 0xa435000;
+ map.offset = 0x1000;
+ map.load_base = 0xd000;
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa534000;
+ map.end = 0xa535000;
+ map.offset = 0x3000;
+ map.load_base = 0x2000;
+ map.flags = PROT_EXEC;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa634000;
+ map.end = 0xa635000;
+ map.offset = 0;
+ map.load_base = 0;
+ map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+ map.name = "/system/lib/fake.so";
+ map_mock_->AddMap(map);
+
+ siginfo_t si;
+ si.si_signo = SIGBUS;
+ si.si_addr = reinterpret_cast<void*>(0xa534040);
+ ptrace_set_fake_getsiginfo(si);
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
+"--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#else
+" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
+"--->0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_fault_address_after) {
+ backtrace_map_t map;
+
+ map.start = 0xa434000;
+ map.end = 0xa435000;
+ map.offset = 0x1000;
+ map.load_base = 0xd000;
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa534000;
+ map.end = 0xa535000;
+ map.offset = 0x3000;
+ map.load_base = 0x2000;
+ map.flags = PROT_EXEC;
+ map_mock_->AddMap(map);
+
+ map.start = 0xa634000;
+ map.end = 0xa635000;
+ map.offset = 0;
+ map.load_base = 0;
+ map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
+ map.name = "/system/lib/fake.so";
+ map_mock_->AddMap(map);
+
+ siginfo_t si;
+ si.si_signo = SIGBUS;
+#if defined(__LP64__)
+ si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
+#else
+ si.si_addr = reinterpret_cast<void*>(0xf534040UL);
+#endif
+ ptrace_set_fake_getsiginfo(si);
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
+" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n"
+"--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
+#else
+" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
+" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
+" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n"
+"--->Fault address falls at 0f534040 after any mapped regions\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_getsiginfo_fail) {
+ backtrace_map_t map;
+
+ map.start = 0xa434000;
+ map.end = 0xa435000;
+ map.offset = 0x1000;
+ map.load_base = 0xd000;
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ siginfo_t si;
+ si.si_signo = 0;
+ ptrace_set_fake_getsiginfo(si);
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"Cannot get siginfo for 100: Bad address\n"
+"\nmemory map:\n"
+#if defined(__LP64__)
+" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n";
+#else
+" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("DEBUG Cannot get siginfo for 100: Bad address\n",
+ getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMapsTest, multiple_maps_check_signal_has_si_addr) {
+ backtrace_map_t map;
+
+ map.start = 0xa434000;
+ map.end = 0xa435000;
+ map.flags = PROT_WRITE;
+ map_mock_->AddMap(map);
+
+ for (int i = 1; i < 255; i++) {
+ ASSERT_TRUE(ftruncate(log_.tfd, 0) == 0);
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+
+ siginfo_t si;
+ si.si_signo = i;
+ si.si_addr = reinterpret_cast<void*>(0x1000);
+ ptrace_set_fake_getsiginfo(si);
+ dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ bool has_addr = false;
+ switch (si.si_signo) {
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ case SIGSEGV:
+ case SIGTRAP:
+ has_addr = true;
+ break;
+ }
+
+ const char* expected_addr_dump = \
+"\nmemory map: (fault address prefixed with --->)\n"
+#if defined(__LP64__)
+"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
+" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
+#else
+"--->Fault address falls at 00001000 before any mapped regions\n"
+" 0a434000-0a434fff -w- 0 1000\n";
+#endif
+ const char* expected_dump = \
+"\nmemory map:\n"
+#if defined(__LP64__)
+" 00000000'0a434000-00000000'0a434fff -w- 0 1000\n";
+#else
+" 0a434000-0a434fff -w- 0 1000\n";
+#endif
+ if (has_addr) {
+ ASSERT_STREQ(expected_addr_dump, tombstone_contents.c_str())
+ << "Signal " << si.si_signo << " expected to include an address.";
+ } else {
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str())
+ << "Signal " << si.si_signo << " is not expected to include an address.";
+ }
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+ }
+}
diff --git a/debuggerd/test/elf_fake.cpp b/debuggerd/test/elf_fake.cpp
new file mode 100644
index 0000000..bb52b59
--- /dev/null
+++ b/debuggerd/test/elf_fake.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <string>
+
+class Backtrace;
+
+std::string g_build_id;
+
+void elf_set_fake_build_id(const std::string& build_id) {
+ g_build_id = build_id;
+}
+
+bool elf_get_build_id(Backtrace*, uintptr_t, std::string* build_id) {
+ if (g_build_id != "") {
+ *build_id = g_build_id;
+ return true;
+ }
+ return false;
+}
diff --git a/debuggerd/test/elf_fake.h b/debuggerd/test/elf_fake.h
new file mode 100644
index 0000000..08a8454
--- /dev/null
+++ b/debuggerd/test/elf_fake.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DEBUGGERD_TEST_ELF_FAKE_H
+#define _DEBUGGERD_TEST_ELF_FAKE_H
+
+#include <string>
+
+void elf_set_fake_build_id(const std::string&);
+
+#endif // _DEBUGGERD_TEST_ELF_FAKE_H
diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/test/host_signal_fixup.h
new file mode 100644
index 0000000..c7796ef
--- /dev/null
+++ b/debuggerd/test/host_signal_fixup.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
+#define _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
+
+#include <signal.h>
+
+#if !defined(__BIONIC__)
+
+// In order to compile parts of debuggerd for the host, we need to
+// define these values.
+
+#if !defined(NSIGILL)
+#define NSIGILL ILL_BADSTK
+#endif
+
+#if !defined(BUS_MCEERR_AR)
+#define BUS_MCEERR_AR 4
+#endif
+#if !defined(BUS_MCEERR_AO)
+#define BUS_MCEERR_AO 5
+#endif
+#if !defined(NSIGBUS)
+#define NSIGBUS BUS_MCEERR_AO
+#endif
+
+#if !defined(NSIGFPE)
+#define NSIGFPE FPE_FLTSUB
+#endif
+
+#if !defined(NSIGSEGV)
+#define NSIGSEGV SEGV_ACCERR
+#endif
+
+#if !defined(TRAP_BRANCH)
+#define TRAP_BRANCH 3
+#endif
+#if !defined(TRAP_HWBKPT)
+#define TRAP_HWBKPT 4
+#endif
+#if !defined(NSIGTRAP)
+#define NSIGTRAP TRAP_HWBKPT
+#endif
+
+#if !defined(SI_DETHREAD)
+#define SI_DETHREAD -7
+#endif
+
+#endif
+
+#endif // _DEBUGGERD_TEST_HOST_SIGNAL_FIXUP_H
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
index 1161afe..26523ad 100644
--- a/debuggerd/test/log_fake.cpp
+++ b/debuggerd/test/log_fake.cpp
@@ -19,6 +19,13 @@
#include <string>
#include <base/stringprintf.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+// Forward declarations.
+class Backtrace;
+struct EventTagMap;
+struct AndroidLogEntry;
std::string g_fake_log_buf;
@@ -29,6 +36,14 @@
g_fake_log_print = "";
}
+std::string getFakeLogBuf() {
+ return g_fake_log_buf;
+}
+
+std::string getFakeLogPrint() {
+ return g_fake_log_print;
+}
+
extern "C" int __android_log_buf_write(int, int, const char* tag, const char* msg) {
g_fake_log_buf += tag;
g_fake_log_buf += ' ';
@@ -36,10 +51,6 @@
return 1;
}
-std::string getFakeLogBuf() {
- return g_fake_log_buf;
-}
-
extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) {
g_fake_log_print += tag;
g_fake_log_print += ' ';
@@ -54,6 +65,27 @@
return 1;
}
-std::string getFakeLogPrint() {
- return g_fake_log_print;
+extern "C" log_id_t android_name_to_log_id(const char*) {
+ return LOG_ID_SYSTEM;
+}
+
+extern "C" struct logger_list* android_logger_list_open(log_id_t, int, unsigned int, pid_t) {
+ return nullptr;
+}
+
+extern "C" int android_logger_list_read(struct logger_list*, struct log_msg*) {
+ return 0;
+}
+
+extern "C" EventTagMap* android_openEventTagMap(const char*) {
+ return nullptr;
+}
+
+extern "C" int android_log_processBinaryLogBuffer(
+ struct logger_entry*,
+ AndroidLogEntry*, const EventTagMap*, char*, int) {
+ return 0;
+}
+
+extern "C" void android_logger_list_free(struct logger_list*) {
}
diff --git a/debuggerd/test/property_fake.cpp b/debuggerd/test/property_fake.cpp
new file mode 100644
index 0000000..02069f1
--- /dev/null
+++ b/debuggerd/test/property_fake.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include <string>
+#include <unordered_map>
+
+#include <sys/system_properties.h>
+
+std::unordered_map<std::string, std::string> g_properties;
+
+extern "C" int property_set(const char* name, const char* value) {
+ if (g_properties.count(name) != 0) {
+ g_properties.erase(name);
+ }
+ g_properties[name] = value;
+ return 0;
+}
+
+extern "C" int property_get(const char* key, char* value, const char* default_value) {
+ if (g_properties.count(key) == 0) {
+ if (default_value == nullptr) {
+ return 0;
+ }
+ strncpy(value, default_value, PROP_VALUE_MAX-1);
+ } else {
+ strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
+ }
+ value[PROP_VALUE_MAX-1] = '\0';
+ return strlen(value);
+}
diff --git a/debuggerd/test/ptrace_fake.cpp b/debuggerd/test/ptrace_fake.cpp
new file mode 100644
index 0000000..f40cbd4
--- /dev/null
+++ b/debuggerd/test/ptrace_fake.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <sys/ptrace.h>
+
+#include <string>
+
+#include "ptrace_fake.h"
+
+siginfo_t g_fake_si = {.si_signo = 0};
+
+void ptrace_set_fake_getsiginfo(const siginfo_t& si) {
+ g_fake_si = si;
+}
+
+#if !defined(__BIONIC__)
+extern "C" long ptrace_fake(enum __ptrace_request request, ...) {
+#else
+extern "C" long ptrace_fake(int request, ...) {
+#endif
+ if (request == PTRACE_GETSIGINFO) {
+ if (g_fake_si.si_signo == 0) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ va_list ap;
+ va_start(ap, request);
+ va_arg(ap, int);
+ va_arg(ap, int);
+ siginfo_t* si = va_arg(ap, siginfo*);
+ va_end(ap);
+ *si = g_fake_si;
+ return 0;
+ }
+ return -1;
+}
diff --git a/debuggerd/test/ptrace_fake.h b/debuggerd/test/ptrace_fake.h
new file mode 100644
index 0000000..fdbb663
--- /dev/null
+++ b/debuggerd/test/ptrace_fake.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DEBUGGERD_TEST_PTRACE_FAKE_H
+#define _DEBUGGERD_TEST_PTRACE_FAKE_H
+
+#include <signal.h>
+
+void ptrace_set_fake_getsiginfo(const siginfo_t&);
+
+#endif // _DEBUGGERD_TEST_PTRACE_FAKE_H
diff --git a/debuggerd/test/selinux_fake.cpp b/debuggerd/test/selinux_fake.cpp
new file mode 100644
index 0000000..acdd0a9
--- /dev/null
+++ b/debuggerd/test/selinux_fake.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" int selinux_android_restorecon(const char*, unsigned int) {
+ return 0;
+}
diff --git a/debuggerd/test/sys/system_properties.h b/debuggerd/test/sys/system_properties.h
new file mode 100644
index 0000000..9d44345
--- /dev/null
+++ b/debuggerd/test/sys/system_properties.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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
+ * COPYRIGHT OWNER OR CONTRIBUTORS 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.
+ */
+
+#ifndef _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
+#define _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
+
+// This is just enough to get the property code to compile on
+// the host.
+
+#define PROP_NAME_MAX 32
+#define PROP_VALUE_MAX 92
+
+#endif // _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 614edb6..b0ad274 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -317,16 +317,28 @@
}
}
+static std::string get_addr_string(uintptr_t addr) {
+ std::string addr_str;
+#if defined(__LP64__)
+ addr_str = android::base::StringPrintf("%08x'%08x",
+ static_cast<uint32_t>(addr >> 32),
+ static_cast<uint32_t>(addr & 0xffffffff));
+#else
+ addr_str = android::base::StringPrintf("%08x", addr);
+#endif
+ return addr_str;
+}
+
static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) {
bool print_fault_address_marker = false;
uintptr_t addr = 0;
siginfo_t si;
memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
- _LOG(log, logtype::ERROR, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
- } else {
+ if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) != -1) {
print_fault_address_marker = signal_has_si_addr(si.si_signo);
addr = reinterpret_cast<uintptr_t>(si.si_addr);
+ } else {
+ _LOG(log, logtype::ERROR, "Cannot get siginfo for %d: %s\n", tid, strerror(errno));
}
_LOG(log, logtype::MAPS, "\n");
@@ -335,8 +347,8 @@
} else {
_LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n");
if (map->begin() != map->end() && addr < map->begin()->start) {
- _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n",
- addr);
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %s before any mapped regions\n",
+ get_addr_string(addr).c_str());
print_fault_address_marker = false;
}
}
@@ -346,15 +358,15 @@
line = " ";
if (print_fault_address_marker) {
if (addr < it->start) {
- _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n",
- addr);
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
+ get_addr_string(addr).c_str());
print_fault_address_marker = false;
} else if (addr >= it->start && addr < it->end) {
line = "--->";
print_fault_address_marker = false;
}
}
- line += android::base::StringPrintf("%" PRIPTR "-%" PRIPTR " ", it->start, it->end - 1);
+ line += get_addr_string(it->start) + '-' + get_addr_string(it->end - 1) + ' ';
if (it->flags & PROT_READ) {
line += 'r';
} else {
@@ -372,7 +384,9 @@
}
line += android::base::StringPrintf(" %8" PRIxPTR " %8" PRIxPTR,
it->offset, it->end - it->start);
+ bool space_needed = true;
if (it->name.length() > 0) {
+ space_needed = false;
line += " " + it->name;
std::string build_id;
if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) {
@@ -380,13 +394,16 @@
}
}
if (it->load_base != 0) {
+ if (space_needed) {
+ line += ' ';
+ }
line += android::base::StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base);
}
_LOG(log, logtype::MAPS, "%s\n", line.c_str());
}
if (print_fault_address_marker) {
- _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n",
- addr);
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %s after any mapped regions\n",
+ get_addr_string(addr).c_str());
}
}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index dee471a..66a470a 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -14,6 +14,8 @@
LOCAL_PATH:= $(call my-dir)
+fastboot_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
@@ -23,7 +25,9 @@
LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
LOCAL_CONLYFLAGS += -std=gnu99
-LOCAL_CFLAGS += -Wall -Wextra -Werror
+LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
+
+LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
ifeq ($(HOST_OS),linux)
LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -31,8 +35,7 @@
ifeq ($(HOST_OS),darwin)
LOCAL_SRC_FILES += usb_osx.c util_osx.c
- LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit \
- -framework Carbon
+ LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS += -Wno-unused-parameter
endif
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 7acfd6e..0de1def 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -59,7 +59,6 @@
char cur_product[FB_RESPONSE_SZ + 1];
-static usb_handle *usb = 0;
static const char *serial = 0;
static const char *product = 0;
static const char *cmdline = 0;
@@ -417,6 +416,35 @@
return data;
}
+#if defined(_WIN32)
+
+// TODO: move this to somewhere it can be shared.
+
+#include <windows.h>
+
+// Windows' tmpfile(3) requires administrator rights because
+// it creates temporary files in the root directory.
+static FILE* win32_tmpfile() {
+ char temp_path[PATH_MAX];
+ DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
+ if (nchars == 0 || nchars >= sizeof(temp_path)) {
+ fprintf(stderr, "GetTempPath failed, error %ld\n", GetLastError());
+ return nullptr;
+ }
+
+ char filename[PATH_MAX];
+ if (GetTempFileName(temp_path, "fastboot", 0, filename) == 0) {
+ fprintf(stderr, "GetTempFileName failed, error %ld\n", GetLastError());
+ return nullptr;
+ }
+
+ return fopen(filename, "w+bTD");
+}
+
+#define tmpfile win32_tmpfile
+
+#endif
+
static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
FILE* fp = tmpfile();
if (fp == NULL) {
@@ -619,7 +647,7 @@
* erase partitions of type ext4 before flashing a filesystem so no stale
* inodes are left lying around. Otherwise, e2fsck gets very upset.
*/
-static int needs_erase(const char *part)
+static int needs_erase(usb_handle* usb, const char *part)
{
/* The function fb_format_supported() currently returns the value
* we want, so just call it.
@@ -722,29 +750,33 @@
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
+ CloseArchive(zip);
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
unsigned sz;
void* data = unzip_file(zip, "android-info.txt", &sz);
if (data == 0) {
+ CloseArchive(zip);
die("update package '%s' has no android-info.txt", filename);
}
setup_requirements(reinterpret_cast<char*>(data), sz);
- for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
+ for (size_t i = 0; i < ARRAY_SIZE(images); ++i) {
int fd = unzip_to_file(zip, images[i].img_name);
- if (fd < 0) {
- if (images[i].is_optional)
+ if (fd == -1) {
+ if (images[i].is_optional) {
continue;
- die("update package missing %s", images[i].img_name);
+ }
+ CloseArchive(zip);
+ exit(1); // unzip_to_file already explained why.
}
fastboot_buffer buf;
int rc = load_buf_fd(usb, fd, &buf);
if (rc) die("cannot load %s from flash", images[i].img_name);
do_update_signature(zip, images[i].sig_name);
- if (erase_first && needs_erase(images[i].part_name)) {
+ if (erase_first && needs_erase(usb, images[i].part_name)) {
fb_queue_erase(images[i].part_name);
}
flash_buf(images[i].part_name, &buf);
@@ -799,7 +831,7 @@
die("could not load %s\n", images[i].img_name);
}
do_send_signature(fname);
- if (erase_first && needs_erase(images[i].part_name)) {
+ if (erase_first && needs_erase(usb, images[i].part_name)) {
fb_queue_erase(images[i].part_name);
}
flash_buf(images[i].part_name, &buf);
@@ -867,7 +899,8 @@
return num;
}
-void fb_perform_format(const char *partition, int skip_if_not_supported,
+void fb_perform_format(usb_handle* usb,
+ const char *partition, int skip_if_not_supported,
const char *type_override, const char *size_override)
{
char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
@@ -971,8 +1004,9 @@
{"page_size", required_argument, 0, 'n'},
{"ramdisk_offset", required_argument, 0, 'r'},
{"tags_offset", required_argument, 0, 't'},
- {"help", 0, 0, 'h'},
- {"unbuffered", 0, 0, 0},
+ {"help", no_argument, 0, 'h'},
+ {"unbuffered", no_argument, 0, 0},
+ {"version", no_argument, 0, 0},
{0, 0, 0, 0}
};
@@ -1044,6 +1078,9 @@
if (strcmp("unbuffered", longopts[longindex].name) == 0) {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
+ } else if (strcmp("version", longopts[longindex].name) == 0) {
+ fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
+ return 0;
}
break;
default:
@@ -1070,7 +1107,7 @@
return 0;
}
- usb = open_device();
+ usb_handle* usb = open_device();
while (argc > 0) {
if(!strcmp(*argv, "getvar")) {
@@ -1112,10 +1149,10 @@
}
if (type_override && !type_override[0]) type_override = NULL;
if (size_override && !size_override[0]) size_override = NULL;
- if (erase_first && needs_erase(argv[1])) {
+ if (erase_first && needs_erase(usb, argv[1])) {
fb_queue_erase(argv[1]);
}
- fb_perform_format(argv[1], 0, type_override, size_override);
+ fb_perform_format(usb, argv[1], 0, type_override, size_override);
skip(2);
} else if(!strcmp(*argv, "signature")) {
require(2);
@@ -1175,7 +1212,7 @@
skip(2);
}
if (fname == 0) die("cannot determine image filename for '%s'", pname);
- if (erase_first && needs_erase(pname)) {
+ if (erase_first && needs_erase(usb, pname)) {
fb_queue_erase(pname);
}
do_flash(usb, pname, fname);
@@ -1230,9 +1267,9 @@
if (wants_wipe) {
fb_queue_erase("userdata");
- fb_perform_format("userdata", 1, NULL, NULL);
+ fb_perform_format(usb, "userdata", 1, NULL, NULL);
fb_queue_erase("cache");
- fb_perform_format("cache", 1, NULL, NULL);
+ fb_perform_format(usb, "cache", 1, NULL, NULL);
}
if (wants_reboot) {
fb_queue_reboot();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 1786e49..481c501 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -69,7 +69,7 @@
/* util stuff */
double now();
char *mkmsg(const char *fmt, ...);
-void die(const char *fmt, ...);
+__attribute__((__noreturn__)) void die(const char *fmt, ...);
void get_my_path(char *path);
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index 784bc03..bb18aa2 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -33,13 +33,11 @@
#include <string>
struct backtrace_map_t {
- backtrace_map_t(): start(0), end(0), flags(0) {}
-
- uintptr_t start;
- uintptr_t end;
- uintptr_t offset;
- uintptr_t load_base;
- int flags;
+ uintptr_t start = 0;
+ uintptr_t end = 0;
+ uintptr_t offset = 0;
+ uintptr_t load_base = 0;
+ int flags = 0;
std::string name;
};
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 96249e9..4b812cc 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -36,9 +36,10 @@
FORMAT_TIME,
FORMAT_THREADTIME,
FORMAT_LONG,
- /* The following two are modifiers to above formats */
+ /* The following three are modifiers to above formats */
FORMAT_MODIFIER_COLOR, /* converts priority to color */
FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
+ FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
diff --git a/init/init.cpp b/init/init.cpp
index 60fcf64..2500985 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -380,7 +380,8 @@
if ((svc->flags & SVC_EXEC) != 0) {
INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
- svc->pid, svc->uid, svc->gid, svc->nr_supp_gids, svc->seclabel);
+ svc->pid, svc->uid, svc->gid, svc->nr_supp_gids,
+ svc->seclabel ? : "default");
waiting_for_exec = true;
}
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index df049ed..f975b6c 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -664,6 +664,7 @@
service* make_exec_oneshot_service(int nargs, char** args) {
// Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
+ // SECLABEL can be a - to denote default
int command_arg = 1;
for (int i = 1; i < nargs; ++i) {
if (strcmp(args[i], "--") == 0) {
@@ -689,7 +690,7 @@
return NULL;
}
- if (command_arg > 2) {
+ if ((command_arg > 2) && strcmp(args[1], "-")) {
svc->seclabel = args[1];
}
if (command_arg > 3) {
diff --git a/init/readme.txt b/init/readme.txt
index 6b9c42d..c213041 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -180,7 +180,7 @@
Fork and execute command with the given arguments. The command starts
after "--" so that an optional security context, user, and supplementary
groups can be provided. No other commands will be run until this one
- finishes.
+ finishes. <seclabel> can be a - to denote default.
export <name> <value>
Set the environment variable <name> equal to <value> in the
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 50742df..9d5ea0e 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -22,7 +22,7 @@
#include <log/log_read.h>
-const char log_time::default_format[] = "%m-%d %H:%M:%S.%3q";
+const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
const timespec log_time::EPOCH = { 0, 0 };
// Add %#q for fractional seconds to standard strptime function
diff --git a/liblog/logprint.c b/liblog/logprint.c
index a3f1d7e..c2f1545 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -32,6 +32,9 @@
#include <log/logd.h>
#include <log/logprint.h>
+/* open coded fragment, prevent circular dependencies */
+#define WEAK static
+
typedef struct FilterInfo_t {
char *mTag;
android_LogPriority mPri;
@@ -44,6 +47,7 @@
AndroidLogPrintFormat format;
bool colored_output;
bool usec_time_output;
+ bool printable_output;
};
/*
@@ -187,6 +191,7 @@
p_ret->format = FORMAT_BRIEF;
p_ret->colored_output = false;
p_ret->usec_time_output = false;
+ p_ret->printable_output = false;
return p_ret;
}
@@ -212,13 +217,18 @@
int android_log_setPrintFormat(AndroidLogFormat *p_format,
AndroidLogPrintFormat format)
{
- if (format == FORMAT_MODIFIER_COLOR) {
+ switch (format) {
+ case FORMAT_MODIFIER_COLOR:
p_format->colored_output = true;
return 0;
- }
- if (format == FORMAT_MODIFIER_TIME_USEC) {
+ case FORMAT_MODIFIER_TIME_USEC:
p_format->usec_time_output = true;
return 0;
+ case FORMAT_MODIFIER_PRINTABLE:
+ p_format->printable_output = true;
+ return 0;
+ default:
+ break;
}
p_format->format = format;
return 1;
@@ -241,6 +251,7 @@
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
+ else if (strcmp(formatString, "printable") == 0) format = FORMAT_MODIFIER_PRINTABLE;
else format = FORMAT_OFF;
return format;
@@ -276,29 +287,35 @@
}
if(0 == strncmp("*", filterExpression, tagNameLength)) {
- // This filter expression refers to the global filter
- // The default level for this is DEBUG if the priority
- // is unspecified
+ /*
+ * This filter expression refers to the global filter
+ * The default level for this is DEBUG if the priority
+ * is unspecified
+ */
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_DEBUG;
}
p_format->global_pri = pri;
} else {
- // for filter expressions that don't refer to the global
- // filter, the default is verbose if the priority is unspecified
+ /*
+ * for filter expressions that don't refer to the global
+ * filter, the default is verbose if the priority is unspecified
+ */
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_VERBOSE;
}
char *tagName;
-// Presently HAVE_STRNDUP is never defined, so the second case is always taken
-// Darwin doesn't have strnup, everything else does
+/*
+ * Presently HAVE_STRNDUP is never defined, so the second case is always taken
+ * Darwin doesn't have strnup, everything else does
+ */
#ifdef HAVE_STRNDUP
tagName = strndup(filterExpression, tagNameLength);
#else
- //a few extra bytes copied...
+ /* a few extra bytes copied... */
tagName = strdup(filterExpression);
tagName[tagNameLength] = '\0';
#endif /*HAVE_STRNDUP*/
@@ -335,9 +352,9 @@
char *p_ret;
int err;
- // Yes, I'm using strsep
+ /* Yes, I'm using strsep */
while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
- // ignore whitespace-only entries
+ /* ignore whitespace-only entries */
if(p_ret[0] != '\0') {
err = android_log_addFilterRule(p_format, p_ret);
@@ -381,8 +398,10 @@
* When that happens, we must null-terminate the message ourselves.
*/
if (buf->len < 3) {
- // An well-formed entry must consist of at least a priority
- // and two null characters
+ /*
+ * An well-formed entry must consist of at least a priority
+ * and two null characters
+ */
fprintf(stderr, "+++ LOG: entry too small\n");
return -1;
}
@@ -412,7 +431,7 @@
return -1;
}
if (msgEnd == -1) {
- // incoming message not null-terminated; force it
+ /* incoming message not null-terminated; force it */
msgEnd = buf->len - 1;
msg[msgEnd] = '\0';
}
@@ -473,8 +492,6 @@
type = *eventData++;
eventDataLen--;
- //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen);
-
switch (type) {
case EVENT_TYPE_INT:
/* 32-bit signed int */
@@ -735,6 +752,122 @@
return 0;
}
+/*
+ * One utf8 character at a time
+ *
+ * Returns the length of the utf8 character in the buffer,
+ * or -1 if illegal or truncated
+ *
+ * Open coded from libutils/Unicode.cpp, borrowed from utf8_length(),
+ * can not remove from here because of library circular dependencies.
+ * Expect one-day utf8_character_length with the same signature could
+ * _also_ be part of libutils/Unicode.cpp if its usefullness needs to
+ * propagate globally.
+ */
+WEAK ssize_t utf8_character_length(const char *src, size_t len)
+{
+ const char *cur = src;
+ const char first_char = *cur++;
+ static const uint32_t kUnicodeMaxCodepoint = 0x0010FFFF;
+ int32_t mask, to_ignore_mask;
+ size_t num_to_read;
+ uint32_t utf32;
+
+ if ((first_char & 0x80) == 0) { /* ASCII */
+ return 1;
+ }
+
+ /*
+ * (UTF-8's character must not be like 10xxxxxx,
+ * but 110xxxxx, 1110xxxx, ... or 1111110x)
+ */
+ if ((first_char & 0x40) == 0) {
+ return -1;
+ }
+
+ for (utf32 = 1, num_to_read = 1, mask = 0x40, to_ignore_mask = 0x80;
+ num_to_read < 5 && (first_char & mask);
+ num_to_read++, to_ignore_mask |= mask, mask >>= 1) {
+ if (num_to_read > len) {
+ return -1;
+ }
+ if ((*cur & 0xC0) != 0x80) { /* can not be 10xxxxxx? */
+ return -1;
+ }
+ utf32 = (utf32 << 6) + (*cur++ & 0b00111111);
+ }
+ /* "first_char" must be (110xxxxx - 11110xxx) */
+ if (num_to_read >= 5) {
+ return -1;
+ }
+ to_ignore_mask |= mask;
+ utf32 |= ((~to_ignore_mask) & first_char) << (6 * (num_to_read - 1));
+ if (utf32 > kUnicodeMaxCodepoint) {
+ return -1;
+ }
+ return num_to_read;
+}
+
+/*
+ * Convert to printable from message to p buffer, return string length. If p is
+ * NULL, do not copy, but still return the expected string length.
+ */
+static size_t convertPrintable(char *p, const char *message, size_t messageLen)
+{
+ char *begin = p;
+ bool print = p != NULL;
+
+ while (messageLen) {
+ char buf[6];
+ ssize_t len = sizeof(buf) - 1;
+ if ((size_t)len > messageLen) {
+ len = messageLen;
+ }
+ len = utf8_character_length(message, len);
+
+ if (len < 0) {
+ snprintf(buf, sizeof(buf),
+ ((messageLen > 1) && isdigit(message[1]))
+ ? "\\%03o"
+ : "\\%o",
+ *message & 0377);
+ len = 1;
+ } else {
+ buf[0] = '\0';
+ if (len == 1) {
+ if (*message == '\a') {
+ strcpy(buf, "\\a");
+ } else if (*message == '\b') {
+ strcpy(buf, "\\b");
+ } else if (*message == '\t') {
+ strcpy(buf, "\\t");
+ } else if (*message == '\v') {
+ strcpy(buf, "\\v");
+ } else if (*message == '\f') {
+ strcpy(buf, "\\f");
+ } else if (*message == '\r') {
+ strcpy(buf, "\\r");
+ } else if (*message == '\\') {
+ strcpy(buf, "\\\\");
+ } else if ((*message < ' ') || (*message & 0x80)) {
+ snprintf(buf, sizeof(buf), "\\%o", *message & 0377);
+ }
+ }
+ if (!buf[0]) {
+ strncpy(buf, message, len);
+ buf[len] = '\0';
+ }
+ }
+ if (print) {
+ strcpy(p, buf);
+ }
+ p += strlen(buf);
+ message += len;
+ messageLen -= len;
+ }
+ return p - begin;
+}
+
/**
* Formats a log message into a buffer
*
@@ -778,7 +911,7 @@
#else
ptm = localtime(&(entry->tv_sec));
#endif
- //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
+ /* strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm); */
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
len = strlen(timeBuf);
if (p_format->usec_time_output) {
@@ -873,24 +1006,34 @@
const char *pm;
if (prefixSuffixIsHeaderFooter) {
- // we're just wrapping message with a header/footer
+ /* we're just wrapping message with a header/footer */
numLines = 1;
} else {
pm = entry->message;
numLines = 0;
- // The line-end finding here must match the line-end finding
- // in for ( ... numLines...) loop below
+ /*
+ * The line-end finding here must match the line-end finding
+ * in for ( ... numLines...) loop below
+ */
while (pm < (entry->message + entry->messageLen)) {
if (*pm++ == '\n') numLines++;
}
- // plus one line for anything not newline-terminated at the end
+ /* plus one line for anything not newline-terminated at the end */
if (pm > entry->message && *(pm-1) != '\n') numLines++;
}
- // this is an upper bound--newlines in message may be counted
- // extraneously
- bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1;
+ /*
+ * this is an upper bound--newlines in message may be counted
+ * extraneously
+ */
+ bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
+ if (p_format->printable_output) {
+ /* Calculate extra length to convert non-printable to printable */
+ bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
+ } else {
+ bufferSize += entry->messageLen;
+ }
if (defaultBufferSize >= bufferSize) {
ret = defaultBuffer;
@@ -910,8 +1053,12 @@
if (prefixSuffixIsHeaderFooter) {
strcat(p, prefixBuf);
p += prefixLen;
- strncat(p, entry->message, entry->messageLen);
- p += entry->messageLen;
+ if (p_format->printable_output) {
+ p += convertPrintable(p, entry->message, entry->messageLen);
+ } else {
+ strncat(p, entry->message, entry->messageLen);
+ p += entry->messageLen;
+ }
strcat(p, suffixBuf);
p += suffixLen;
} else {
@@ -920,15 +1067,19 @@
size_t lineLen;
lineStart = pm;
- // Find the next end-of-line in message
+ /* Find the next end-of-line in message */
while (pm < (entry->message + entry->messageLen)
&& *pm != '\n') pm++;
lineLen = pm - lineStart;
strcat(p, prefixBuf);
p += prefixLen;
- strncat(p, lineStart, lineLen);
- p += lineLen;
+ if (p_format->printable_output) {
+ p += convertPrintable(p, lineStart, lineLen);
+ } else {
+ strncat(p, lineStart, lineLen);
+ p += lineLen;
+ }
strcat(p, suffixBuf);
p += suffixLen;
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 79c4c53..d7af34e 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -473,7 +473,7 @@
return kEmptyArchive;
}
- ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
+ ALOGV("+++ num_entries=%" PRIu32 " dir_size=%" PRIu32 " dir_offset=%" PRIu32,
eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
/*
@@ -1008,8 +1008,13 @@
// entry. Note that the call to ftruncate below will change the file size but
// will not allocate space on disk and this call to fallocate will not
// change the file size.
+ // Note: fallocate is only supported by the following filesystems -
+ // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with
+ // EOPNOTSUPP error when issued in other filesystems.
+ // Hence, check for the return error code before concluding that the
+ // disk does not have enough space.
result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
- if (result == -1) {
+ if (result == -1 && errno == ENOSPC) {
ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
static_cast<int64_t>(declared_length + current_offset), strerror(errno));
return std::unique_ptr<FileWriter>(nullptr);
diff --git a/logcat/Android.mk b/logcat/Android.mk
index f46a4de..7115f9b 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -5,7 +5,7 @@
LOCAL_SRC_FILES:= logcat.cpp event.logtags
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
LOCAL_MODULE := logcat
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 2c2d785..736e02e 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,29 +1,38 @@
// Copyright 2006-2015 The Android Open Source Project
+#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <unistd.h>
#include <sys/cdefs.h>
#include <sys/socket.h>
#include <sys/stat.h>
-#include <arpa/inet.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <memory>
+#include <string>
+
+#include <base/file.h>
+#include <base/strings.h>
+#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
+#include <log/event_tag_map.h>
#include <log/log.h>
#include <log/log_read.h>
-#include <log/logger.h>
#include <log/logd.h>
+#include <log/logger.h>
#include <log/logprint.h>
-#include <log/event_tag_map.h>
#define DEFAULT_MAX_ROTATED_LOGS 4
@@ -202,7 +211,15 @@
g_outFD = STDOUT_FILENO;
} else {
- struct stat statbuf;
+ if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+ fprintf(stderr, "failed to set background scheduling policy\n");
+ }
+
+ struct sched_param param;
+ memset(¶m, 0, sizeof(param));
+ if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
+ fprintf(stderr, "failed to set to batch scheduler\n");
+ }
g_outFD = openLogFile (g_outputFileName);
@@ -210,6 +227,7 @@
logcat_panic(false, "couldn't open output file");
}
+ struct stat statbuf;
if (fstat(g_outFD, &statbuf) == -1) {
close(g_outFD);
logcat_panic(false, "couldn't get output file stat\n");
@@ -231,11 +249,12 @@
fprintf(stderr, "options include:\n"
" -s Set default filter to silent.\n"
" Like specifying filterspec '*:S'\n"
- " -f <filename> Log to file. Default to stdout\n"
+ " -f <filename> Log to file. Default is stdout\n"
" -r <kbytes> Rotate log every kbytes. Requires -f\n"
" -n <count> Sets max number of rotated logs to <count>, default 4\n"
" -v <format> Sets the log print format, where <format> is:\n\n"
- " brief color long process raw tag thread threadtime time usec\n\n"
+ " brief color long printable process raw tag thread\n"
+ " threadtime time usec\n\n"
" -D print dividers between each log buffer\n"
" -c clear (flush) the entire log and exit\n"
" -d dump the log and then exit (don't block)\n"
@@ -352,6 +371,86 @@
exit(EXIT_FAILURE);
}
+static const char g_defaultTimeFormat[] = "%m-%d %H:%M:%S.%q";
+
+// Find last logged line in gestalt of all matching existing output files
+static log_time lastLogTime(char *outputFileName) {
+ log_time retval(log_time::EPOCH);
+ if (!outputFileName) {
+ return retval;
+ }
+
+ log_time now(CLOCK_REALTIME);
+
+ std::string directory;
+ char *file = strrchr(outputFileName, '/');
+ if (!file) {
+ directory = ".";
+ file = outputFileName;
+ } else {
+ *file = '\0';
+ directory = outputFileName;
+ *file = '/';
+ ++file;
+ }
+ size_t len = strlen(file);
+ log_time modulo(0, NS_PER_SEC);
+ std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(directory.c_str()), closedir);
+ struct dirent *dp;
+ while ((dp = readdir(dir.get())) != NULL) {
+ if ((dp->d_type != DT_REG)
+ || strncmp(dp->d_name, file, len)
+ || (dp->d_name[len]
+ && ((dp->d_name[len] != '.')
+ || !isdigit(dp->d_name[len+1])))) {
+ continue;
+ }
+
+ std::string file_name = directory;
+ file_name += "/";
+ file_name += dp->d_name;
+ std::string file;
+ if (!android::base::ReadFileToString(file_name, &file)) {
+ continue;
+ }
+
+ bool found = false;
+ for (const auto& line : android::base::Split(file, "\n")) {
+ log_time t(log_time::EPOCH);
+ char *ep = t.strptime(line.c_str(), g_defaultTimeFormat);
+ if (!ep || (*ep != ' ')) {
+ continue;
+ }
+ // determine the time precision of the logs (eg: msec or usec)
+ for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
+ if (t.tv_nsec % (mod * 10)) {
+ modulo.tv_nsec = mod;
+ break;
+ }
+ }
+ // We filter any times later than current as we may not have the
+ // year stored with each log entry. Also, since it is possible for
+ // entries to be recorded out of order (very rare) we select the
+ // maximum we find just in case.
+ if ((t < now) && (t > retval)) {
+ retval = t;
+ found = true;
+ }
+ }
+ // We count on the basename file to be the definitive end, so stop here.
+ if (!dp->d_name[len] && found) {
+ break;
+ }
+ }
+ if (retval == log_time::EPOCH) {
+ return retval;
+ }
+ // tail_time prints matching or higher, round up by the modulo to prevent
+ // a replay of the last entry we have just checked.
+ retval += modulo;
+ return retval;
+}
+
} /* namespace android */
@@ -417,12 +516,11 @@
/* FALLTHRU */
case 'T':
if (strspn(optarg, "0123456789") != strlen(optarg)) {
- char *cp = tail_time.strptime(optarg,
- log_time::default_format);
+ char *cp = tail_time.strptime(optarg, g_defaultTimeFormat);
if (!cp) {
logcat_panic(false,
"-%c \"%s\" not in \"%s\" time format\n",
- ret, optarg, log_time::default_format);
+ ret, optarg, g_defaultTimeFormat);
}
if (*cp) {
char c = *cp;
@@ -545,9 +643,11 @@
break;
case 'f':
+ if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
+ tail_time = lastLogTime(optarg);
+ }
// redirect output to a file
g_outputFileName = optarg;
-
break;
case 'r':
diff --git a/logd/Android.mk b/logd/Android.mk
index 73da8dc..615d030 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -41,4 +41,15 @@
include $(BUILD_EXECUTABLE)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := logpersist.start
+LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(bin_dir)
+LOCAL_SRC_FILES := logpersist
+ALL_TOOLS := logpersist.start logpersist.stop logpersist.cat
+LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,$(filter-out $(LOCAL_MODULE),$(ALL_TOOLS)),ln -sf $(LOCAL_MODULE) $(TARGET_OUT)/bin/$(t);)
+include $(BUILD_PREBUILT)
+
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1da52d8..4373e2a 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -22,6 +22,8 @@
#include <time.h>
#include <unistd.h>
+#include <unordered_map>
+
#include <cutils/properties.h>
#include <log/logger.h>
@@ -246,31 +248,21 @@
uint64_t getKey() { return value; }
};
-class LogBufferElementEntry {
- const uint64_t key;
- LogBufferElement *last;
+class LogBufferElementLast {
+
+ typedef std::unordered_map<uint64_t, LogBufferElement *> LogBufferElementMap;
+ LogBufferElementMap map;
public:
- LogBufferElementEntry(const uint64_t &k, LogBufferElement *e):key(k),last(e) { }
- const uint64_t&getKey() const { return key; }
-
- LogBufferElement *getLast() { return last; }
-};
-
-class LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> {
-
-public:
bool merge(LogBufferElement *e, unsigned short dropped) {
LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
- android::hash_t hash = android::hash_type(key.getKey());
- ssize_t index = find(-1, hash, key.getKey());
- if (index != -1) {
- LogBufferElementEntry &entry = editEntryAt(index);
- LogBufferElement *l = entry.getLast();
+ LogBufferElementMap::iterator it = map.find(key.getKey());
+ if (it != map.end()) {
+ LogBufferElement *l = it->second;
unsigned short d = l->getDropped();
if ((dropped + d) > USHRT_MAX) {
- removeAt(index);
+ map.erase(it);
} else {
l->setDropped(dropped + d);
return true;
@@ -279,26 +271,25 @@
return false;
}
- size_t add(LogBufferElement *e) {
+ void add(LogBufferElement *e) {
LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
- android::hash_t hash = android::hash_type(key.getKey());
- return android::BasicHashtable<uint64_t, LogBufferElementEntry>::
- add(hash, LogBufferElementEntry(key.getKey(), e));
+ map[key.getKey()] = e;
}
inline void clear() {
- android::BasicHashtable<uint64_t, LogBufferElementEntry>::clear();
+ map.clear();
}
void clear(LogBufferElement *e) {
- uint64_t current = e->getRealTime().nsec() - NS_PER_SEC;
- ssize_t index = -1;
- while((index = next(index)) >= 0) {
- LogBufferElement *l = editEntryAt(index).getLast();
+ uint64_t current = e->getRealTime().nsec()
+ - (EXPIRE_RATELIMIT * NS_PER_SEC);
+ for(LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
+ LogBufferElement *l = it->second;
if ((l->getDropped() >= EXPIRE_THRESHOLD)
&& (current > l->getRealTime().nsec())) {
- removeAt(index);
- index = -1;
+ it = map.erase(it);
+ } else {
+ ++it;
}
}
}
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 3d7237e..8238a52 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -104,8 +104,8 @@
// assumption: mMsg == NULL
size_t LogBufferElement::populateDroppedMessage(char *&buffer,
LogBuffer *parent) {
- static const char tag[] = "logd";
- static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s";
+ static const char tag[] = "chatty";
+ static const char format_uid[] = "uid=%u%s%s expire %u line%s";
char *name = parent->uidToName(mUid);
char *commName = android::tidToName(mTid);
@@ -115,9 +115,15 @@
if (!commName) {
commName = parent->pidToName(mPid);
}
- if (name && commName && !strcmp(name, commName)) {
- free(commName);
- commName = NULL;
+ size_t len = name ? strlen(name) : 0;
+ if (len && commName && !strncmp(name, commName, len)) {
+ if (commName[len] == '\0') {
+ free(commName);
+ commName = NULL;
+ } else {
+ free(name);
+ name = NULL;
+ }
}
if (name) {
char *p = NULL;
@@ -129,16 +135,16 @@
}
if (commName) {
char *p = NULL;
- asprintf(&p, " comm=%s", commName);
+ asprintf(&p, " %s", commName);
if (p) {
free(commName);
commName = p;
}
}
// identical to below to calculate the buffer size required
- size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
- commName ? commName : "",
- mDropped, (mDropped > 1) ? "s" : "");
+ len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
+ commName ? commName : "",
+ mDropped, (mDropped > 1) ? "s" : "");
size_t hdrLen;
if (mLogId == LOG_ID_EVENTS) {
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 3dcf9d1..ca2c3a6 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -50,8 +50,9 @@
#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
// non-chatty UIDs less than this age in hours
-#define EXPIRE_THRESHOLD 4 // A smaller expire count is considered too
+#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
// chatty for the temporal expire messages
+#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
class LogBufferElement {
const log_id_t mLogId;
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 8df0d0a..7d14648 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -36,6 +36,140 @@
static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
+// Parsing is hard
+
+// called if we see a '<', s is the next character, returns pointer after '>'
+static char *is_prio(char *s) {
+ if (!isdigit(*s++)) {
+ return NULL;
+ }
+ char c;
+ while ((c = *s++)) {
+ if (!isdigit(c) && (c == '>')) {
+ return s;
+ }
+ }
+ return NULL;
+}
+
+// called if we see a '[', s is the next character, returns pointer after ']'
+static char *is_timestamp(char *s) {
+ while (*s == ' ') {
+ ++s;
+ }
+ if (!isdigit(*s++)) {
+ return NULL;
+ }
+ bool first_period = true;
+ char c;
+ while ((c = *s++)) {
+ if ((c == '.') && first_period) {
+ first_period = false;
+ continue;
+ }
+ if (!isdigit(c) && (c == ']')) {
+ return s;
+ }
+ }
+ return NULL;
+}
+
+// Like strtok_r with "\r\n" except that we look for log signatures (regex)
+// \(\(<[0-9]+>\)\([[] *[0-9]+[]]\)\{0,1\}\|[[] *[0-9]+[]]\)
+// and split if we see a second one without a newline.
+
+#define SIGNATURE_MASK 0xF0
+// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
+#define LESS_THAN_SIG SIGNATURE_MASK
+#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
+// space is one more than <digit> of 9
+#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
+
+char *log_strtok_r(char *s, char **last) {
+ if (!s) {
+ if (!(s = *last)) {
+ return NULL;
+ }
+ // fixup for log signature split <,
+ // LESS_THAN_SIG + <digit>
+ if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) {
+ *s = (*s & ~SIGNATURE_MASK) + '0';
+ *--s = '<';
+ }
+ // fixup for log signature split [,
+ // OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit>
+ if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) {
+ if (*s == OPEN_BRACKET_SPACE) {
+ *s = ' ';
+ } else {
+ *s = (*s & ~SIGNATURE_MASK) + '0';
+ }
+ *--s = '[';
+ }
+ }
+
+ s += strspn(s, "\r\n");
+
+ if (!*s) { // no non-delimiter characters
+ *last = NULL;
+ return NULL;
+ }
+ char *peek, *tok = s;
+
+ for (;;) {
+ char c = *s++;
+ switch (c) {
+ case '\0':
+ *last = NULL;
+ return tok;
+
+ case '\r':
+ case '\n':
+ s[-1] = '\0';
+ *last = s;
+ return tok;
+
+ case '<':
+ peek = is_prio(s);
+ if (!peek) {
+ break;
+ }
+ if (s != (tok + 1)) { // not first?
+ s[-1] = '\0';
+ *s &= ~SIGNATURE_MASK;
+ *s |= LESS_THAN_SIG; // signature for '<'
+ *last = s;
+ return tok;
+ }
+ s = peek;
+ if ((*s == '[') && ((peek = is_timestamp(s + 1)))) {
+ s = peek;
+ }
+ break;
+
+ case '[':
+ peek = is_timestamp(s);
+ if (!peek) {
+ break;
+ }
+ if (s != (tok + 1)) { // not first?
+ s[-1] = '\0';
+ if (*s == ' ') {
+ *s = OPEN_BRACKET_SPACE;
+ } else {
+ *s &= ~SIGNATURE_MASK;
+ *s |= OPEN_BRACKET_SIG; // signature for '['
+ }
+ *last = s;
+ return tok;
+ }
+ s = peek;
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
+
log_time LogKlog::correction = log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC);
LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
@@ -81,8 +215,8 @@
char *ep = buffer + len;
*ep = '\0';
len = 0;
- for(char *ptr, *tok = buffer;
- ((tok = strtok_r(tok, "\r\n", &ptr)));
+ for(char *ptr = NULL, *tok = buffer;
+ ((tok = log_strtok_r(tok, &ptr)));
tok = NULL) {
if (((tok + strlen(tok)) == ep) && (retval != 0) && full) {
len = strlen(tok);
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 8de9c87..a898c63 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -21,6 +21,8 @@
#include <log/log_read.h>
#include "LogReader.h"
+char *log_strtok_r(char *str, char **saveptr);
+
class LogKlog : public SocketListener {
LogBuffer *logbuf;
LogReader *reader;
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 90c49c0..48c2fe6 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -161,9 +161,8 @@
}
// report uid -> pid(s) -> pidToName if unique
- ssize_t index = -1;
- while ((index = pidTable.next(index)) != -1) {
- const PidEntry &entry = pidTable.entryAt(index);
+ for(pidTable_t::iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
+ const PidEntry &entry = it->second;
if (entry.getUid() == uid) {
const char *n = entry.getName();
@@ -520,12 +519,12 @@
}
uid_t LogStatistics::pidToUid(pid_t pid) {
- return pidTable.entryAt(pidTable.add(pid)).getUid();
+ return pidTable.add(pid)->second.getUid();
}
// caller must free character string
char *LogStatistics::pidToName(pid_t pid) {
- const char *name = pidTable.entryAt(pidTable.add(pid)).getName();
+ const char *name = pidTable.add(pid)->second.getName();
if (!name) {
return NULL;
}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f60f3ed..b9e9650 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -21,8 +21,9 @@
#include <stdlib.h>
#include <sys/types.h>
+#include <unordered_map>
+
#include <log/log.h>
-#include <utils/BasicHashtable.h>
#include "LogBufferElement.h"
@@ -30,8 +31,14 @@
for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
template <typename TKey, typename TEntry>
-class LogHashtable : public android::BasicHashtable<TKey, TEntry> {
+class LogHashtable {
+
+ std::unordered_map<TKey, TEntry> map;
+
public:
+
+ typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
+
std::unique_ptr<const TEntry *[]> sort(size_t n) {
if (!n) {
std::unique_ptr<const TEntry *[]> sorted(NULL);
@@ -41,9 +48,8 @@
const TEntry **retval = new const TEntry* [n];
memset(retval, 0, sizeof(*retval) * n);
- ssize_t index = -1;
- while ((index = android::BasicHashtable<TKey, TEntry>::next(index)) >= 0) {
- const TEntry &entry = android::BasicHashtable<TKey, TEntry>::entryAt(index);
+ for(iterator it = map.begin(); it != map.end(); ++it) {
+ const TEntry &entry = it->second;
size_t s = entry.getSizes();
ssize_t i = n - 1;
while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0))
@@ -70,45 +76,43 @@
return index;
}
- ssize_t next(ssize_t index) {
- return android::BasicHashtable<TKey, TEntry>::next(index);
+ inline iterator add(TKey key, LogBufferElement *e) {
+ iterator it = map.find(key);
+ if (it == map.end()) {
+ it = map.insert(std::make_pair(key, TEntry(e))).first;
+ } else {
+ it->second.add(e);
+ }
+ return it;
}
- size_t add(TKey key, LogBufferElement *e) {
- android::hash_t hash = android::hash_type(key);
- ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
- if (index == -1) {
- return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(e));
+ inline iterator add(TKey key) {
+ iterator it = map.find(key);
+ if (it == map.end()) {
+ it = map.insert(std::make_pair(key, TEntry(key))).first;
+ } else {
+ it->second.add(key);
}
- android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(e);
- return index;
- }
-
- inline size_t add(TKey key) {
- android::hash_t hash = android::hash_type(key);
- ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
- if (index == -1) {
- return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(key));
- }
- android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(key);
- return index;
+ return it;
}
void subtract(TKey key, LogBufferElement *e) {
- ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
- if ((index != -1)
- && android::BasicHashtable<TKey, TEntry>::editEntryAt(index).subtract(e)) {
- android::BasicHashtable<TKey, TEntry>::removeAt(index);
+ iterator it = map.find(key);
+ if ((it != map.end()) && it->second.subtract(e)) {
+ map.erase(it);
}
}
inline void drop(TKey key, LogBufferElement *e) {
- ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
- if (index != -1) {
- android::BasicHashtable<TKey, TEntry>::editEntryAt(index).drop(e);
+ iterator it = map.find(key);
+ if (it != map.end()) {
+ it->second.drop(e);
}
}
+ inline iterator begin() { return map.begin(); }
+ inline iterator end() { return map.end(); }
+
};
struct EntryBase {
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index ec67c07..68a0680 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -31,6 +31,7 @@
mRelease(false),
mError(false),
threadRunning(false),
+ leadingDropped(false),
mReader(reader),
mLogMask(logMask),
mPid(pid),
@@ -123,6 +124,8 @@
bool privileged = FlushCommand::hasReadLogs(client);
+ me->leadingDropped = true;
+
lock();
while (me->threadRunning && !me->isError_Locked()) {
@@ -132,6 +135,7 @@
if (me->mTail) {
logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
+ me->leadingDropped = true;
}
start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
@@ -163,6 +167,14 @@
LogTimeEntry::lock();
+ if (me->leadingDropped) {
+ if (element->getDropped()) {
+ LogTimeEntry::unlock();
+ return false;
+ }
+ me->leadingDropped = false;
+ }
+
if (me->mCount == 0) {
me->mStart = element->getSequence();
}
@@ -190,6 +202,13 @@
goto skip;
}
+ if (me->leadingDropped) {
+ if (element->getDropped()) {
+ goto skip;
+ }
+ me->leadingDropped = false;
+ }
+
// Truncate to close race between first and second pass
if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
goto stop;
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index ae2f92b..783bce6 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -32,6 +32,7 @@
bool mRelease;
bool mError;
bool threadRunning;
+ bool leadingDropped;
pthread_cond_t threadTriggeredCondition;
pthread_t mThread;
LogReader &mReader;
diff --git a/logd/README.property b/logd/README.property
index ad7d0cd..a472efd 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -10,6 +10,8 @@
default false
ro.build.type string if user, logd.statistics & logd.klogd
default false
+persist.logd.logpersistd string Enable logpersist daemon, "logcatd"
+ turns on logcat -f in logd context
persist.logd.size number 256K default size of the buffer for all
log ids at initial startup, at runtime
use: logcat -b all -G <value>
diff --git a/logd/logpersist b/logd/logpersist
new file mode 100755
index 0000000..215e1e2
--- /dev/null
+++ b/logd/logpersist
@@ -0,0 +1,36 @@
+#! /system/bin/sh
+# logpersist cat start and stop handlers
+data=/data/misc/logd
+property=persist.logd.logpersistd
+service=logcatd
+progname="${0##*/}"
+if [ X"${1}" = "-h" -o X"${1}" = X"--help" ]; then
+ echo "${progname%.*}.cat - dump current ${service%d} logs"
+ echo "${progname%.*}.start - start ${service} service"
+ echo "${progname%.*}.stop [--clear] - stop ${service} service"
+ exit 0
+fi
+case ${progname} in
+*.cat)
+ su 1036 ls "${data}" |
+ tr -d '\r' |
+ sort -ru |
+ sed "s#^#${data}/#" |
+ su 1036 xargs cat
+ ;;
+*.start)
+ su 0 setprop ${property} ${service}
+ getprop ${property}
+ sleep 1
+ ps -t | grep "${data##*/}.*${service%d}"
+ ;;
+*.stop)
+ su 0 stop ${service}
+ su 0 setprop ${property} ""
+ [ X"${1}" != X"-c" -a X"${1}" != X"--clear" ] ||
+ ( sleep 1 ; su 1036,9998 rm -rf "${data}" )
+ ;;
+*)
+ echo "Unexpected command ${0##*/} ${@}" >&2
+ exit 1
+esac
diff --git a/logd/main.cpp b/logd/main.cpp
index 6db819e..805cbe6 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -417,8 +417,8 @@
kl->synchronize(buf);
}
- for (char *ptr, *tok = buf;
- (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
+ for (char *ptr = NULL, *tok = buf;
+ (rc >= 0) && ((tok = log_strtok_r(tok, &ptr)));
tok = NULL) {
if (al) {
rc = al->log(tok);
diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk
index 0c9b0c6..8661d7d 100644
--- a/mkbootimg/Android.mk
+++ b/mkbootimg/Android.mk
@@ -2,12 +2,10 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := mkbootimg.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-LOCAL_CFLAGS := -Werror
+LOCAL_SRC_FILES := mkbootimg
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE := mkbootimg
-include $(BUILD_HOST_EXECUTABLE)
-
-$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
+include $(BUILD_PREBUILT)
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
new file mode 100755
index 0000000..aea2585
--- /dev/null
+++ b/mkbootimg/mkbootimg
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+# Copyright 2015, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+from sys import argv, exit, stderr
+from argparse import ArgumentParser, FileType, Action
+from os import fstat
+from struct import pack
+from hashlib import sha1
+
+def filesize(f):
+ if f is None:
+ return 0
+ try:
+ return fstat(f.fileno()).st_size
+ except OSError:
+ return 0
+
+
+def update_sha(sha, f):
+ if f:
+ sha.update(f.read())
+ f.seek(0)
+ sha.update(pack('I', filesize(f)))
+ else:
+ sha.update(pack('I', 0))
+
+
+def pad_file(f, padding):
+ pad = (padding - (f.tell() & (padding - 1))) & (padding - 1)
+ f.write(pack(str(pad) + 'x'))
+
+
+def write_header(args):
+ BOOT_MAGIC = 'ANDROID!'.encode()
+ args.output.write(pack('8s', BOOT_MAGIC))
+ args.output.write(pack('8I',
+ filesize(args.kernel), # size in bytes
+ args.base + args.kernel_offset, # physical load addr
+ filesize(args.ramdisk), # size in bytes
+ args.base + args.ramdisk_offset, # physical load addr
+ filesize(args.second), # size in bytes
+ args.base + args.second_offset, # physical load addr
+ args.base + args.tags_offset, # physical addr for kernel tags
+ args.pagesize)) # flash page size we assume
+ args.output.write(pack('8x')) # future expansion: should be 0
+ args.output.write(pack('16s', args.board.encode())) # asciiz product name
+ args.output.write(pack('512s', args.cmdline[:512].encode()))
+
+ sha = sha1()
+ update_sha(sha, args.kernel)
+ update_sha(sha, args.ramdisk)
+ update_sha(sha, args.second)
+ img_id = pack('32s', sha.digest())
+
+ args.output.write(img_id)
+ args.output.write(pack('1024s', args.cmdline[512:].encode()))
+ pad_file(args.output, args.pagesize)
+ return img_id
+
+
+class ValidateStrLenAction(Action):
+ def __init__(self, option_strings, dest, nargs=None, **kwargs):
+ if 'maxlen' not in kwargs:
+ raise ValueError('maxlen must be set')
+ self.maxlen = int(kwargs['maxlen'])
+ del kwargs['maxlen']
+ super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ if len(values) > self.maxlen:
+ raise ValueError('String argument too long: max {0:d}, got {1:d}'.
+ format(self.maxlen, len(values)))
+ setattr(namespace, self.dest, values)
+
+
+def write_padded_file(f_out, f_in, padding):
+ if f_in is None:
+ return
+ f_out.write(f_in.read())
+ pad_file(f_out, padding)
+
+
+def parse_int(x):
+ return int(x, 0)
+
+
+def parse_cmdline():
+ parser = ArgumentParser()
+ parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'),
+ required=True)
+ parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
+ parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
+ parser.add_argument('--cmdline', help='extra arguments to be passed on the '
+ 'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
+ parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
+ parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000)
+ parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000)
+ parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
+ default=0x00f00000)
+ parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
+ parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
+ maxlen=16)
+ parser.add_argument('--pagesize', help='page size', type=parse_int,
+ choices=[2**i for i in range(11,15)], default=2048)
+ parser.add_argument('--id', help='print the image ID on standard output',
+ action='store_true')
+ parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'),
+ required=True)
+ return parser.parse_args()
+
+
+def write_data(args):
+ write_padded_file(args.output, args.kernel, args.pagesize)
+ write_padded_file(args.output, args.ramdisk, args.pagesize)
+ write_padded_file(args.output, args.second, args.pagesize)
+
+
+def main():
+ args = parse_cmdline()
+ img_id = write_header(args)
+ write_data(args)
+ if args.id:
+ print('0x' + ''.join('{:02x}'.format(ord(c)) for c in img_id))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
deleted file mode 100644
index 40e5261..0000000
--- a/mkbootimg/mkbootimg.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* tools/mkbootimg/mkbootimg.c
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdbool.h>
-
-#include "mincrypt/sha.h"
-#include "bootimg.h"
-
-static void *load_file(const char *fn, unsigned *_sz)
-{
- char *data;
- int sz;
- int fd;
-
- data = 0;
- fd = open(fn, O_RDONLY);
- if(fd < 0) return 0;
-
- sz = lseek(fd, 0, SEEK_END);
- if(sz < 0) goto oops;
-
- if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
-
- data = (char*) malloc(sz);
- if(data == 0) goto oops;
-
- if(read(fd, data, sz) != sz) goto oops;
- close(fd);
-
- if(_sz) *_sz = sz;
- return data;
-
-oops:
- close(fd);
- if(data != 0) free(data);
- return 0;
-}
-
-int usage(void)
-{
- fprintf(stderr,"usage: mkbootimg\n"
- " --kernel <filename>\n"
- " --ramdisk <filename>\n"
- " [ --second <2ndbootloader-filename> ]\n"
- " [ --cmdline <kernel-commandline> ]\n"
- " [ --board <boardname> ]\n"
- " [ --base <address> ]\n"
- " [ --pagesize <pagesize> ]\n"
- " [ --id ]\n"
- " -o|--output <filename>\n"
- );
- return 1;
-}
-
-
-
-static unsigned char padding[16384] = { 0, };
-
-static void print_id(const uint8_t *id, size_t id_len) {
- printf("0x");
- for (unsigned i = 0; i < id_len; i++) {
- printf("%02x", id[i]);
- }
- printf("\n");
-}
-
-int write_padding(int fd, unsigned pagesize, unsigned itemsize)
-{
- unsigned pagemask = pagesize - 1;
- ssize_t count;
-
- if((itemsize & pagemask) == 0) {
- return 0;
- }
-
- count = pagesize - (itemsize & pagemask);
-
- if(write(fd, padding, count) != count) {
- return -1;
- } else {
- return 0;
- }
-}
-
-int main(int argc, char **argv)
-{
- boot_img_hdr hdr;
-
- char *kernel_fn = NULL;
- void *kernel_data = NULL;
- char *ramdisk_fn = NULL;
- void *ramdisk_data = NULL;
- char *second_fn = NULL;
- void *second_data = NULL;
- char *cmdline = "";
- char *bootimg = NULL;
- char *board = "";
- uint32_t pagesize = 2048;
- int fd;
- SHA_CTX ctx;
- const uint8_t* sha;
- uint32_t base = 0x10000000U;
- uint32_t kernel_offset = 0x00008000U;
- uint32_t ramdisk_offset = 0x01000000U;
- uint32_t second_offset = 0x00f00000U;
- uint32_t tags_offset = 0x00000100U;
- size_t cmdlen;
-
- argc--;
- argv++;
-
- memset(&hdr, 0, sizeof(hdr));
-
- bool get_id = false;
- while(argc > 0){
- char *arg = argv[0];
- if (!strcmp(arg, "--id")) {
- get_id = true;
- argc -= 1;
- argv += 1;
- } else if(argc >= 2) {
- char *val = argv[1];
- argc -= 2;
- argv += 2;
- if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
- bootimg = val;
- } else if(!strcmp(arg, "--kernel")) {
- kernel_fn = val;
- } else if(!strcmp(arg, "--ramdisk")) {
- ramdisk_fn = val;
- } else if(!strcmp(arg, "--second")) {
- second_fn = val;
- } else if(!strcmp(arg, "--cmdline")) {
- cmdline = val;
- } else if(!strcmp(arg, "--base")) {
- base = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--kernel_offset")) {
- kernel_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--ramdisk_offset")) {
- ramdisk_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--second_offset")) {
- second_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--tags_offset")) {
- tags_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--board")) {
- board = val;
- } else if(!strcmp(arg,"--pagesize")) {
- pagesize = strtoul(val, 0, 10);
- if ((pagesize != 2048) && (pagesize != 4096)
- && (pagesize != 8192) && (pagesize != 16384)) {
- fprintf(stderr,"error: unsupported page size %d\n", pagesize);
- return -1;
- }
- } else {
- return usage();
- }
- } else {
- return usage();
- }
- }
- hdr.page_size = pagesize;
-
- hdr.kernel_addr = base + kernel_offset;
- hdr.ramdisk_addr = base + ramdisk_offset;
- hdr.second_addr = base + second_offset;
- hdr.tags_addr = base + tags_offset;
-
- if(bootimg == 0) {
- fprintf(stderr,"error: no output filename specified\n");
- return usage();
- }
-
- if(kernel_fn == 0) {
- fprintf(stderr,"error: no kernel image specified\n");
- return usage();
- }
-
- if(ramdisk_fn == 0) {
- fprintf(stderr,"error: no ramdisk image specified\n");
- return usage();
- }
-
- if(strlen(board) >= BOOT_NAME_SIZE) {
- fprintf(stderr,"error: board name too large\n");
- return usage();
- }
-
- strcpy((char *) hdr.name, board);
-
- memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
-
- cmdlen = strlen(cmdline);
- if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) {
- fprintf(stderr,"error: kernel commandline too large\n");
- return 1;
- }
- /* Even if we need to use the supplemental field, ensure we
- * are still NULL-terminated */
- strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1);
- hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0';
- if (cmdlen >= (BOOT_ARGS_SIZE - 1)) {
- cmdline += (BOOT_ARGS_SIZE - 1);
- strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE);
- }
-
- kernel_data = load_file(kernel_fn, &hdr.kernel_size);
- if(kernel_data == 0) {
- fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
- return 1;
- }
-
- if(!strcmp(ramdisk_fn,"NONE")) {
- ramdisk_data = 0;
- hdr.ramdisk_size = 0;
- } else {
- ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);
- if(ramdisk_data == 0) {
- fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn);
- return 1;
- }
- }
-
- if(second_fn) {
- second_data = load_file(second_fn, &hdr.second_size);
- if(second_data == 0) {
- fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn);
- return 1;
- }
- }
-
- /* put a hash of the contents in the header so boot images can be
- * differentiated based on their first 2k.
- */
- SHA_init(&ctx);
- SHA_update(&ctx, kernel_data, hdr.kernel_size);
- SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
- SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
- SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
- SHA_update(&ctx, second_data, hdr.second_size);
- SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
- sha = SHA_final(&ctx);
- memcpy(hdr.id, sha,
- SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
-
- fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
- if(fd < 0) {
- fprintf(stderr,"error: could not create '%s'\n", bootimg);
- return 1;
- }
-
- if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
- if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
-
- if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail;
- if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
-
- if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail;
- if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
-
- if(second_data) {
- if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail;
- if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
- }
-
- if (get_id) {
- print_id((uint8_t *) hdr.id, sizeof(hdr.id));
- }
-
- return 0;
-
-fail:
- unlink(bootimg);
- close(fd);
- fprintf(stderr,"error: failed writing '%s': %s\n", bootimg,
- strerror(errno));
- return 1;
-}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0966038..b5b74ea 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -321,7 +321,7 @@
restorecon_recursive /data
# Check any timezone data in /data is newer than the copy in /system, delete if not.
- exec u:r:tzdatacheck:s0 system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
+ exec - system system -- /system/bin/tzdatacheck /system/usr/share/zoneinfo /data/misc/zoneinfo
# If there is no fs-post-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
@@ -649,3 +649,17 @@
class late_start
user root
oneshot
+
+on property:persist.logd.logpersistd=logcatd
+ # all exec/services are called with umask(077), so no gain beyond 0700
+ mkdir /data/misc/logd 0700 logd log
+ # logd for write to /data/misc/logd, log group for read from pstore (-L)
+ exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+ start logcatd
+
+service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+ class late_start
+ disabled
+ # logd for write to /data/misc/logd, log group for read from log daemon
+ user logd
+ group log
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index cd8d350..50944e6 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -1,6 +1,6 @@
## Permissions to allow system-wide tracing to the kernel trace buffer.
##
-on early-boot
+on boot
# Allow writing to the kernel trace log.
chmod 0222 /sys/kernel/debug/tracing/trace_marker
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index ad99a39..fc38907 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -2,7 +2,6 @@
common_cflags := \
- -std=gnu99 \
-Werror -Wno-unused-parameter \
-I$(LOCAL_PATH)/upstream-netbsd/include/ \
-include bsd-compatibility.h \
@@ -63,10 +62,12 @@
ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
LOCAL_SRC_FILES := \
+ start_stop.cpp \
toolbox.c \
$(patsubst %,%.c,$(OUR_TOOLS)) \
LOCAL_CFLAGS += $(common_cflags)
+LOCAL_CONLYFLAGS += -std=gnu99
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/toolbox/start.c b/toolbox/start.c
index 6c8a3f2..cca5fef 100644
--- a/toolbox/start.c
+++ b/toolbox/start.c
@@ -1,21 +1 @@
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-
-int start_main(int argc, char *argv[])
-{
- if(argc > 1) {
- property_set("ctl.start", argv[1]);
- } else {
- /* defaults to starting the common services stopped by stop.c */
- property_set("ctl.start", "netd");
- property_set("ctl.start", "surfaceflinger");
- property_set("ctl.start", "zygote");
- property_set("ctl.start", "zygote_secondary");
- }
-
- return 0;
-}
+/* Needed by Android.mk. Actual code in start_stop.cpp. */
diff --git a/toolbox/start_stop.cpp b/toolbox/start_stop.cpp
new file mode 100644
index 0000000..dc48c0c
--- /dev/null
+++ b/toolbox/start_stop.cpp
@@ -0,0 +1,43 @@
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+
+static const char* services[] = {
+ "netd",
+ "surfaceflinger",
+ "zygote",
+ "zygote_secondary",
+};
+
+static int start_stop(bool start, int argc, char* argv[]) {
+ if (getuid() != 0) error(1, 0, "must be root");
+ const char* property = start ? "ctl.start" : "ctl.stop";
+ if (argc > 2) {
+ error(1, 0, "usage: %s [SERVICE]\n", argv[0]);
+ } else if (argc == 2) {
+ property_set(property, argv[1]);
+ } else {
+ if (start) {
+ for (size_t i = 0; i < sizeof(services)/sizeof(services[0]); ++i) {
+ property_set(property, services[i]);
+ }
+ } else {
+ for (int i = sizeof(services)/sizeof(services[0]) - 1; i >= 0; --i) {
+ property_set(property, services[i]);
+ }
+ }
+ }
+ return 0;
+}
+
+extern "C" int start_main(int argc, char* argv[]) {
+ return start_stop(true, argc, argv);
+}
+
+extern "C" int stop_main(int argc, char* argv[]) {
+ return start_stop(false, argc, argv);
+}
diff --git a/toolbox/stop.c b/toolbox/stop.c
index 5e3ce3c..cca5fef 100644
--- a/toolbox/stop.c
+++ b/toolbox/stop.c
@@ -1,19 +1 @@
-#include <stdio.h>
-#include <string.h>
-
-#include <cutils/properties.h>
-
-int stop_main(int argc, char *argv[])
-{
- if(argc > 1) {
- property_set("ctl.stop", argv[1]);
- } else{
- /* defaults to stopping the common services */
- property_set("ctl.stop", "zygote_secondary");
- property_set("ctl.stop", "zygote");
- property_set("ctl.stop", "surfaceflinger");
- property_set("ctl.stop", "netd");
- }
-
- return 0;
-}
+/* Needed by Android.mk. Actual code in start_stop.cpp. */