am 0d4a4cb8: fastboot: allow format on devices with small buffers
* commit '0d4a4cb8aa16fdb3897eaa89a62cb055d8dcbdf9':
fastboot: allow format on devices with small buffers
diff --git a/adb/adb.c b/adb/adb.c
index e116414..018dd3c 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -318,6 +318,15 @@
#endif
}
+static void send_msg_with_okay(int fd, char* msg, size_t msglen) {
+ char header[9];
+ if (msglen > 0xffff)
+ msglen = 0xffff;
+ snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
+ writex(fd, header, 8);
+ writex(fd, msg, msglen);
+}
+
static void send_connect(atransport *t)
{
D("Calling send_connect \n");
@@ -1421,7 +1430,6 @@
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
{
atransport *transport = NULL;
- char buf[4096];
if(!strcmp(service, "kill")) {
fprintf(stderr,"adb server killed by remote request\n");
@@ -1467,13 +1475,11 @@
char buffer[4096];
int use_long = !strcmp(service+7, "-l");
if (use_long || service[7] == 0) {
- memset(buf, 0, sizeof(buf));
memset(buffer, 0, sizeof(buffer));
D("Getting device list \n");
list_transports(buffer, sizeof(buffer), use_long);
- snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
D("Wrote device list \n");
- writex(reply_fd, buf, strlen(buf));
+ send_msg_with_okay(reply_fd, buffer, strlen(buffer));
return 0;
}
}
@@ -1502,8 +1508,7 @@
}
}
- snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer), buffer);
- writex(reply_fd, buf, strlen(buf));
+ send_msg_with_okay(reply_fd, buffer, strlen(buffer));
return 0;
}
@@ -1511,8 +1516,7 @@
if (!strcmp(service, "version")) {
char version[12];
snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
- snprintf(buf, sizeof buf, "OKAY%04x%s", (unsigned)strlen(version), version);
- writex(reply_fd, buf, strlen(buf));
+ send_msg_with_okay(reply_fd, version, strlen(version));
return 0;
}
@@ -1522,8 +1526,7 @@
if (transport && transport->serial) {
out = transport->serial;
}
- snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
- writex(reply_fd, buf, strlen(buf));
+ send_msg_with_okay(reply_fd, out, strlen(out));
return 0;
}
if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
@@ -1532,8 +1535,7 @@
if (transport && transport->devpath) {
out = transport->devpath;
}
- snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(out),out);
- writex(reply_fd, buf, strlen(buf));
+ send_msg_with_okay(reply_fd, out, strlen(out));
return 0;
}
// indicates a new emulator instance has started
@@ -1547,14 +1549,11 @@
if(!strcmp(service,"list-forward")) {
// Create the list of forward redirections.
- char header[9];
int buffer_size = format_listeners(NULL, 0);
// Add one byte for the trailing zero.
char* buffer = malloc(buffer_size+1);
(void) format_listeners(buffer, buffer_size+1);
- snprintf(header, sizeof header, "OKAY%04x", buffer_size);
- writex(reply_fd, header, 8);
- writex(reply_fd, buffer, buffer_size);
+ send_msg_with_okay(reply_fd, buffer, buffer_size);
free(buffer);
return 0;
}
@@ -1643,8 +1642,7 @@
if(!strncmp(service,"get-state",strlen("get-state"))) {
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
char *state = connection_state_name(transport);
- snprintf(buf, sizeof buf, "OKAY%04x%s",(unsigned)strlen(state),state);
- writex(reply_fd, buf, strlen(buf));
+ send_msg_with_okay(reply_fd, state, strlen(state));
return 0;
}
return -1;
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 586cd7b..1e47486 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -324,7 +324,10 @@
buf[4] = 0;
n = strtoul(buf, 0, 16);
- if(n > 1024) goto oops;
+ if(n >= 0xffff) {
+ strcpy(__adb_error, "reply is too long (>= 64kB)");
+ goto oops;
+ }
tmp = malloc(n + 1);
if(tmp == 0) goto oops;
diff --git a/adb/commandline.c b/adb/commandline.c
index c9bb437..83b568d 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -107,8 +107,12 @@
" will disconnect from all connected TCP/IP devices.\n"
"\n"
"device commands:\n"
- " adb push <local> <remote> - copy file/dir to device\n"
- " adb pull <remote> [<local>] - copy file/dir from device\n"
+ " adb push [-p] <local> <remote>\n"
+ " - copy file/dir to device\n"
+ " ('-p' to display the transfer progress)\n"
+ " adb pull [-p] <remote> [<local>]\n"
+ " - copy file/dir from device\n"
+ " ('-p' to display the transfer progress)\n"
" adb sync [ <directory> ] - copy host->device only if changed\n"
" (-l means list but don't copy)\n"
" (see 'adb help all')\n"
@@ -921,6 +925,28 @@
return path_buf;
}
+
+static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2,
+ int* show_progress) {
+ *show_progress = 0;
+
+ if ((narg > 0) && !strcmp(*arg, "-p")) {
+ *show_progress = 1;
+ ++arg;
+ --narg;
+ }
+
+ if (narg > 0) {
+ *path1 = *arg;
+ ++arg;
+ --narg;
+ }
+
+ if (narg > 0) {
+ *path2 = *arg;
+ }
+}
+
int adb_commandline(int argc, char **argv)
{
char buf[4096];
@@ -1368,18 +1394,29 @@
}
if(!strcmp(argv[0], "push")) {
- if(argc != 3) return usage();
- return do_sync_push(argv[1], argv[2], 0 /* no verify APK */);
+ int show_progress = 0;
+ const char* lpath = NULL, *rpath = NULL;
+
+ parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress);
+
+ if ((lpath != NULL) && (rpath != NULL)) {
+ return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress);
+ }
+
+ return usage();
}
if(!strcmp(argv[0], "pull")) {
- if (argc == 2) {
- return do_sync_pull(argv[1], ".");
- } else if (argc == 3) {
- return do_sync_pull(argv[1], argv[2]);
- } else {
- return usage();
+ int show_progress = 0;
+ const char* rpath = NULL, *lpath = ".";
+
+ parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress);
+
+ if (rpath != NULL) {
+ return do_sync_pull(rpath, lpath, show_progress);
}
+
+ return usage();
}
if(!strcmp(argv[0], "install")) {
@@ -1717,7 +1754,7 @@
}
}
- err = do_sync_push(apk_file, apk_dest, verify_apk);
+ err = do_sync_push(apk_file, apk_dest, verify_apk, 0 /* no show progress */);
if (err) {
goto cleanup_apk;
} else {
@@ -1725,7 +1762,8 @@
}
if (verification_file != NULL) {
- err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */);
+ err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */,
+ 0 /* no show progress */);
if (err) {
goto cleanup_apk;
} else {
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 9fec081..8fad50e 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -62,6 +62,22 @@
total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
}
+static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
+
+static void print_transfer_progress(unsigned long long bytes_current,
+ unsigned long long bytes_total) {
+ if (bytes_total == 0) return;
+
+ fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
+ (int) (bytes_current * 100 / bytes_total));
+
+ if (bytes_current == bytes_total) {
+ fputc('\n', stderr);
+ }
+
+ fflush(stderr);
+}
+
void sync_quit(int fd)
{
syncmsg msg;
@@ -207,9 +223,10 @@
return 0;
}
-static int write_data_file(int fd, const char *path, syncsendbuf *sbuf)
+static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show_progress)
{
int lfd, err = 0;
+ unsigned long long size = 0;
lfd = adb_open(path, O_RDONLY);
if(lfd < 0) {
@@ -217,6 +234,17 @@
return -1;
}
+ if (show_progress) {
+ // Determine local file size.
+ struct stat st;
+ if (lstat(path, &st)) {
+ fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ size = st.st_size;
+ }
+
sbuf->id = ID_DATA;
for(;;) {
int ret;
@@ -238,13 +266,18 @@
break;
}
total_bytes += ret;
+
+ if (show_progress) {
+ print_transfer_progress(total_bytes, size);
+ }
}
adb_close(lfd);
return err;
}
-static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf)
+static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
+ int show_progress)
{
int err = 0;
int total = 0;
@@ -264,6 +297,10 @@
}
total += count;
total_bytes += count;
+
+ if (show_progress) {
+ print_transfer_progress(total, size);
+ }
}
return err;
@@ -295,7 +332,7 @@
#endif
static int sync_send(int fd, const char *lpath, const char *rpath,
- unsigned mtime, mode_t mode, int verifyApk)
+ unsigned mtime, mode_t mode, int verifyApk, int show_progress)
{
syncmsg msg;
int len, r;
@@ -377,10 +414,10 @@
}
if (file_buffer) {
- write_data_buffer(fd, file_buffer, size, sbuf);
+ write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
free(file_buffer);
} else if (S_ISREG(mode))
- write_data_file(fd, lpath, sbuf);
+ write_data_file(fd, lpath, sbuf, show_progress);
#ifdef HAVE_SYMLINKS
else if (S_ISLNK(mode))
write_data_link(fd, lpath, sbuf);
@@ -438,17 +475,38 @@
return 0;
}
-int sync_recv(int fd, const char *rpath, const char *lpath)
+int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
{
syncmsg msg;
int len;
int lfd = -1;
char *buffer = send_buffer.data;
unsigned id;
+ unsigned long long size = 0;
len = strlen(rpath);
if(len > 1024) return -1;
+ if (show_progress) {
+ // Determine remote file size.
+ syncmsg stat_msg;
+ stat_msg.req.id = ID_STAT;
+ stat_msg.req.namelen = htoll(len);
+
+ if (writex(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
+ writex(fd, rpath, len)) {
+ return -1;
+ }
+
+ if (readx(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
+ return -1;
+ }
+
+ if (stat_msg.stat.id != ID_STAT) return -1;
+
+ size = ltohl(stat_msg.stat.size);
+ }
+
msg.req.id = ID_RECV;
msg.req.namelen = htoll(len);
if(writex(fd, &msg.req, sizeof(msg.req)) ||
@@ -502,6 +560,10 @@
}
total_bytes += len;
+
+ if (show_progress) {
+ print_transfer_progress(total_bytes, size);
+ }
}
adb_close(lfd);
@@ -721,7 +783,8 @@
if(ci->flag == 0) {
fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
if(!listonly &&
- sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */)){
+ sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */,
+ 0 /* no show progress */)) {
return 1;
}
pushed++;
@@ -739,7 +802,7 @@
}
-int do_sync_push(const char *lpath, const char *rpath, int verifyApk)
+int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress)
{
struct stat st;
unsigned mode;
@@ -786,7 +849,7 @@
rpath = tmp;
}
BEGIN();
- if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk)) {
+ if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk, show_progress)) {
return 1;
} else {
END();
@@ -923,7 +986,7 @@
next = ci->next;
if (ci->flag == 0) {
fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
- if (sync_recv(fd, ci->src, ci->dst)) {
+ if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
return 1;
}
pulled++;
@@ -940,7 +1003,7 @@
return 0;
}
-int do_sync_pull(const char *rpath, const char *lpath)
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress)
{
unsigned mode;
struct stat st;
@@ -981,7 +1044,7 @@
}
}
BEGIN();
- if(sync_recv(fd, rpath, lpath)) {
+ if (sync_recv(fd, rpath, lpath, show_progress)) {
return 1;
} else {
END();
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 577fb8f..1d80d26 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -68,7 +68,7 @@
*x = '/';
return ret;
}
- selinux_android_restorecon(name);
+ selinux_android_restorecon(name, 0);
}
*x++ = '/';
}
@@ -172,7 +172,7 @@
}
static int handle_send_file(int s, char *path, uid_t uid,
- gid_t gid, mode_t mode, char *buffer)
+ gid_t gid, mode_t mode, char *buffer, bool do_unlink)
{
syncmsg msg;
unsigned int timestamp = 0;
@@ -236,7 +236,7 @@
if(writex(fd, buffer, len)) {
int saved_errno = errno;
adb_close(fd);
- adb_unlink(path);
+ if (do_unlink) adb_unlink(path);
fd = -1;
errno = saved_errno;
if(fail_errno(s)) return -1;
@@ -246,7 +246,7 @@
if(fd >= 0) {
struct utimbuf u;
adb_close(fd);
- selinux_android_restorecon(path);
+ selinux_android_restorecon(path, 0);
u.actime = timestamp;
u.modtime = timestamp;
utime(path, &u);
@@ -261,7 +261,7 @@
fail:
if(fd >= 0)
adb_close(fd);
- adb_unlink(path);
+ if (do_unlink) adb_unlink(path);
return -1;
}
@@ -323,6 +323,7 @@
char *tmp;
unsigned int mode;
int is_link, ret;
+ bool do_unlink;
tmp = strrchr(path,',');
if(tmp) {
@@ -339,11 +340,16 @@
if(!tmp || errno) {
mode = 0644;
is_link = 0;
+ do_unlink = true;
+ } else {
+ struct stat st;
+ /* Don't delete files before copying if they are not "regular" */
+ do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+ if (do_unlink) {
+ adb_unlink(path);
+ }
}
- adb_unlink(path);
-
-
#ifdef HAVE_SYMLINKS
if(is_link)
ret = handle_send_link(s, path, buffer);
@@ -366,7 +372,7 @@
if (is_on_system(path)) {
fs_config(tmp, 0, &uid, &gid, &mode, &cap);
}
- ret = handle_send_file(s, path, uid, gid, mode, buffer);
+ ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
}
return ret;
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index e402e06..3e7e096 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -72,15 +72,15 @@
struct {
unsigned id;
unsigned msglen;
- } status;
+ } status;
} syncmsg;
void file_sync_service(int fd, void *cookie);
int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, int verifyApk);
+int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress);
int do_sync_sync(const char *lpath, const char *rpath, int listonly);
-int do_sync_pull(const char *rpath, const char *lpath);
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress);
#define SYNC_DATA_MAX (64*1024)
diff --git a/adb/transport.c b/adb/transport.c
index 6002530..f35880c 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -1188,6 +1188,10 @@
D("writex: fd=%d error %d: %s\n", fd, errno, strerror(errno));
if (errno == EINTR)
continue;
+ if (errno == EAGAIN) {
+ adb_sleep_ms(1); // just yield some cpu time
+ continue;
+ }
} else {
D("writex: fd=%d disconnected\n", fd);
}
diff --git a/adf/libadfhwc/adfhwc.cpp b/adf/libadfhwc/adfhwc.cpp
index dee3cae..57e09eb 100644
--- a/adf/libadfhwc/adfhwc.cpp
+++ b/adf/libadfhwc/adfhwc.cpp
@@ -257,7 +257,7 @@
ret = adf_set_event(dup_intf_fd, ADF_EVENT_HOTPLUG, 1);
if (ret < 0 && ret != -EINVAL) {
- ALOGE("failed to enable hotplug event on display %u: %s",
+ ALOGE("failed to enable hotplug event on display %zu: %s",
i, strerror(errno));
goto err;
}
diff --git a/charger/Android.mk b/charger/Android.mk
index b9d3473..40c7d78 100644
--- a/charger/Android.mk
+++ b/charger/Android.mk
@@ -24,7 +24,7 @@
LOCAL_C_INCLUDES := bootable/recovery
-LOCAL_STATIC_LIBRARIES := libminui libpixelflinger_static libpng
+LOCAL_STATIC_LIBRARIES := libminui libpng
ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
LOCAL_STATIC_LIBRARIES += libsuspend
endif
diff --git a/charger/charger.c b/charger/charger.c
index 66ddeaf..402d0e8 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -47,6 +47,8 @@
#include "minui/minui.h"
+char *locale;
+
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
@@ -89,7 +91,6 @@
};
struct frame {
- const char *name;
int disp_time;
int min_capacity;
bool level_only;
@@ -140,33 +141,27 @@
static struct frame batt_anim_frames[] = {
{
- .name = "charger/battery_0",
.disp_time = 750,
.min_capacity = 0,
},
{
- .name = "charger/battery_1",
.disp_time = 750,
.min_capacity = 20,
},
{
- .name = "charger/battery_2",
.disp_time = 750,
.min_capacity = 40,
},
{
- .name = "charger/battery_3",
.disp_time = 750,
.min_capacity = 60,
},
{
- .name = "charger/battery_4",
.disp_time = 750,
.min_capacity = 80,
.level_only = true,
},
{
- .name = "charger/battery_5",
.disp_time = 750,
.min_capacity = BATTERY_FULL_THRESH,
},
@@ -196,8 +191,8 @@
static void clear_screen(void)
{
gr_color(0, 0, 0, 255);
- gr_fill(0, 0, gr_fb_width(), gr_fb_height());
-};
+ gr_clear();
+}
#define MAX_KLOG_WRITE_BUF_SZ 256
@@ -657,8 +652,8 @@
if (batt_anim->num_frames != 0) {
draw_surface_centered(charger, frame->surface);
- LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n",
- batt_anim->cur_frame, frame->name, frame->min_capacity,
+ LOGV("drawing frame #%d min_cap=%d time=%d\n",
+ batt_anim->cur_frame, frame->min_capacity,
frame->disp_time);
}
}
@@ -980,20 +975,27 @@
ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < 0) {
- LOGE("Cannot load image\n");
+ LOGE("Cannot load battery_fail image\n");
charger->surf_unknown = NULL;
}
- for (i = 0; i < charger->batt_anim->num_frames; i++) {
- struct frame *frame = &charger->batt_anim->frames[i];
+ charger->batt_anim = &battery_animation;
- ret = res_create_surface(frame->name, &frame->surface);
- if (ret < 0) {
- LOGE("Cannot load image %s\n", frame->name);
- /* TODO: free the already allocated surfaces... */
- charger->batt_anim->num_frames = 0;
- charger->batt_anim->num_cycles = 1;
- break;
+ gr_surface* scale_frames;
+ int scale_count;
+ ret = res_create_multi_surface("charger/battery_scale", &scale_count, &scale_frames);
+ if (ret < 0) {
+ LOGE("Cannot load battery_scale image\n");
+ charger->batt_anim->num_frames = 0;
+ charger->batt_anim->num_cycles = 1;
+ } else if (scale_count != charger->batt_anim->num_frames) {
+ LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
+ scale_count, charger->batt_anim->num_frames);
+ charger->batt_anim->num_frames = 0;
+ charger->batt_anim->num_cycles = 1;
+ } else {
+ for (i = 0; i < charger->batt_anim->num_frames; i++) {
+ charger->batt_anim->frames[i].surface = scale_frames[i];
}
}
diff --git a/charger/images/battery_0.png b/charger/images/battery_0.png
deleted file mode 100644
index 2347074..0000000
--- a/charger/images/battery_0.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_1.png b/charger/images/battery_1.png
deleted file mode 100644
index cd34620..0000000
--- a/charger/images/battery_1.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_2.png b/charger/images/battery_2.png
deleted file mode 100644
index 3e4095e..0000000
--- a/charger/images/battery_2.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_3.png b/charger/images/battery_3.png
deleted file mode 100644
index 08c1551..0000000
--- a/charger/images/battery_3.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_4.png b/charger/images/battery_4.png
deleted file mode 100644
index 3a678da..0000000
--- a/charger/images/battery_4.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_5.png b/charger/images/battery_5.png
deleted file mode 100644
index d8dc40e..0000000
--- a/charger/images/battery_5.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_charge.png b/charger/images/battery_charge.png
deleted file mode 100644
index b501933..0000000
--- a/charger/images/battery_charge.png
+++ /dev/null
Binary files differ
diff --git a/charger/images/battery_fail.png b/charger/images/battery_fail.png
index 36fc254..aded88a 100644
--- a/charger/images/battery_fail.png
+++ b/charger/images/battery_fail.png
Binary files differ
diff --git a/charger/images/battery_scale.png b/charger/images/battery_scale.png
new file mode 100644
index 0000000..2ae8f0f
--- /dev/null
+++ b/charger/images/battery_scale.png
Binary files differ
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 422a86a..77fcbe0 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,55 +1,12 @@
-# Copyright 2005 The Android Open Source Project
-
-ifneq ($(filter arm mips x86,$(TARGET_ARCH)),)
-
LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- backtrace.cpp \
- debuggerd.cpp \
- getevent.cpp \
- tombstone.cpp \
- utility.cpp \
- $(TARGET_ARCH)/machine.cpp \
+debuggerd_2nd_arch_var_prefix :=
+include $(LOCAL_PATH)/debuggerd.mk
-LOCAL_CONLYFLAGS := -std=gnu99
-LOCAL_CPPFLAGS := -std=gnu++11
-LOCAL_CFLAGS := \
- -Wall \
- -Wno-array-bounds \
- -Werror \
-
-LOCAL_MODULE := debuggerd
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_CFLAGS += -DWITH_VFP
-endif # ARCH_ARM_HAVE_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
-
-LOCAL_SHARED_LIBRARIES := \
- libbacktrace \
- libc \
- libcutils \
- liblog \
- libselinux \
-
-include external/stlport/libstlport.mk
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.c
-LOCAL_SRC_FILES += $(TARGET_ARCH)/crashglue.S
-LOCAL_MODULE := crasher
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Wno-unused-parameter -Wno-free-nonheap-object
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-include $(BUILD_EXECUTABLE)
+ifdef TARGET_2ND_ARCH
+debuggerd_2nd_arch_var_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX)
+include $(LOCAL_PATH)/debuggerd.mk
+endif
ifeq ($(ARCH_ARM_HAVE_VFP),true)
include $(CLEAR_VARS)
@@ -59,12 +16,20 @@
LOCAL_CFLAGS += -DWITH_VFP_D32
endif # ARCH_ARM_HAVE_VFP_D32
-LOCAL_SRC_FILES := vfp-crasher.c vfp.S
+LOCAL_SRC_FILES := vfp-crasher.c arm/vfp.S
LOCAL_MODULE := vfp-crasher
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_MODULE_TARGET_ARCH := arm
include $(BUILD_EXECUTABLE)
endif # ARCH_ARM_HAVE_VFP == true
-endif # arm or x86 in TARGET_ARCH
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := vfp-crasher.c arm64/vfp.S
+LOCAL_MODULE := vfp-crasher64
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_MODULE_TARGET_ARCH := arm64
+include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 3fba6db..fd2f69b 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -38,65 +38,6 @@
#endif
#endif
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
- char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45
- char ascii_buffer[32]; // actual 16 + 1 == 17
- uintptr_t p, end;
-
- p = addr & ~3;
- p -= 32;
- if (p > addr) {
- // catch underflow
- p = 0;
- }
- // Dump more memory content for the crashing thread.
- end = p + 256;
- // catch overflow; 'end - p' has to be multiples of 16
- while (end < p)
- end -= 16;
-
- // Dump the code around PC as:
- // addr contents ascii
- // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q
- // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p......
- while (p < end) {
- char* asc_out = ascii_buffer;
-
- sprintf(code_buffer, "%08x ", p);
-
- int i;
- for (i = 0; i < 4; i++) {
- // If we see (data == -1 && errno != 0), we know that the ptrace
- // call failed, probably because we're dumping memory in an
- // unmapped or inaccessible page. I don't know if there's
- // value in making that explicit in the output -- it likely
- // just complicates parsing and clarifies nothing for the
- // enlightened reader.
- long data = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(p), NULL);
- sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
- // Enable the following code blob to dump ASCII values
-#if 0
- int j;
- for (j = 0; j < 4; j++) {
- // Our isprint() allows high-ASCII characters that display
- // differently (often badly) in different viewers, so we
- // just use a simpler test.
- char val = (data >> (j*8)) & 0xff;
- if (val >= 0x20 && val < 0x7f) {
- *asc_out++ = val;
- } else {
- *asc_out++ = '.';
- }
- }
-#endif
- p += 4;
- }
- *asc_out = '\0';
- _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
- }
-}
-
// If configured to do so, dump memory around *all* registers
// for the crashing thread.
void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
diff --git a/debuggerd/vfp.S b/debuggerd/arm/vfp.S
similarity index 100%
rename from debuggerd/vfp.S
rename to debuggerd/arm/vfp.S
diff --git a/debuggerd/arm64/crashglue.S b/debuggerd/arm64/crashglue.S
new file mode 100644
index 0000000..b06b67c
--- /dev/null
+++ b/debuggerd/arm64/crashglue.S
@@ -0,0 +1,47 @@
+.globl crash1
+.type crash1, %function
+.globl crashnostack
+.type crashnostack, %function
+
+crash1:
+ ldr x0, =0xa5a50000
+ ldr x1, =0xa5a50001
+ ldr x2, =0xa5a50002
+ ldr x3, =0xa5a50003
+ ldr x4, =0xa5a50004
+ ldr x5, =0xa5a50005
+ ldr x6, =0xa5a50006
+ ldr x7, =0xa5a50007
+ ldr x8, =0xa5a50008
+ ldr x9, =0xa5a50009
+ ldr x10, =0xa5a50010
+ ldr x11, =0xa5a50011
+ ldr x12, =0xa5a50012
+ ldr x13, =0xa5a50013
+ ldr x14, =0xa5a50014
+ ldr x15, =0xa5a50015
+ ldr x16, =0xa5a50016
+ ldr x17, =0xa5a50017
+ ldr x18, =0xa5a50018
+ ldr x19, =0xa5a50019
+ ldr x20, =0xa5a50020
+ ldr x21, =0xa5a50021
+ ldr x22, =0xa5a50022
+ ldr x23, =0xa5a50023
+ ldr x24, =0xa5a50024
+ ldr x25, =0xa5a50025
+ ldr x26, =0xa5a50026
+ ldr x27, =0xa5a50027
+ ldr x28, =0xa5a50028
+ ldr x29, =0xa5a50029
+
+ mov x30, xzr
+ ldr x30, [x30]
+ b .
+
+
+crashnostack:
+ mov x0, xzr
+ add sp, x0, xzr
+ ldr x0, [x0]
+ b .
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
new file mode 100644
index 0000000..7159228
--- /dev/null
+++ b/debuggerd/arm64/machine.cpp
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/user.h>
+#include <sys/uio.h>
+#include <linux/elf.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+/* enable to dump memory pointed to by every register */
+#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
+
+/*
+ * If configured to do so, dump memory around *all* registers
+ * for the crashing thread.
+ */
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+ struct user_pt_regs regs;
+ struct iovec io;
+ io.iov_base = ®s;
+ io.iov_len = sizeof(regs);
+
+ if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
+ _LOG(log, scope_flags, "%s: ptrace failed to get registers: %s\n",
+ __func__, strerror(errno));
+ return;
+ }
+
+ if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
+ for (int reg = 0; reg < 31; reg++) {
+ uintptr_t addr = regs.regs[reg];
+
+ /*
+ * Don't bother if it looks like a small int or ~= null, or if
+ * it's in the kernel area.
+ */
+ if (addr < 4096 || addr >= (1UL<<63)) {
+ continue;
+ }
+
+ _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near x%d:\n", reg);
+ dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ }
+ }
+
+ _LOG(log, scope_flags, "\ncode around pc:\n");
+ dump_memory(log, tid, (uintptr_t)regs.pc, scope_flags);
+
+ if (regs.pc != regs.sp) {
+ _LOG(log, scope_flags, "\ncode around sp:\n");
+ dump_memory(log, tid, (uintptr_t)regs.sp, scope_flags);
+ }
+}
+
+void dump_registers(log_t* log, pid_t tid, int scope_flags)
+{
+ struct user_pt_regs r;
+ struct iovec io;
+ io.iov_base = &r;
+ io.iov_len = sizeof(r);
+
+ bool only_in_tombstone = !IS_AT_FAULT(scope_flags);
+
+ if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
+ _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+ return;
+ }
+
+ for (int i = 0; i < 28; i += 4) {
+ _LOG(log, scope_flags, " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n",
+ i, (uint64_t)r.regs[i],
+ i+1, (uint64_t)r.regs[i+1],
+ i+2, (uint64_t)r.regs[i+2],
+ i+3, (uint64_t)r.regs[i+3]);
+ }
+
+ _LOG(log, scope_flags, " x28 %016lx x29 %016lx x30 %016lx\n",
+ (uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]);
+
+ _LOG(log, scope_flags, " sp %016lx pc %016lx\n",
+ (uint64_t)r.sp, (uint64_t)r.pc);
+
+
+ struct user_fpsimd_state f;
+ io.iov_base = &f;
+ io.iov_len = sizeof(f);
+
+ if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
+ _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+ return;
+ }
+
+ for (int i = 0; i < 32; i += 4) {
+ _LOG(log, scope_flags, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n",
+ i, (uint64_t)f.vregs[i],
+ i+1, (uint64_t)f.vregs[i+1],
+ i+2, (uint64_t)f.vregs[i+2],
+ i+3, (uint64_t)f.vregs[i+3]);
+ }
+}
diff --git a/debuggerd/arm64/vfp.S b/debuggerd/arm64/vfp.S
new file mode 100644
index 0000000..bf12c22
--- /dev/null
+++ b/debuggerd/arm64/vfp.S
@@ -0,0 +1,42 @@
+ .text
+ .align 2
+ .global crash
+ .type crash, %function
+crash:
+ fmov d0, XZR
+ fmov d1, 1.0
+ fmov d2, 2.0
+ fmov d3, 3.0
+ fmov d4, 4.0
+ fmov d5, 5.0
+ fmov d6, 6.0
+ fmov d7, 7.0
+ fmov d8, 8.0
+ fmov d9, 9.0
+ fmov d10, 10.0
+ fmov d11, 11.0
+ fmov d12, 12.0
+ fmov d13, 13.0
+ fmov d14, 14.0
+ fmov d15, 15.0
+ fmov d16, 16.0
+ fmov d17, 17.0
+ fmov d18, 18.0
+ fmov d19, 19.0
+ fmov d20, 20.0
+ fmov d21, 21.0
+ fmov d22, 22.0
+ fmov d23, 23.0
+ fmov d24, 24.0
+ fmov d25, 25.0
+ fmov d26, 26.0
+ fmov d27, 27.0
+ fmov d28, 28.0
+ fmov d29, 29.0
+ fmov d30, 30.0
+ fmov d31, 31.0
+
+ mov x0, xzr
+ str x0, [x0]
+ br x30
+
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 5ecb1a5..5a2bc3c 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -23,19 +23,6 @@
void crashnostack(void);
static int do_action(const char* arg);
-static void debuggerd_connect()
-{
- char tmp[1];
- int s;
- sprintf(tmp, "%d", gettid());
- s = socket_local_client("android:debuggerd",
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- if(s >= 0) {
- read(s, tmp, 1);
- close(s);
- }
-}
-
static void maybeabort() {
if(time(0) != 42) {
abort();
@@ -70,13 +57,13 @@
static void *noisy(void *x)
{
- char c = (unsigned) x;
+ char c = (uintptr_t) x;
for(;;) {
usleep(250*1000);
write(2, &c, 1);
if(c == 'C') *((unsigned*) 0) = 42;
}
- return 0;
+ return NULL;
}
static int ctest()
@@ -94,7 +81,7 @@
static void* thread_callback(void* raw_arg)
{
- return (void*) do_action((const char*) raw_arg);
+ return (void*) (uintptr_t) do_action((const char*) raw_arg);
}
static int do_action_on_thread(const char* arg)
@@ -103,7 +90,7 @@
pthread_create(&t, NULL, thread_callback, (void*) arg);
void* result = NULL;
pthread_join(t, &result);
- return (int) result;
+ return (int) (uintptr_t) result;
}
__attribute__((noinline)) static int crash3(int a) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index de8ba9d..a2b164e 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -46,12 +46,12 @@
#include "tombstone.h"
#include "utility.h"
-typedef struct {
+struct debugger_request_t {
debugger_action_t action;
pid_t pid, tid;
uid_t uid, gid;
uintptr_t abort_msg_address;
-} debugger_request_t;
+};
static int write_string(const char* file, const char* string) {
int len;
@@ -116,7 +116,7 @@
dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
};
size_t s = 0;
- struct input_event e;
+ input_event e;
bool done = false;
init_debug_led();
enable_debug_led();
@@ -176,8 +176,8 @@
}
static int read_request(int fd, debugger_request_t* out_request) {
- struct ucred cr;
- int len = sizeof(cr);
+ ucred cr;
+ socklen_t len = sizeof(cr);
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (status != 0) {
LOG("cannot get credentials\n");
@@ -187,7 +187,7 @@
XLOG("reading tid\n");
fcntl(fd, F_SETFL, O_NONBLOCK);
- struct pollfd pollfds[1];
+ pollfd pollfds[1];
pollfds[0].fd = fd;
pollfds[0].events = POLLIN;
pollfds[0].revents = 0;
@@ -205,7 +205,8 @@
return -1;
}
if (status == sizeof(debugger_msg_t)) {
- XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address);
+ XLOG("crash request of size %d abort_msg_address=0x%" PRIPTR "\n",
+ status, msg.abort_msg_address);
} else {
LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
return -1;
@@ -440,13 +441,11 @@
LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
for (;;) {
- struct sockaddr addr;
- socklen_t alen;
- int fd;
+ sockaddr addr;
+ socklen_t alen = sizeof(addr);
- alen = sizeof(addr);
XLOG("waiting for connection\n");
- fd = accept(s, &addr, &alen);
+ int fd = accept(s, &addr, &alen);
if (fd < 0) {
XLOG("accept failed: %s\n", strerror(errno));
continue;
diff --git a/debuggerd/debuggerd.mk b/debuggerd/debuggerd.mk
new file mode 100644
index 0000000..a3982c1
--- /dev/null
+++ b/debuggerd/debuggerd.mk
@@ -0,0 +1,75 @@
+# Copyright 2005 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ backtrace.cpp \
+ debuggerd.cpp \
+ getevent.cpp \
+ tombstone.cpp \
+ utility.cpp \
+
+LOCAL_SRC_FILES_arm := arm/machine.cpp
+LOCAL_SRC_FILES_arm64 := arm64/machine.cpp
+LOCAL_SRC_FILES_mips := mips/machine.cpp
+LOCAL_SRC_FILES_x86 := x86/machine.cpp
+LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
+
+LOCAL_CONLYFLAGS := -std=gnu99
+LOCAL_CPPFLAGS := -std=gnu++11
+LOCAL_CFLAGS := \
+ -Wall \
+ -Wno-array-bounds \
+ -Werror \
+ -Wno-unused-parameter \
+
+ifeq ($(ARCH_ARM_HAVE_VFP),true)
+LOCAL_CFLAGS_arm += -DWITH_VFP
+endif # ARCH_ARM_HAVE_VFP
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_CFLAGS_arm += -DWITH_VFP_D32
+endif # ARCH_ARM_HAVE_VFP_D32
+
+LOCAL_SHARED_LIBRARIES := \
+ libbacktrace \
+ libc \
+ libcutils \
+ liblog \
+ libselinux \
+
+include external/stlport/libstlport.mk
+
+ifeq ($(TARGET_IS_64_BIT)|$(debuggerd_2nd_arch_var_prefix),true|)
+LOCAL_MODULE := debuggerd64
+LOCAL_NO_2ND_ARCH := true
+else
+LOCAL_MODULE := debuggerd
+LOCAL_32_BIT_ONLY := true
+endif
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := crasher.c
+LOCAL_SRC_FILES_arm := arm/crashglue.S
+LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
+LOCAL_SRC_FILES_mips := mips/crashglue.S
+LOCAL_SRC_FILES_x86 := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS += -fstack-protector-all -Wno-unused-parameter -Wno-free-nonheap-object
+#LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+
+LOCAL_2ND_ARCH_VAR_PREFIX := $(debuggerd_2nd_arch_var_prefix)
+
+ifeq ($(TARGET_IS_64_BIT)|$(debuggerd_2nd_arch_var_prefix),true|)
+LOCAL_MODULE := crasher64
+LOCAL_NO_2ND_ARCH := true
+else
+LOCAL_MODULE := crasher
+LOCAL_32_BIT_ONLY := true
+endif
+include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index d1a7f2d..7b4e29e 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -34,61 +34,6 @@
#define R(x) (static_cast<unsigned int>(x))
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
- char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45
- char ascii_buffer[32]; // actual 16 + 1 == 17
- uintptr_t p, end;
-
- p = addr & ~3;
- p -= 32;
- if (p > addr) {
- // catch underflow
- p = 0;
- }
- end = p + 80;
- // catch overflow; 'end - p' has to be multiples of 16
- while (end < p)
- end -= 16;
-
- // Dump the code around PC as:
- // addr contents ascii
- // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q
- // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p......
- while (p < end) {
- char* asc_out = ascii_buffer;
-
- sprintf(code_buffer, "%08x ", p);
-
- int i;
- for (i = 0; i < 4; i++) {
- // If we see (data == -1 && errno != 0), we know that the ptrace
- // call failed, probably because we're dumping memory in an
- // unmapped or inaccessible page. I don't know if there's
- // value in making that explicit in the output -- it likely
- // just complicates parsing and clarifies nothing for the
- // enlightened reader.
- long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
- sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
- int j;
- for (j = 0; j < 4; j++) {
- // Our isprint() allows high-ASCII characters that display
- // differently (often badly) in different viewers, so we
- // just use a simpler test.
- char val = (data >> (j*8)) & 0xff;
- if (val >= 0x20 && val < 0x7f) {
- *asc_out++ = val;
- } else {
- *asc_out++ = '.';
- }
- }
- p += 4;
- }
- *asc_out = '\0';
- _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
- }
-}
-
// If configured to do so, dump memory around *all* registers
// for the crashing thread.
void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
old mode 100644
new mode 100755
index 11e9af5..6a1b963
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -14,18 +14,20 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <time.h>
#include <sys/ptrace.h>
+#include <sys/socket.h>
#include <sys/stat.h>
-#include <inttypes.h>
+#include <sys/un.h>
#include <private/android_filesystem_config.h>
@@ -36,9 +38,6 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
-#include <sys/socket.h>
-#include <linux/un.h>
-
#include <selinux/android.h>
#include <UniquePtr.h>
@@ -51,16 +50,11 @@
#define MAX_TOMBSTONES 10
#define TOMBSTONE_DIR "/data/tombstones"
+#define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
// Must match the path defined in NativeCrashListener.java
#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
-#define typecheck(x,y) { \
- typeof(x) __dummy1; \
- typeof(y) __dummy2; \
- (void)(&__dummy1 == &__dummy2); }
-
-
static bool signal_has_address(int sig) {
switch (sig) {
case SIGILL:
@@ -180,9 +174,9 @@
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
_LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
} else if (signal_has_address(sig)) {
- _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %0*" PRIxPTR "\n",
+ _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %" PRIPTR "\n",
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code),
- sizeof(uintptr_t)*2, reinterpret_cast<uintptr_t>(si.si_addr));
+ reinterpret_cast<uintptr_t>(si.si_addr));
} else {
_LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
@@ -227,7 +221,7 @@
static void dump_stack_segment(
Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
for (size_t i = 0; i < words; i++) {
- uint32_t stack_content;
+ word_t stack_content;
if (!backtrace->ReadWord(*sp, &stack_content)) {
break;
}
@@ -244,32 +238,32 @@
if (!func_name.empty()) {
if (!i && label >= 0) {
if (offset) {
- _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n",
+ _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
label, *sp, stack_content, map_name, func_name.c_str(), offset);
} else {
- _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n",
+ _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
label, *sp, stack_content, map_name, func_name.c_str());
}
} else {
if (offset) {
- _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n",
+ _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
*sp, stack_content, map_name, func_name.c_str(), offset);
} else {
- _LOG(log, scope_flags, " %08x %08x %s (%s)\n",
+ _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s)\n",
*sp, stack_content, map_name, func_name.c_str());
}
}
} else {
if (!i && label >= 0) {
- _LOG(log, scope_flags, " #%02d %08x %08x %s\n",
+ _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
label, *sp, stack_content, map_name);
} else {
- _LOG(log, scope_flags, " %08x %08x %s\n",
+ _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s\n",
*sp, stack_content, map_name);
}
}
- *sp += sizeof(uint32_t);
+ *sp += sizeof(word_t);
}
}
@@ -292,7 +286,7 @@
scope_flags |= SCOPE_SENSITIVE;
// Dump a few words before the first frame.
- uintptr_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(uint32_t);
+ word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
// Dump a few words from all successive frames.
@@ -312,7 +306,7 @@
_LOG(log, scope_flags, " ........ ........\n");
}
} else {
- size_t words = frame->stack_size / sizeof(uint32_t);
+ size_t words = frame->stack_size / sizeof(word_t);
if (words == 0) {
words = 1;
} else if (words > STACK_WORDS) {
@@ -335,7 +329,7 @@
static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
if (map != NULL) {
- _LOG(log, scope_flags, " %08x-%08x %c%c%c %s\n", map->start, map->end,
+ _LOG(log, scope_flags, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end,
(map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
(map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
} else {
@@ -361,7 +355,7 @@
return;
}
- _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIxPTR ":\n",
+ _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIPTR ":\n",
reinterpret_cast<uintptr_t>(si.si_addr));
// Search for a match, or for a hole where the match would be. The list
@@ -574,24 +568,15 @@
memset(msg, 0, sizeof(msg));
char* p = &msg[0];
while (p < &msg[sizeof(msg)]) {
- uint32_t data;
+ word_t data;
+ size_t len = sizeof(word_t);
if (!backtrace->ReadWord(address, &data)) {
break;
}
- address += sizeof(uint32_t);
+ address += sizeof(word_t);
- if ((*p++ = (data >> 0) & 0xff) == 0) {
- break;
- }
- if ((*p++ = (data >> 8) & 0xff) == 0) {
- break;
- }
- if ((*p++ = (data >> 16) & 0xff) == 0) {
- break;
- }
- if ((*p++ = (data >> 24) & 0xff) == 0) {
- break;
- }
+ while (len > 0 && (*p++ = (data >> (sizeof(word_t) - len) * 8) & 0xff) != 0)
+ len--;
}
msg[sizeof(msg) - 1] = '\0';
@@ -663,24 +648,19 @@
//
// Returns the path of the tombstone file, allocated using malloc(). Caller must free() it.
static char* find_and_open_tombstone(int* fd) {
- unsigned long mtime = ULONG_MAX;
- struct stat sb;
-
- // XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
- // to, our logic breaks. This check will generate a warning if that happens.
- typecheck(mtime, sb.st_mtime);
-
- // In a single wolf-like pass, find an available slot and, in case none
+ // In a single pass, find an available slot and, in case none
// exist, find and record the least-recently-modified file.
char path[128];
- int oldest = 0;
+ int oldest = -1;
+ struct stat oldest_sb;
for (int i = 0; i < MAX_TOMBSTONES; i++) {
- snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
+ snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i);
+ struct stat sb;
if (!stat(path, &sb)) {
- if (sb.st_mtime < mtime) {
+ if (oldest < 0 || sb.st_mtime < oldest_sb.st_mtime) {
oldest = i;
- mtime = sb.st_mtime;
+ oldest_sb.st_mtime = sb.st_mtime;
}
continue;
}
@@ -695,8 +675,13 @@
return strdup(path);
}
+ if (oldest < 0) {
+ LOG("Failed to find a valid tombstone, default to using tombstone 0.\n");
+ oldest = 0;
+ }
+
// we didn't find an available file, so we clobber the oldest one
- snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
+ snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
*fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (*fd < 0) {
LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
@@ -739,10 +724,15 @@
char* engrave_tombstone(
pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address, bool dump_sibling_threads,
bool quiet, bool* detach_failed, int* total_sleep_time_usec) {
- mkdir(TOMBSTONE_DIR, 0755);
- chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
+ if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
+ LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+ }
- if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) {
+ if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
+ LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+ }
+
+ if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == -1) {
*detach_failed = false;
return NULL;
}
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 35f061e..9b20914 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -14,19 +14,17 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
+#include "utility.h"
+
#include <errno.h>
-#include <unistd.h>
#include <signal.h>
-#include <log/logd.h>
+#include <string.h>
+#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
-#include <arpa/inet.h>
-#include <assert.h>
-#include "utility.h"
+#include <backtrace/Backtrace.h>
+#include <log/logd.h>
const int sleep_time_usec = 50000; // 0.05 seconds
const int max_total_sleep_usec = 10000000; // 10 seconds
@@ -34,7 +32,7 @@
static int write_to_am(int fd, const char* buf, int len) {
int to_write = len;
while (to_write > 0) {
- int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
+ int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
if (written < 0) {
// hard failure
LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
@@ -46,34 +44,28 @@
}
void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
- char buf[512];
- bool want_tfd_write;
- bool want_log_write;
- bool want_amfd_write;
- int len = 0;
+ bool want_tfd_write = log && log->tfd >= 0;
+ bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
+ bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
+ char buf[512];
va_list ap;
va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
- // where is the information going to go?
- want_tfd_write = log && log->tfd >= 0;
- want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
- want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
-
- // if we're going to need the literal string, generate it once here
- if (want_tfd_write || want_amfd_write) {
- vsnprintf(buf, sizeof(buf), fmt, ap);
- len = strlen(buf);
+ size_t len = strlen(buf);
+ if (len <= 0) {
+ return;
}
if (want_tfd_write) {
- write(log->tfd, buf, len);
+ TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
}
if (want_log_write) {
- // whatever goes to logcat also goes to the Activity Manager
- __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
- if (want_amfd_write && len > 0) {
+ __android_log_write(ANDROID_LOG_INFO, "DEBUG", buf);
+ if (want_amfd_write) {
int written = write_to_am(log->amfd, buf, len);
if (written <= 0) {
// timeout or other failure on write; stop informing the activity manager
@@ -81,7 +73,6 @@
}
}
}
- va_end(ap);
}
int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
@@ -127,3 +118,77 @@
*total_sleep_time_usec += sleep_time_usec;
}
}
+
+#if defined (__mips__)
+#define DUMP_MEMORY_AS_ASCII 1
+#else
+#define DUMP_MEMORY_AS_ASCII 0
+#endif
+
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
+ char code_buffer[64];
+ char ascii_buffer[32];
+ uintptr_t p, end;
+
+ p = addr & ~(sizeof(long) - 1);
+ /* Dump 32 bytes before addr */
+ p -= 32;
+ if (p > addr) {
+ /* catch underflow */
+ p = 0;
+ }
+ /* Dump 256 bytes */
+ end = p + 256;
+ /* catch overflow; 'end - p' has to be multiples of 16 */
+ while (end < p) {
+ end -= 16;
+ }
+
+ /* Dump the code around PC as:
+ * addr contents ascii
+ * 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
+ * 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
+ * On 32-bit machines, there are still 16 bytes per line but addresses and
+ * words are of course presented differently.
+ */
+ while (p < end) {
+ char* asc_out = ascii_buffer;
+
+ int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
+
+ for (size_t i = 0; i < 16/sizeof(long); i++) {
+ long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
+ if (data == -1 && errno != 0) {
+ // ptrace failed, probably because we're dumping memory in an
+ // unmapped or inaccessible page.
+#ifdef __LP64__
+ len += sprintf(code_buffer + len, "---------------- ");
+#else
+ len += sprintf(code_buffer + len, "-------- ");
+#endif
+ } else {
+ len += sprintf(code_buffer + len, "%" PRIPTR " ",
+ static_cast<uintptr_t>(data));
+ }
+
+#if DUMP_MEMORY_AS_ASCII
+ for (size_t j = 0; j < sizeof(long); j++) {
+ /*
+ * Our isprint() allows high-ASCII characters that display
+ * differently (often badly) in different viewers, so we
+ * just use a simpler test.
+ */
+ char val = (data >> (j*8)) & 0xff;
+ if (val >= 0x20 && val < 0x7f) {
+ *asc_out++ = val;
+ } else {
+ *asc_out++ = '.';
+ }
+ }
+#endif
+ p += sizeof(long);
+ }
+ *asc_out = '\0';
+ _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
+ }
+}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 1f006ed..0f88605 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -18,8 +18,8 @@
#ifndef _DEBUGGERD_UTILITY_H
#define _DEBUGGERD_UTILITY_H
-#include <stddef.h>
#include <stdbool.h>
+#include <sys/types.h>
typedef struct {
/* tombstone file descriptor */
@@ -63,4 +63,6 @@
int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags);
+
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/x86_64/crashglue.S b/debuggerd/x86_64/crashglue.S
new file mode 100644
index 0000000..4d2a5c0
--- /dev/null
+++ b/debuggerd/x86_64/crashglue.S
@@ -0,0 +1,15 @@
+.globl crash1
+.globl crashnostack
+
+crash1:
+ movl $0xa5a50000, %eax
+ movl $0xa5a50001, %ebx
+ movl $0xa5a50002, %ecx
+
+ movl $0, %edx
+ jmp *%rdx
+
+
+crashnostack:
+ movl $0, %ebp
+ jmp *%rbp
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
new file mode 100755
index 0000000..406851a
--- /dev/null
+++ b/debuggerd/x86_64/machine.cpp
@@ -0,0 +1,51 @@
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/user.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+}
+
+void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+ struct user_regs_struct r;
+ if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+ _LOG(log, scope_flags, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
+ r.rax, r.rbx, r.rcx, r.rdx);
+ _LOG(log, scope_flags, " rsi %016lx rdi %016lx\n",
+ r.rsi, r.rdi);
+ _LOG(log, scope_flags, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
+ r.r8, r.r9, r.r10, r.r11);
+ _LOG(log, scope_flags, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
+ r.r12, r.r13, r.r14, r.r15);
+ _LOG(log, scope_flags, " cs %016lx ss %016lx\n",
+ r.cs, r.ss);
+ _LOG(log, scope_flags, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
+ r.rip, r.rbp, r.rsp, r.eflags);
+}
diff --git a/fastbootd/commands.c b/fastbootd/commands.c
index 063e1a6..98b7866 100644
--- a/fastbootd/commands.c
+++ b/fastbootd/commands.c
@@ -124,9 +124,9 @@
goto error;
}
- kernel_ptr = (void *)((unsigned) ptr + hdr->page_size);
- ramdisk_ptr = (void *)((unsigned) kernel_ptr + kernel_actual);
- second_ptr = (void *)((unsigned) ramdisk_ptr + ramdisk_actual);
+ kernel_ptr = (void *)((uintptr_t) ptr + hdr->page_size);
+ ramdisk_ptr = (void *)((uintptr_t) kernel_ptr + kernel_actual);
+ second_ptr = (void *)((uintptr_t) ramdisk_ptr + ramdisk_actual);
D(INFO, "preparing to boot");
// Prepares boot physical address. Addresses from header are ignored
diff --git a/fastbootd/commands/boot.c b/fastbootd/commands/boot.c
index 8da9a28..922914b 100644
--- a/fastbootd/commands/boot.c
+++ b/fastbootd/commands/boot.c
@@ -89,10 +89,10 @@
* Kernel address is not set into kernel_phys
* Ramdisk is set to position relative to kernel
*/
-int prepare_boot_linux(unsigned kernel_phys, void *kernel_addr, int kernel_size,
- unsigned ramdisk_phys, void *ramdisk_addr, int ramdisk_size,
- unsigned second_phys, void *second_addr, int second_size,
- unsigned atags_phys, void *atags_addr, int atags_size) {
+int prepare_boot_linux(uintptr_t kernel_phys, void *kernel_addr, int kernel_size,
+ uintptr_t ramdisk_phys, void *ramdisk_addr, int ramdisk_size,
+ uintptr_t second_phys, void *second_addr, int second_size,
+ uintptr_t atags_phys, void *atags_addr, int atags_size) {
struct kexec_segment segment[4];
int segment_count = 2;
unsigned entry = START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET;
diff --git a/fastbootd/commands/boot.h b/fastbootd/commands/boot.h
index 901c38a..a5efd01 100644
--- a/fastbootd/commands/boot.h
+++ b/fastbootd/commands/boot.h
@@ -40,8 +40,8 @@
#define KEXEC_TYPE_DEFAULT 0
#define KEXEC_TYPE_CRASH 1
-int prepare_boot_linux(unsigned, void *, int, unsigned, void *, int,
- unsigned, void *, int, unsigned, void *, int);
+int prepare_boot_linux(uintptr_t, void *, int, uintptr_t, void *, int,
+ uintptr_t, void *, int, uintptr_t, void *, int);
unsigned *create_atags(unsigned *, int, const struct boot_img_hdr *, int *);
long kexec_load(unsigned int, unsigned long, struct kexec_segment *, unsigned long);
char *read_atags(const char *, int *);
diff --git a/fastbootd/protocol.c b/fastbootd/protocol.c
index 0086b4a..3908020 100644
--- a/fastbootd/protocol.c
+++ b/fastbootd/protocol.c
@@ -142,7 +142,7 @@
char response[64];
ssize_t ret;
- snprintf(response, 64, "DATA%08x", len);
+ snprintf(response, 64, "DATA%08zx", len);
ret = protocol_handle_write(phandle, response, strlen(response));
if (ret < 0)
return;
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 790598a..165ebd4 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -3,7 +3,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c
+LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 24ce806..dcda005 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -54,55 +54,6 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
-struct flag_list {
- const char *name;
- unsigned flag;
-};
-
-static struct flag_list mount_flags[] = {
- { "noatime", MS_NOATIME },
- { "noexec", MS_NOEXEC },
- { "nosuid", MS_NOSUID },
- { "nodev", MS_NODEV },
- { "nodiratime", MS_NODIRATIME },
- { "ro", MS_RDONLY },
- { "rw", 0 },
- { "remount", MS_REMOUNT },
- { "bind", MS_BIND },
- { "rec", MS_REC },
- { "unbindable", MS_UNBINDABLE },
- { "private", MS_PRIVATE },
- { "slave", MS_SLAVE },
- { "shared", MS_SHARED },
- { "defaults", 0 },
- { 0, 0 },
-};
-
-static struct flag_list fs_mgr_flags[] = {
- { "wait", MF_WAIT },
- { "check", MF_CHECK },
- { "encryptable=",MF_CRYPT },
- { "nonremovable",MF_NONREMOVABLE },
- { "voldmanaged=",MF_VOLDMANAGED},
- { "length=", MF_LENGTH },
- { "recoveryonly",MF_RECOVERYONLY },
- { "swapprio=", MF_SWAPPRIO },
- { "zramsize=", MF_ZRAMSIZE },
- { "verify", MF_VERIFY },
- { "noemulatedsd", MF_NOEMULATEDSD },
- { "defaults", 0 },
- { 0, 0 },
-};
-
-struct fs_mgr_flag_values {
- char *key_loc;
- long long part_length;
- char *label;
- int partnum;
- int swap_prio;
- unsigned int zram_size;
-};
-
/*
* gettime() - returns the time in seconds of the system's monotonic clock or
* zero on error.
@@ -133,269 +84,6 @@
return ret;
}
-static int parse_flags(char *flags, struct flag_list *fl,
- struct fs_mgr_flag_values *flag_vals,
- char *fs_options, int fs_options_len)
-{
- int f = 0;
- int i;
- char *p;
- char *savep;
-
- /* initialize flag values. If we find a relevant flag, we'll
- * update the value */
- if (flag_vals) {
- memset(flag_vals, 0, sizeof(*flag_vals));
- flag_vals->partnum = -1;
- flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
- }
-
- /* initialize fs_options to the null string */
- if (fs_options && (fs_options_len > 0)) {
- fs_options[0] = '\0';
- }
-
- p = strtok_r(flags, ",", &savep);
- while (p) {
- /* Look for the flag "p" in the flag list "fl"
- * If not found, the loop exits with fl[i].name being null.
- */
- for (i = 0; fl[i].name; i++) {
- if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
- f |= fl[i].flag;
- if ((fl[i].flag == MF_CRYPT) && flag_vals) {
- /* The encryptable flag is followed by an = and the
- * location of the keys. Get it and return it.
- */
- flag_vals->key_loc = strdup(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
- /* The length flag is followed by an = and the
- * size of the partition. Get it and return it.
- */
- flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
- /* The voldmanaged flag is followed by an = and the
- * label, a colon and the partition number or the
- * word "auto", e.g.
- * voldmanaged=sdcard:3
- * Get and return them.
- */
- char *label_start;
- char *label_end;
- char *part_start;
-
- label_start = strchr(p, '=') + 1;
- label_end = strchr(p, ':');
- if (label_end) {
- flag_vals->label = strndup(label_start,
- (int) (label_end - label_start));
- part_start = strchr(p, ':') + 1;
- if (!strcmp(part_start, "auto")) {
- flag_vals->partnum = -1;
- } else {
- flag_vals->partnum = strtol(part_start, NULL, 0);
- }
- } else {
- ERROR("Warning: voldmanaged= flag malformed\n");
- }
- } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
- flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
- flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
- }
- break;
- }
- }
-
- if (!fl[i].name) {
- if (fs_options) {
- /* It's not a known flag, so it must be a filesystem specific
- * option. Add it to fs_options if it was passed in.
- */
- strlcat(fs_options, p, fs_options_len);
- strlcat(fs_options, ",", fs_options_len);
- } else {
- /* fs_options was not passed in, so if the flag is unknown
- * it's an error.
- */
- ERROR("Warning: unknown flag %s\n", p);
- }
- }
- p = strtok_r(NULL, ",", &savep);
- }
-
-out:
- if (fs_options && fs_options[0]) {
- /* remove the last trailing comma from the list of options */
- fs_options[strlen(fs_options) - 1] = '\0';
- }
-
- return f;
-}
-
-struct fstab *fs_mgr_read_fstab(const char *fstab_path)
-{
- FILE *fstab_file;
- int cnt, entries;
- ssize_t len;
- size_t alloc_len = 0;
- char *line = NULL;
- const char *delim = " \t";
- char *save_ptr, *p;
- struct fstab *fstab = NULL;
- struct fstab_rec *recs;
- struct fs_mgr_flag_values flag_vals;
-#define FS_OPTIONS_LEN 1024
- char tmp_fs_options[FS_OPTIONS_LEN];
-
- fstab_file = fopen(fstab_path, "r");
- if (!fstab_file) {
- ERROR("Cannot open file %s\n", fstab_path);
- return 0;
- }
-
- entries = 0;
- while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
- /* if the last character is a newline, shorten the string by 1 byte */
- if (line[len - 1] == '\n') {
- line[len - 1] = '\0';
- }
- /* Skip any leading whitespace */
- p = line;
- while (isspace(*p)) {
- p++;
- }
- /* ignore comments or empty lines */
- if (*p == '#' || *p == '\0')
- continue;
- entries++;
- }
-
- if (!entries) {
- ERROR("No entries found in fstab\n");
- goto err;
- }
-
- /* Allocate and init the fstab structure */
- fstab = calloc(1, sizeof(struct fstab));
- fstab->num_entries = entries;
- fstab->fstab_filename = strdup(fstab_path);
- fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
-
- fseek(fstab_file, 0, SEEK_SET);
-
- cnt = 0;
- while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
- /* if the last character is a newline, shorten the string by 1 byte */
- if (line[len - 1] == '\n') {
- line[len - 1] = '\0';
- }
-
- /* Skip any leading whitespace */
- p = line;
- while (isspace(*p)) {
- p++;
- }
- /* ignore comments or empty lines */
- if (*p == '#' || *p == '\0')
- continue;
-
- /* If a non-comment entry is greater than the size we allocated, give an
- * error and quit. This can happen in the unlikely case the file changes
- * between the two reads.
- */
- if (cnt >= entries) {
- ERROR("Tried to process more entries than counted\n");
- break;
- }
-
- if (!(p = strtok_r(line, delim, &save_ptr))) {
- ERROR("Error parsing mount source\n");
- goto err;
- }
- fstab->recs[cnt].blk_device = strdup(p);
-
- if (!(p = strtok_r(NULL, delim, &save_ptr))) {
- ERROR("Error parsing mount_point\n");
- goto err;
- }
- fstab->recs[cnt].mount_point = strdup(p);
-
- if (!(p = strtok_r(NULL, delim, &save_ptr))) {
- ERROR("Error parsing fs_type\n");
- goto err;
- }
- fstab->recs[cnt].fs_type = strdup(p);
-
- if (!(p = strtok_r(NULL, delim, &save_ptr))) {
- ERROR("Error parsing mount_flags\n");
- goto err;
- }
- tmp_fs_options[0] = '\0';
- fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
- tmp_fs_options, FS_OPTIONS_LEN);
-
- /* fs_options are optional */
- if (tmp_fs_options[0]) {
- fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
- } else {
- fstab->recs[cnt].fs_options = NULL;
- }
-
- if (!(p = strtok_r(NULL, delim, &save_ptr))) {
- ERROR("Error parsing fs_mgr_options\n");
- goto err;
- }
- fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
- &flag_vals, NULL, 0);
- fstab->recs[cnt].key_loc = flag_vals.key_loc;
- fstab->recs[cnt].length = flag_vals.part_length;
- fstab->recs[cnt].label = flag_vals.label;
- fstab->recs[cnt].partnum = flag_vals.partnum;
- fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
- fstab->recs[cnt].zram_size = flag_vals.zram_size;
- cnt++;
- }
- fclose(fstab_file);
- free(line);
- return fstab;
-
-err:
- fclose(fstab_file);
- free(line);
- if (fstab)
- fs_mgr_free_fstab(fstab);
- return NULL;
-}
-
-void fs_mgr_free_fstab(struct fstab *fstab)
-{
- int i;
-
- if (!fstab) {
- return;
- }
-
- for (i = 0; i < fstab->num_entries; i++) {
- /* Free the pointers return by strdup(3) */
- free(fstab->recs[i].blk_device);
- free(fstab->recs[i].mount_point);
- free(fstab->recs[i].fs_type);
- free(fstab->recs[i].fs_options);
- free(fstab->recs[i].key_loc);
- free(fstab->recs[i].label);
- }
-
- /* Free the fstab_recs array created by calloc(3) */
- free(fstab->recs);
-
- /* Free the fstab filename */
- free(fstab->fstab_filename);
-
- /* Free fstab */
- free(fstab);
-}
-
static void check_fs(char *blk_device, char *fs_type, char *target)
{
int status;
@@ -428,15 +116,24 @@
umount(target);
}
- INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
+ /*
+ * Some system images do not have e2fsck for licensing reasons
+ * (e.g. recent SDK system images). Detect these and skip the check.
+ */
+ if (access(E2FSCK_BIN, X_OK)) {
+ INFO("Not running %s on %s (executable not in system image)\n",
+ E2FSCK_BIN, blk_device);
+ } else {
+ INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
- ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
- &status, true, LOG_KLOG | LOG_FILE,
- true, FSCK_LOG_FILE);
+ ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
+ &status, true, LOG_KLOG | LOG_FILE,
+ true, FSCK_LOG_FILE);
- if (ret < 0) {
- /* No need to check for error in fork, we can't really handle it now */
- ERROR("Failed trying to run %s\n", E2FSCK_BIN);
+ if (ret < 0) {
+ /* No need to check for error in fork, we can't really handle it now */
+ ERROR("Failed trying to run %s\n", E2FSCK_BIN);
+ }
}
}
@@ -823,71 +520,3 @@
return 0;
}
-
-/* Add an entry to the fstab, and return 0 on success or -1 on error */
-int fs_mgr_add_entry(struct fstab *fstab,
- const char *mount_point, const char *fs_type,
- const char *blk_device, long long length)
-{
- struct fstab_rec *new_fstab_recs;
- int n = fstab->num_entries;
-
- new_fstab_recs = (struct fstab_rec *)
- realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
-
- if (!new_fstab_recs) {
- return -1;
- }
-
- /* A new entry was added, so initialize it */
- memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
- new_fstab_recs[n].mount_point = strdup(mount_point);
- new_fstab_recs[n].fs_type = strdup(fs_type);
- new_fstab_recs[n].blk_device = strdup(blk_device);
- new_fstab_recs[n].length = 0;
-
- /* Update the fstab struct */
- fstab->recs = new_fstab_recs;
- fstab->num_entries++;
-
- return 0;
-}
-
-struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
-{
- int i;
-
- if (!fstab) {
- return NULL;
- }
-
- for (i = 0; i < fstab->num_entries; i++) {
- int len = strlen(fstab->recs[i].mount_point);
- if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
- (path[len] == '\0' || path[len] == '/')) {
- return &fstab->recs[i];
- }
- }
-
- return NULL;
-}
-
-int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_VOLDMANAGED;
-}
-
-int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_NONREMOVABLE;
-}
-
-int fs_mgr_is_encryptable(struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_CRYPT;
-}
-
-int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
-{
- return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
-}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
new file mode 100644
index 0000000..6145771
--- /dev/null
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+
+#include "fs_mgr_priv.h"
+
+struct fs_mgr_flag_values {
+ char *key_loc;
+ long long part_length;
+ char *label;
+ int partnum;
+ int swap_prio;
+ unsigned int zram_size;
+};
+
+struct flag_list {
+ const char *name;
+ unsigned flag;
+};
+
+static struct flag_list mount_flags[] = {
+ { "noatime", MS_NOATIME },
+ { "noexec", MS_NOEXEC },
+ { "nosuid", MS_NOSUID },
+ { "nodev", MS_NODEV },
+ { "nodiratime", MS_NODIRATIME },
+ { "ro", MS_RDONLY },
+ { "rw", 0 },
+ { "remount", MS_REMOUNT },
+ { "bind", MS_BIND },
+ { "rec", MS_REC },
+ { "unbindable", MS_UNBINDABLE },
+ { "private", MS_PRIVATE },
+ { "slave", MS_SLAVE },
+ { "shared", MS_SHARED },
+ { "defaults", 0 },
+ { 0, 0 },
+};
+
+static struct flag_list fs_mgr_flags[] = {
+ { "wait", MF_WAIT },
+ { "check", MF_CHECK },
+ { "encryptable=",MF_CRYPT },
+ { "nonremovable",MF_NONREMOVABLE },
+ { "voldmanaged=",MF_VOLDMANAGED},
+ { "length=", MF_LENGTH },
+ { "recoveryonly",MF_RECOVERYONLY },
+ { "swapprio=", MF_SWAPPRIO },
+ { "zramsize=", MF_ZRAMSIZE },
+ { "verify", MF_VERIFY },
+ { "noemulatedsd", MF_NOEMULATEDSD },
+ { "defaults", 0 },
+ { 0, 0 },
+};
+
+static int parse_flags(char *flags, struct flag_list *fl,
+ struct fs_mgr_flag_values *flag_vals,
+ char *fs_options, int fs_options_len)
+{
+ int f = 0;
+ int i;
+ char *p;
+ char *savep;
+
+ /* initialize flag values. If we find a relevant flag, we'll
+ * update the value */
+ if (flag_vals) {
+ memset(flag_vals, 0, sizeof(*flag_vals));
+ flag_vals->partnum = -1;
+ flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
+ }
+
+ /* initialize fs_options to the null string */
+ if (fs_options && (fs_options_len > 0)) {
+ fs_options[0] = '\0';
+ }
+
+ p = strtok_r(flags, ",", &savep);
+ while (p) {
+ /* Look for the flag "p" in the flag list "fl"
+ * If not found, the loop exits with fl[i].name being null.
+ */
+ for (i = 0; fl[i].name; i++) {
+ if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
+ f |= fl[i].flag;
+ if ((fl[i].flag == MF_CRYPT) && flag_vals) {
+ /* The encryptable flag is followed by an = and the
+ * location of the keys. Get it and return it.
+ */
+ flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+ } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
+ /* The length flag is followed by an = and the
+ * size of the partition. Get it and return it.
+ */
+ flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
+ } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
+ /* The voldmanaged flag is followed by an = and the
+ * label, a colon and the partition number or the
+ * word "auto", e.g.
+ * voldmanaged=sdcard:3
+ * Get and return them.
+ */
+ char *label_start;
+ char *label_end;
+ char *part_start;
+
+ label_start = strchr(p, '=') + 1;
+ label_end = strchr(p, ':');
+ if (label_end) {
+ flag_vals->label = strndup(label_start,
+ (int) (label_end - label_start));
+ part_start = strchr(p, ':') + 1;
+ if (!strcmp(part_start, "auto")) {
+ flag_vals->partnum = -1;
+ } else {
+ flag_vals->partnum = strtol(part_start, NULL, 0);
+ }
+ } else {
+ ERROR("Warning: voldmanaged= flag malformed\n");
+ }
+ } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
+ flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
+ } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
+ flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
+ }
+ break;
+ }
+ }
+
+ if (!fl[i].name) {
+ if (fs_options) {
+ /* It's not a known flag, so it must be a filesystem specific
+ * option. Add it to fs_options if it was passed in.
+ */
+ strlcat(fs_options, p, fs_options_len);
+ strlcat(fs_options, ",", fs_options_len);
+ } else {
+ /* fs_options was not passed in, so if the flag is unknown
+ * it's an error.
+ */
+ ERROR("Warning: unknown flag %s\n", p);
+ }
+ }
+ p = strtok_r(NULL, ",", &savep);
+ }
+
+out:
+ if (fs_options && fs_options[0]) {
+ /* remove the last trailing comma from the list of options */
+ fs_options[strlen(fs_options) - 1] = '\0';
+ }
+
+ return f;
+}
+
+struct fstab *fs_mgr_read_fstab(const char *fstab_path)
+{
+ FILE *fstab_file;
+ int cnt, entries;
+ ssize_t len;
+ size_t alloc_len = 0;
+ char *line = NULL;
+ const char *delim = " \t";
+ char *save_ptr, *p;
+ struct fstab *fstab = NULL;
+ struct fstab_rec *recs;
+ struct fs_mgr_flag_values flag_vals;
+#define FS_OPTIONS_LEN 1024
+ char tmp_fs_options[FS_OPTIONS_LEN];
+
+ fstab_file = fopen(fstab_path, "r");
+ if (!fstab_file) {
+ ERROR("Cannot open file %s\n", fstab_path);
+ return 0;
+ }
+
+ entries = 0;
+ while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
+ /* if the last character is a newline, shorten the string by 1 byte */
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
+ /* Skip any leading whitespace */
+ p = line;
+ while (isspace(*p)) {
+ p++;
+ }
+ /* ignore comments or empty lines */
+ if (*p == '#' || *p == '\0')
+ continue;
+ entries++;
+ }
+
+ if (!entries) {
+ ERROR("No entries found in fstab\n");
+ goto err;
+ }
+
+ /* Allocate and init the fstab structure */
+ fstab = calloc(1, sizeof(struct fstab));
+ fstab->num_entries = entries;
+ fstab->fstab_filename = strdup(fstab_path);
+ fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
+
+ fseek(fstab_file, 0, SEEK_SET);
+
+ cnt = 0;
+ while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
+ /* if the last character is a newline, shorten the string by 1 byte */
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
+
+ /* Skip any leading whitespace */
+ p = line;
+ while (isspace(*p)) {
+ p++;
+ }
+ /* ignore comments or empty lines */
+ if (*p == '#' || *p == '\0')
+ continue;
+
+ /* If a non-comment entry is greater than the size we allocated, give an
+ * error and quit. This can happen in the unlikely case the file changes
+ * between the two reads.
+ */
+ if (cnt >= entries) {
+ ERROR("Tried to process more entries than counted\n");
+ break;
+ }
+
+ if (!(p = strtok_r(line, delim, &save_ptr))) {
+ ERROR("Error parsing mount source\n");
+ goto err;
+ }
+ fstab->recs[cnt].blk_device = strdup(p);
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ ERROR("Error parsing mount_point\n");
+ goto err;
+ }
+ fstab->recs[cnt].mount_point = strdup(p);
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ ERROR("Error parsing fs_type\n");
+ goto err;
+ }
+ fstab->recs[cnt].fs_type = strdup(p);
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ ERROR("Error parsing mount_flags\n");
+ goto err;
+ }
+ tmp_fs_options[0] = '\0';
+ fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
+ tmp_fs_options, FS_OPTIONS_LEN);
+
+ /* fs_options are optional */
+ if (tmp_fs_options[0]) {
+ fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
+ } else {
+ fstab->recs[cnt].fs_options = NULL;
+ }
+
+ if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ ERROR("Error parsing fs_mgr_options\n");
+ goto err;
+ }
+ fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
+ &flag_vals, NULL, 0);
+ fstab->recs[cnt].key_loc = flag_vals.key_loc;
+ fstab->recs[cnt].length = flag_vals.part_length;
+ fstab->recs[cnt].label = flag_vals.label;
+ fstab->recs[cnt].partnum = flag_vals.partnum;
+ fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
+ fstab->recs[cnt].zram_size = flag_vals.zram_size;
+ cnt++;
+ }
+ fclose(fstab_file);
+ free(line);
+ return fstab;
+
+err:
+ fclose(fstab_file);
+ free(line);
+ if (fstab)
+ fs_mgr_free_fstab(fstab);
+ return NULL;
+}
+
+void fs_mgr_free_fstab(struct fstab *fstab)
+{
+ int i;
+
+ if (!fstab) {
+ return;
+ }
+
+ for (i = 0; i < fstab->num_entries; i++) {
+ /* Free the pointers return by strdup(3) */
+ free(fstab->recs[i].blk_device);
+ free(fstab->recs[i].mount_point);
+ free(fstab->recs[i].fs_type);
+ free(fstab->recs[i].fs_options);
+ free(fstab->recs[i].key_loc);
+ free(fstab->recs[i].label);
+ }
+
+ /* Free the fstab_recs array created by calloc(3) */
+ free(fstab->recs);
+
+ /* Free the fstab filename */
+ free(fstab->fstab_filename);
+
+ /* Free fstab */
+ free(fstab);
+}
+
+/* Add an entry to the fstab, and return 0 on success or -1 on error */
+int fs_mgr_add_entry(struct fstab *fstab,
+ const char *mount_point, const char *fs_type,
+ const char *blk_device, long long length)
+{
+ struct fstab_rec *new_fstab_recs;
+ int n = fstab->num_entries;
+
+ new_fstab_recs = (struct fstab_rec *)
+ realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
+
+ if (!new_fstab_recs) {
+ return -1;
+ }
+
+ /* A new entry was added, so initialize it */
+ memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
+ new_fstab_recs[n].mount_point = strdup(mount_point);
+ new_fstab_recs[n].fs_type = strdup(fs_type);
+ new_fstab_recs[n].blk_device = strdup(blk_device);
+ new_fstab_recs[n].length = 0;
+
+ /* Update the fstab struct */
+ fstab->recs = new_fstab_recs;
+ fstab->num_entries++;
+
+ return 0;
+}
+
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+ int i;
+
+ if (!fstab) {
+ return NULL;
+ }
+
+ for (i = 0; i < fstab->num_entries; i++) {
+ int len = strlen(fstab->recs[i].mount_point);
+ if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
+ (path[len] == '\0' || path[len] == '/')) {
+ return &fstab->recs[i];
+ }
+ }
+
+ return NULL;
+}
+
+int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_VOLDMANAGED;
+}
+
+int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_NONREMOVABLE;
+}
+
+int fs_mgr_is_encryptable(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_CRYPT;
+}
+
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
+}
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 1549316..40bc2ec 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -36,8 +36,7 @@
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"
-#include "ext4_utils.h"
-#include "ext4.h"
+#include "ext4_sb.h"
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_verity.h"
@@ -122,6 +121,7 @@
{
int data_device;
struct ext4_super_block sb;
+ struct fs_info info = {0};
data_device = open(blk_device, O_RDONLY);
if (data_device < 0) {
@@ -141,7 +141,7 @@
return -1;
}
- ext4_parse_sb(&sb);
+ ext4_parse_sb(&sb, &info);
*device_size = info.len;
close(data_device);
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index bd4134c..3c3a482 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -17,6 +17,7 @@
#ifndef _BACKTRACE_BACKTRACE_H
#define _BACKTRACE_BACKTRACE_H
+#include <inttypes.h>
#include <stdint.h>
#include <string>
@@ -25,6 +26,14 @@
#include <backtrace/backtrace_constants.h>
#include <backtrace/BacktraceMap.h>
+#if __LP64__
+#define PRIPTR "016" PRIxPTR
+typedef uint64_t word_t;
+#else
+#define PRIPTR "08" PRIxPTR
+typedef uint32_t word_t;
+#endif
+
struct backtrace_frame_data_t {
size_t num; // The current fame number.
uintptr_t pc; // The absolute pc.
@@ -65,7 +74,7 @@
virtual const backtrace_map_t* FindMap(uintptr_t pc);
// Read the data at a specific address.
- virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
+ virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;
// Create a string representing the formatted line of backtrace information
// for a single frame.
@@ -96,7 +105,7 @@
protected:
Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);
- virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);
+ virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);
bool BuildMap();
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index ae79e00..4f90ef1 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -47,8 +47,10 @@
#include <cutils/atomic-arm64.h>
#elif defined(__arm__)
#include <cutils/atomic-arm.h>
-#elif defined(__i386__) || defined(__x86_64__)
+#elif defined(__i386__)
#include <cutils/atomic-x86.h>
+#elif defined(__x86_64__)
+#include <cutils/atomic-x86_64.h>
#elif defined(__mips__)
#include <cutils/atomic-mips.h>
#else
diff --git a/include/cutils/atomic-x86_64.h b/include/cutils/atomic-x86_64.h
new file mode 100644
index 0000000..5b5c203
--- /dev/null
+++ b/include/cutils/atomic-x86_64.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2014 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 ANDROID_CUTILS_ATOMIC_X86_64_H
+#define ANDROID_CUTILS_ATOMIC_X86_64_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+void android_compiler_barrier(void)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+ android_compiler_barrier();
+}
+extern ANDROID_ATOMIC_INLINE
+void android_memory_store_barrier(void)
+{
+ android_compiler_barrier();
+}
+#else
+extern ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("mfence" : : : "memory");
+}
+extern ANDROID_ATOMIC_INLINE
+void android_memory_store_barrier(void)
+{
+ android_compiler_barrier();
+}
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_compiler_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
+{
+ int64_t value = *ptr;
+ android_compiler_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_load64(volatile const int64_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+ android_compiler_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
+{
+ android_compiler_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int32_t prev;
+ __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ int64_t prev;
+ __asm__ __volatile__ ("lock; cmpxchgq %1, %2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ /* Loads are not reordered with other loads. */
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ /* Loads are not reordered with other loads. */
+ return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ /* Stores are not reordered with other stores. */
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ /* Stores are not reordered with other stores. */
+ return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+ __asm__ __volatile__ ("lock; xaddl %0, %1"
+ : "+r" (increment), "+m" (*ptr)
+ : : "memory");
+ /* increment now holds the old value of *ptr */
+ return increment;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev & value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev | value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_X86_64_H */
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 4eda523..af80e2c 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -23,7 +23,11 @@
extern "C" {
#endif
+#if __LP64__
+#define DEBUGGER_SOCKET_NAME "android:debuggerd64"
+#else
#define DEBUGGER_SOCKET_NAME "android:debuggerd"
+#endif
typedef enum {
// dump a crash
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index ba728ac..3635e89 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -18,22 +18,31 @@
#define _CUTILS_KLOG_H_
#include <sys/cdefs.h>
+#include <stdarg.h>
__BEGIN_DECLS
void klog_init(void);
+int klog_get_level(void);
void klog_set_level(int level);
void klog_close(void);
void klog_write(int level, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
+void klog_vwrite(int level, const char *fmt, va_list ap);
__END_DECLS
-#define KLOG_ERROR(tag,x...) klog_write(3, "<3>" tag ": " x)
-#define KLOG_WARNING(tag,x...) klog_write(4, "<4>" tag ": " x)
-#define KLOG_NOTICE(tag,x...) klog_write(5, "<5>" tag ": " x)
-#define KLOG_INFO(tag,x...) klog_write(6, "<6>" tag ": " x)
-#define KLOG_DEBUG(tag,x...) klog_write(7, "<7>" tag ": " x)
+#define KLOG_ERROR_LEVEL 3
+#define KLOG_WARNING_LEVEL 4
+#define KLOG_NOTICE_LEVEL 5
+#define KLOG_INFO_LEVEL 6
+#define KLOG_DEBUG_LEVEL 7
+
+#define KLOG_ERROR(tag,x...) klog_write(KLOG_ERROR_LEVEL, "<3>" tag ": " x)
+#define KLOG_WARNING(tag,x...) klog_write(KLOG_WARNING_LEVEL, "<4>" tag ": " x)
+#define KLOG_NOTICE(tag,x...) klog_write(KLOG_NOTICE_LEVEL, "<5>" tag ": " x)
+#define KLOG_INFO(tag,x...) klog_write(KLOG_INFO_LEVEL, "<6>" tag ": " x)
+#define KLOG_DEBUG(tag,x...) klog_write(KLOG_DEBUG_LEVEL, "<7>" tag ": " x)
#define KLOG_DEFAULT_LEVEL 3 /* messages <= this level are logged */
diff --git a/include/cutils/misc.h b/include/cutils/misc.h
index 2c48dfa..0de505f 100644
--- a/include/cutils/misc.h
+++ b/include/cutils/misc.h
@@ -28,13 +28,6 @@
*/
extern void *load_file(const char *fn, unsigned *sz);
- /* Connects your process to the system debugger daemon
- * so that on a crash it may be logged or interactively
- * debugged (depending on system settings).
- */
-extern void debuggerd_connect(void);
-
-
/* This is the range of UIDs (and GIDs) that are reserved
* for assigning to applications.
*/
diff --git a/include/log/log.h b/include/log/log.h
index 7f952ff..d469f40 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -73,10 +73,11 @@
* Simplified macro to send a verbose log message using the current LOG_TAG.
*/
#ifndef ALOGV
+#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#if LOG_NDEBUG
-#define ALOGV(...) ((void)0)
+#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
#else
-#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define ALOGV(...) __ALOGV(__VA_ARGS__)
#endif
#endif
@@ -202,10 +203,11 @@
* Simplified macro to send a verbose system log message using the current LOG_TAG.
*/
#ifndef SLOGV
+#define __SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#if LOG_NDEBUG
-#define SLOGV(...) ((void)0)
+#define SLOGV(...) do { if (0) { __SLOGV(__VA_ARGS__); } } while (0)
#else
-#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define SLOGV(...) __SLOGV(__VA_ARGS__)
#endif
#endif
@@ -284,10 +286,11 @@
* Simplified macro to send a verbose radio log message using the current LOG_TAG.
*/
#ifndef RLOGV
+#define __RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#if LOG_NDEBUG
-#define RLOGV(...) ((void)0)
+#define RLOGV(...) do { if (0) { __RLOGV(__VA_ARGS__); } } while (0)
#else
-#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
+#define RLOGV(...) __RLOGV(__VA_ARGS__)
#endif
#endif
@@ -557,7 +560,11 @@
* Send a simple string to the log.
*/
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
-int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+#if defined(__GNUC__)
+ __attribute__((__format__(printf, 4, 5)))
+#endif
+ ;
#ifdef __cplusplus
}
diff --git a/include/log/log_read.h b/include/log/log_read.h
index 861c192..7edfe3c 100644
--- a/include/log/log_read.h
+++ b/include/log/log_read.h
@@ -19,21 +19,38 @@
#include <time.h>
+/* struct log_time is a wire-format variant of struct timespec */
#define NS_PER_SEC 1000000000ULL
#ifdef __cplusplus
-struct log_time : public timespec {
+struct log_time {
public:
- log_time(timespec &T)
+ uint32_t tv_sec; // good to Feb 5 2106
+ uint32_t tv_nsec;
+
+ log_time(const timespec &T)
{
tv_sec = T.tv_sec;
tv_nsec = T.tv_nsec;
}
- log_time(void)
+ log_time(const log_time &T)
+ {
+ tv_sec = T.tv_sec;
+ tv_nsec = T.tv_nsec;
+ }
+ log_time(uint32_t sec, uint32_t nsec)
+ {
+ tv_sec = sec;
+ tv_nsec = nsec;
+ }
+ log_time()
{
}
log_time(clockid_t id)
{
- clock_gettime(id, (timespec *) this);
+ timespec T;
+ clock_gettime(id, &T);
+ tv_sec = T.tv_sec;
+ tv_nsec = T.tv_nsec;
}
log_time(const char *T)
{
@@ -41,6 +58,8 @@
tv_sec = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
tv_nsec = c[4] | (c[5] << 8) | (c[6] << 16) | (c[7] << 24);
}
+
+ // timespec
bool operator== (const timespec &T) const
{
return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
@@ -67,13 +86,45 @@
{
return !(*this > T);
}
- uint64_t nsec(void) const
+
+ // log_time
+ bool operator== (const log_time &T) const
+ {
+ return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+ }
+ bool operator!= (const log_time &T) const
+ {
+ return !(*this == T);
+ }
+ bool operator< (const log_time &T) const
+ {
+ return (tv_sec < T.tv_sec)
+ || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+ }
+ bool operator>= (const log_time &T) const
+ {
+ return !(*this < T);
+ }
+ bool operator> (const log_time &T) const
+ {
+ return (tv_sec > T.tv_sec)
+ || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+ }
+ bool operator<= (const log_time &T) const
+ {
+ return !(*this > T);
+ }
+
+ uint64_t nsec() const
{
return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
}
-};
+} __attribute__((__packed__));
#else
-typedef struct timespec log_time;
+typedef struct log_time {
+ uint32_t tv_sec;
+ uint32_t tv_nsec;
+} __attribute__((__packed__)) log_time;
#endif
#endif /* define _LIBS_LOG_LOG_READ_H */
diff --git a/include/log/logger.h b/include/log/logger.h
index 966397a..8dab234 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -30,12 +30,12 @@
int32_t sec; /* seconds since Epoch */
int32_t nsec; /* nanoseconds */
char msg[0]; /* the entry's payload */
-};
+} __attribute__((__packed__));
/*
* The userspace structure for version 2 of the logger_entry ABI.
* This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version==2
+ * is called with version==2; or used with the user space log daemon.
*/
struct logger_entry_v2 {
uint16_t len; /* length of the payload */
@@ -46,7 +46,18 @@
int32_t nsec; /* nanoseconds */
uint32_t euid; /* effective UID of logger */
char msg[0]; /* the entry's payload */
-};
+} __attribute__((__packed__));
+
+struct logger_entry_v3 {
+ uint16_t len; /* length of the payload */
+ uint16_t hdr_size; /* sizeof(struct logger_entry_v3) */
+ int32_t pid; /* generating process's pid */
+ int32_t tid; /* generating process's tid */
+ int32_t sec; /* seconds since Epoch */
+ int32_t nsec; /* nanoseconds */
+ uint32_t lid; /* log id of the payload */
+ char msg[0]; /* the entry's payload */
+} __attribute__((__packed__));
/*
* The maximum size of the log entry payload that can be
@@ -68,13 +79,10 @@
struct log_msg {
union {
unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry_v2 entry;
+ struct logger_entry_v3 entry;
+ struct logger_entry_v3 entry_v3;
struct logger_entry_v2 entry_v2;
struct logger_entry entry_v1;
- struct {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- log_id_t id;
- } extra;
} __attribute__((aligned(4)));
#ifdef __cplusplus
/* Matching log_time operators */
@@ -106,21 +114,21 @@
{
return !(*this > T);
}
- uint64_t nsec(void) const
+ uint64_t nsec() const
{
return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
}
/* packet methods */
- log_id_t id(void)
+ log_id_t id()
{
- return extra.id;
+ return (log_id_t) entry.lid;
}
- char *msg(void)
+ char *msg()
{
return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
}
- unsigned int len(void)
+ unsigned int len()
{
return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
}
@@ -132,12 +140,24 @@
log_id_t android_logger_get_id(struct logger *logger);
int android_logger_clear(struct logger *logger);
-int android_logger_get_log_size(struct logger *logger);
-int android_logger_get_log_readable_size(struct logger *logger);
+long android_logger_get_log_size(struct logger *logger);
+#ifdef USERDEBUG_BUILD
+int android_logger_set_log_size(struct logger *logger, unsigned long size);
+#endif
+long android_logger_get_log_readable_size(struct logger *logger);
int android_logger_get_log_version(struct logger *logger);
struct logger_list;
+ssize_t android_logger_get_statistics(struct logger_list *logger_list,
+ char *buf, size_t len);
+#ifdef USERDEBUG_BUILD
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
+ char *buf, size_t len);
+int android_logger_set_prune_list(struct logger_list *logger_list,
+ char *buf, size_t len);
+#endif
+
struct logger_list *android_logger_list_alloc(int mode,
unsigned int tail,
pid_t pid);
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 0ed0d78..9c26baf 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -76,6 +76,7 @@
#define AID_SDCARD_PICS 1033 /* external storage photos access */
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
+#define AID_LOGD 1036 /* log daemon */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@@ -151,6 +152,7 @@
{ "sdcard_pics", AID_SDCARD_PICS, },
{ "sdcard_av", AID_SDCARD_AV, },
{ "sdcard_all", AID_SDCARD_ALL, },
+ { "logd", AID_LOGD, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
index c204a0f..bc93b86 100644
--- a/include/sysutils/SocketListener.h
+++ b/include/sysutils/SocketListener.h
@@ -38,6 +38,7 @@
virtual ~SocketListener();
int startListener();
+ int startListener(int backlog);
int stopListener();
void sendBroadcast(int code, const char *msg, bool addErrno);
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
index 0b75b19..46173db 100644
--- a/include/utils/Errors.h
+++ b/include/utils/Errors.h
@@ -41,23 +41,23 @@
#ifdef _WIN32
# undef NO_ERROR
#endif
-
+
enum {
OK = 0, // Everything's swell.
NO_ERROR = 0, // No errors.
-
- UNKNOWN_ERROR = 0x80000000,
+
+ UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
NO_MEMORY = -ENOMEM,
INVALID_OPERATION = -ENOSYS,
BAD_VALUE = -EINVAL,
- BAD_TYPE = 0x80000001,
+ BAD_TYPE = (UNKNOWN_ERROR + 1),
NAME_NOT_FOUND = -ENOENT,
PERMISSION_DENIED = -EPERM,
NO_INIT = -ENODEV,
ALREADY_EXISTS = -EEXIST,
DEAD_OBJECT = -EPIPE,
- FAILED_TRANSACTION = 0x80000002,
+ FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
JPARKS_BROKE_IT = -EPIPE,
#if !defined(HAVE_MS_C_RUNTIME)
BAD_INDEX = -EOVERFLOW,
@@ -67,12 +67,12 @@
UNKNOWN_TRANSACTION = -EBADMSG,
#else
BAD_INDEX = -E2BIG,
- NOT_ENOUGH_DATA = 0x80000003,
- WOULD_BLOCK = 0x80000004,
- TIMED_OUT = 0x80000005,
- UNKNOWN_TRANSACTION = 0x80000006,
+ NOT_ENOUGH_DATA = (UNKNOWN_ERROR + 3),
+ WOULD_BLOCK = (UNKNOWN_ERROR + 4),
+ TIMED_OUT = (UNKNOWN_ERROR + 5),
+ UNKNOWN_TRANSACTION = (UNKNOWN_ERROR + 6),
#endif
- FDS_NOT_ALLOWED = 0x80000007,
+ FDS_NOT_ALLOWED = (UNKNOWN_ERROR + 7),
};
// Restore define; enumeration is in "android" namespace, so the value defined
diff --git a/init/Android.mk b/init/Android.mk
index 1f43ba6..740d10f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -26,6 +26,9 @@
LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1
endif
+# Enable ueventd logging
+#LOCAL_CFLAGS += -DLOG_UEVENTS=1
+
LOCAL_MODULE:= init
LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -42,6 +45,8 @@
libmincrypt \
libext4_utils_static
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+
include $(BUILD_EXECUTABLE)
# Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init
diff --git a/init/devices.c b/init/devices.c
index f7df453..80c6d75 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,6 @@
#include <private/android_filesystem_config.h>
#include <sys/time.h>
-#include <asm/page.h>
#include <sys/wait.h>
#include <cutils/list.h>
@@ -48,6 +47,8 @@
#include "util.h"
#include "log.h"
+#define UNUSED __attribute__((__unused__))
+
#define SYSFS_PREFIX "/sys"
#define FIRMWARE_DIR1 "/etc/firmware"
#define FIRMWARE_DIR2 "/vendor/firmware"
@@ -194,7 +195,7 @@
}
static void make_device(const char *path,
- const char *upath,
+ const char *upath UNUSED,
int block, int major, int minor)
{
unsigned uid;
@@ -590,6 +591,11 @@
mkdir_recursive(dir, 0755);
}
+static inline void __attribute__((__deprecated__)) kernel_logger()
+{
+ INFO("kernel logger is deprecated\n");
+}
+
static void handle_generic_device_event(struct uevent *uevent)
{
char *base;
@@ -676,6 +682,7 @@
make_dir(base, 0755);
} else if(!strncmp(uevent->subsystem, "misc", 4) &&
!strncmp(name, "log_", 4)) {
+ kernel_logger();
base = "/dev/log/";
make_dir(base, 0755);
name += 4;
diff --git a/init/init.c b/init/init.c
index 00f4558..0884236 100644
--- a/init/init.c
+++ b/init/init.c
@@ -933,12 +933,33 @@
return 0;
}
-int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
+static int audit_callback(void *data, security_class_t cls __attribute__((unused)), char *buf, size_t len)
{
snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
return 0;
}
+static int log_callback(int type, const char *fmt, ...)
+{
+ int level;
+ va_list ap;
+ switch (type) {
+ case SELINUX_WARNING:
+ level = KLOG_WARNING_LEVEL;
+ break;
+ case SELINUX_INFO:
+ level = KLOG_INFO_LEVEL;
+ break;
+ default:
+ level = KLOG_ERROR_LEVEL;
+ break;
+ }
+ va_start(ap, fmt);
+ klog_vwrite(level, fmt, ap);
+ va_end(ap);
+ return 0;
+}
+
static void selinux_initialize(void)
{
if (selinux_is_disabled()) {
@@ -1012,7 +1033,7 @@
process_kernel_cmdline();
union selinux_callback cb;
- cb.func_log = klog_write;
+ cb.func_log = log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
cb.func_audit = audit_callback;
diff --git a/init/log.h b/init/log.h
index 4aac3df..0ba770f 100644
--- a/init/log.h
+++ b/init/log.h
@@ -23,6 +23,4 @@
#define NOTICE(x...) KLOG_NOTICE("init", x)
#define INFO(x...) KLOG_INFO("init", x)
-#define LOG_UEVENTS 0 /* log uevent messages if 1. verbose */
-
#endif
diff --git a/init/ueventd.c b/init/ueventd.c
index 3d01836..5517448 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -69,6 +69,12 @@
open_devnull_stdio();
klog_init();
+#if LOG_UEVENTS
+ /* Ensure we're at a logging level that will show the events */
+ if (klog_get_level() < KLOG_LEVEL_INFO) {
+ klog_set_level(KLOG_LEVEL_INFO);
+ }
+#endif
INFO("starting ueventd\n");
diff --git a/init/util.c b/init/util.c
index e772342..0f69e1c 100644
--- a/init/util.c
+++ b/init/util.c
@@ -527,10 +527,10 @@
int restorecon(const char* pathname)
{
- return selinux_android_restorecon(pathname);
+ return selinux_android_restorecon(pathname, 0);
}
int restorecon_recursive(const char* pathname)
{
- return selinux_android_restorecon_recursive(pathname);
+ return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
}
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
new file mode 100644
index 0000000..3c80cc2
--- /dev/null
+++ b/libbacktrace/Android.build.mk
@@ -0,0 +1,73 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := $(module)
+LOCAL_MODULE_TAGS := $(module_tag)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk \
+ $(LOCAL_PATH)/Android.build.mk \
+
+LOCAL_CFLAGS := \
+ $(common_cflags) \
+ $($(module)_cflags) \
+ $($(module)_cflags_$(build_type)) \
+
+LOCAL_CONLYFLAGS += \
+ $(common_conlyflags) \
+ $($(module)_conlyflags) \
+ $($(module)_conlyflags_$(build_type)) \
+
+LOCAL_CPPFLAGS += \
+ $(common_cppflags) \
+ $($(module)_cppflags) \
+ $($(module)_cppflags_$(build_type)) \
+
+LOCAL_C_INCLUDES := \
+ $(common_c_includes) \
+ $($(module)_c_includes) \
+ $($(module)_c_includes_$(build_type)) \
+
+LOCAL_SRC_FILES := \
+ $($(module)_src_files) \
+ $($(module)_src_files_$(build_type)) \
+
+LOCAL_STATIC_LIBRARIES := \
+ $($(module)_static_libraries) \
+ $($(module)_static_libraries_$(build_type)) \
+
+LOCAL_SHARED_LIBRARIES := \
+ $($(module)_shared_libraries) \
+ $($(module)_shared_libraries_$(build_type)) \
+
+LOCAL_LDLIBS := \
+ $($(module)_ldlibs) \
+ $($(module)_ldlibs_$(build_type)) \
+
+ifeq ($(build_type),target)
+ include external/stlport/libstlport.mk
+
+ include $(BUILD_$(build_target))
+endif
+
+ifeq ($(build_type),host)
+ # Only build if host builds are supported.
+ ifeq ($(build_host),true)
+ include $(BUILD_HOST_$(build_target))
+ endif
+endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
old mode 100644
new mode 100755
index 0ae8839..2e56756
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -1,14 +1,23 @@
-LOCAL_PATH:= $(call my-dir)
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
-common_src := \
- BacktraceImpl.cpp \
- BacktraceMap.cpp \
- BacktraceThread.cpp \
- thread_utils.c \
+LOCAL_PATH:= $(call my-dir)
common_cflags := \
-Wall \
- -Wno-unused-parameter \
-Werror \
common_conlyflags := \
@@ -17,274 +26,148 @@
common_cppflags := \
-std=gnu++11 \
-common_shared_libs := \
+build_host := false
+ifeq ($(HOST_OS),linux)
+ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
+build_host := true
+endif
+endif
+
+#-------------------------------------------------------------------------
+# The libbacktrace library.
+#-------------------------------------------------------------------------
+libbacktrace_src_files := \
+ BacktraceImpl.cpp \
+ BacktraceMap.cpp \
+ BacktraceThread.cpp \
+ thread_utils.c \
+
+libbacktrace_shared_libraries_target := \
libcutils \
libgccdemangle \
- liblog \
# To enable using libunwind on each arch, add it to this list.
-libunwind_architectures := arm arm64
+libunwind_architectures := arm arm64 mips x86 x86_64
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
-
-#----------------------------------------------------------------------------
-# The native libbacktrace library with libunwind.
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- $(common_src) \
+libbacktrace_src_files += \
UnwindCurrent.cpp \
UnwindMap.cpp \
UnwindPtrace.cpp \
-LOCAL_CFLAGS := \
- $(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
- $(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
- $(common_cppflags) \
-
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
- $(common_c_includes) \
+libbacktrace_c_includes := \
external/libunwind/include \
-LOCAL_SHARED_LIBRARIES := \
- $(common_shared_libs) \
+libbacktrace_shared_libraries := \
libunwind \
libunwind-ptrace \
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk
-
-include external/stlport/libstlport.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-else
-
-#----------------------------------------------------------------------------
-# The native libbacktrace library with libcorkscrew.
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- $(common_src) \
- Corkscrew.cpp \
-
-LOCAL_CFLAGS := \
- $(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
- $(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
- $(common_cppflags) \
-
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
- $(common_c_includes) \
- system/core/libcorkscrew \
-
-LOCAL_SHARED_LIBRARIES := \
- $(common_shared_libs) \
- libcorkscrew \
- libdl \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk
-
-include external/stlport/libstlport.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-endif
-
-#----------------------------------------------------------------------------
-# libbacktrace test library, all optimizations turned off
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
- backtrace_testlib.c
-
-LOCAL_CFLAGS += \
- -std=gnu99 \
- -O0 \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-#----------------------------------------------------------------------------
-# libbacktrace test executable
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := backtrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
- backtrace_test.cpp \
- thread_utils.c \
-
-LOCAL_CFLAGS += \
- $(common_cflags) \
- -fno-builtin \
- -fstack-protector-all \
- -O0 \
- -g \
- -DGTEST_OS_LINUX_ANDROID \
- -DGTEST_HAS_STD_STRING \
-
-ifeq ($(TARGET_ARCH),arm64)
- $(info TODO: $(LOCAL_PATH)/Android.mk -fstack-protector not yet available for the AArch64 toolchain)
- LOCAL_CFLAGS += -fno-stack-protector
-endif # arm64
-
-LOCAL_CONLYFLAGS += \
- $(common_conlyflags) \
-
-LOCAL_CPPFLAGS += \
- $(common_cppflags) \
-
-LOCAL_SHARED_LIBRARIES += \
- libcutils \
- libbacktrace_test \
- libbacktrace \
-
-LOCAL_LDLIBS := \
- -lpthread \
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk
-
-include $(BUILD_NATIVE_TEST)
-
-#----------------------------------------------------------------------------
-# Only x86 host versions of libbacktrace supported.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_ARCH),x86)
-
-#----------------------------------------------------------------------------
-# The host libbacktrace library using libcorkscrew
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-
-LOCAL_CFLAGS += \
- $(common_cflags) \
-
-LOCAL_CONLYFLAGS += \
- $(common_conlyflags) \
-
-LOCAL_C_INCLUDES := \
- $(common_c_includes) \
-
-LOCAL_SHARED_LIBRARIES := \
- libgccdemangle \
+libbacktrace_shared_libraries_host := \
liblog \
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk
-
-ifeq ($(HOST_OS),linux)
-LOCAL_SRC_FILES += \
- $(common_src) \
- Corkscrew.cpp \
-
-LOCAL_C_INCLUDES += \
- system/core/libcorkscrew \
-
-LOCAL_SHARED_LIBRARIES := \
- libcorkscrew \
-
-LOCAL_CPPFLAGS += \
- $(common_cppflags) \
-
-LOCAL_LDLIBS += \
- -ldl \
- -lrt \
+libbacktrace_static_libraries_host := \
+ libcutils \
else
-LOCAL_SRC_FILES += \
- BacktraceMap.cpp \
+libbacktrace_src_files += \
+ Corkscrew.cpp \
+
+libbacktrace_c_includes := \
+ system/core/libcorkscrew \
+
+libbacktrace_shared_libraries := \
+ libcorkscrew \
+
+libbacktrace_shared_libraries_target += \
+ libdl \
+
+libbacktrace_ldlibs_host := \
+ -ldl \
endif
-include $(BUILD_HOST_SHARED_LIBRARY)
+module := libbacktrace
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
-#----------------------------------------------------------------------------
-# The host test is only supported on linux.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_OS),linux)
-
-#----------------------------------------------------------------------------
-# libbacktrace host test library, all optimizations turned off
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
- backtrace_testlib.c
-
-LOCAL_CFLAGS += \
- -std=gnu99 \
+#-------------------------------------------------------------------------
+# The libbacktrace_test library needed by backtrace_test.
+#-------------------------------------------------------------------------
+libbacktrace_test_cflags := \
-O0 \
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk
+libbacktrace_test_src_files := \
+ backtrace_testlib.c \
-include $(BUILD_HOST_SHARED_LIBRARY)
+module := libbacktrace_test
+module_tag := debug
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
-#----------------------------------------------------------------------------
-# libbacktrace host test executable
-#----------------------------------------------------------------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := backtrace_test
-LOCAL_MODULE_FLAGS := debug
-
-LOCAL_SRC_FILES := \
- backtrace_test.cpp \
- thread_utils.c \
-
-LOCAL_CFLAGS += \
- $(common_cflags) \
+#-------------------------------------------------------------------------
+# The backtrace_test executable.
+#-------------------------------------------------------------------------
+backtrace_test_cflags := \
-fno-builtin \
- -fstack-protector-all \
-O0 \
-g \
-DGTEST_HAS_STD_STRING \
-LOCAL_SHARED_LIBRARIES := \
+ifneq ($(TARGET_ARCH),arm64)
+backtrace_test_cflags += -fstack-protector-all
+else
+ $(info TODO: $(LOCAL_PATH)/Android.mk -fstack-protector not yet available for the AArch64 toolchain)
+ common_cflags += -fno-stack-protector
+endif # arm64
+
+backtrace_test_cflags_target := \
+ -DGTEST_OS_LINUX_ANDROID \
+
+backtrace_test_src_files := \
+ backtrace_test.cpp \
+ thread_utils.c \
+
+backtrace_test_ldlibs := \
+ -lpthread \
+
+backtrace_test_ldlibs_host := \
+ -lrt \
+
+backtrace_test_shared_libraries := \
libbacktrace_test \
libbacktrace \
-LOCAL_LDLIBS := \
- -lpthread \
+backtrace_test_shared_libraries_target := \
+ libcutils \
-LOCAL_ADDITIONAL_DEPENDENCIES := \
- $(LOCAL_PATH)/Android.mk
+module := backtrace_test
+module_tag := debug
+build_type := target
+build_target := NATIVE_TEST
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
-include $(BUILD_HOST_NATIVE_TEST)
+#----------------------------------------------------------------------------
+# Special truncated libbacktrace library for mac.
+#----------------------------------------------------------------------------
+ifeq ($(HOST_OS),darwin)
-endif # HOST_OS == linux
+include $(CLEAR_VARS)
-endif # HOST_ARCH == x86
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ BacktraceMap.cpp \
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif # HOST_OS-darwin
diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp
index 39296b4..855810e 100644
--- a/libbacktrace/BacktraceImpl.cpp
+++ b/libbacktrace/BacktraceImpl.cpp
@@ -21,9 +21,6 @@
#include <sys/types.h>
#include <unistd.h>
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
#include <string>
#include <backtrace/Backtrace.h>
@@ -82,10 +79,10 @@
return func_name;
}
-bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
- if (ptr & 3) {
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
+ if (ptr & (sizeof(word_t)-1)) {
BACK_LOGW("invalid pointer %p", (void*)ptr);
- *out_value = (uint32_t)-1;
+ *out_value = (word_t)-1;
return false;
}
return true;
@@ -143,18 +140,18 @@
BacktraceCurrent::~BacktraceCurrent() {
}
-bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
if (!VerifyReadWordArgs(ptr, out_value)) {
return false;
}
const backtrace_map_t* map = FindMap(ptr);
if (map && map->flags & PROT_READ) {
- *out_value = *reinterpret_cast<uint32_t*>(ptr);
+ *out_value = *reinterpret_cast<word_t*>(ptr);
return true;
} else {
BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
- *out_value = static_cast<uint32_t>(-1);
+ *out_value = static_cast<word_t>(-1);
return false;
}
}
@@ -171,7 +168,7 @@
BacktracePtrace::~BacktracePtrace() {
}
-bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
if (!VerifyReadWordArgs(ptr, out_value)) {
return false;
}
@@ -184,7 +181,7 @@
// To disambiguate -1 from a valid result, we clear errno beforehand.
errno = 0;
*out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
- if (*out_value == static_cast<uint32_t>(-1) && errno) {
+ if (*out_value == static_cast<word_t>(-1) && errno) {
BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
return false;
diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h
old mode 100644
new mode 100755
index af014d5..48dd11c
--- a/libbacktrace/BacktraceImpl.h
+++ b/libbacktrace/BacktraceImpl.h
@@ -61,7 +61,7 @@
BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
virtual ~BacktraceCurrent();
- bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+ bool ReadWord(uintptr_t ptr, word_t* out_value);
};
class BacktracePtrace : public Backtrace {
@@ -69,7 +69,7 @@
BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
virtual ~BacktracePtrace();
- bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+ bool ReadWord(uintptr_t ptr, word_t* out_value);
};
Backtrace* CreateCurrentObj(BacktraceMap* map);
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 6320800..6eb290d 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -93,7 +93,8 @@
}
ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s",
- map->start, map->end, map->flags, map->name.c_str());
+ reinterpret_cast<void*>(map->start), reinterpret_cast<void*>(map->end),
+ map->flags, map->name.c_str());
return true;
}
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
old mode 100644
new mode 100755
index 17b71b9..81e69bb
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "libbacktrace"
+#include <sys/ucontext.h>
#include <sys/types.h>
#include <backtrace/Backtrace.h>
@@ -27,27 +28,6 @@
#include "UnwindCurrent.h"
#include "UnwindMap.h"
-// Define the ucontext_t structures needed for each supported arch.
-#if defined(__arm__)
- // The current version of the <signal.h> doesn't define ucontext_t.
- #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined.
-
- // Machine context at the time a signal was raised.
- typedef struct ucontext {
- uint32_t uc_flags;
- struct ucontext* uc_link;
- stack_t uc_stack;
- struct sigcontext uc_mcontext;
- uint32_t uc_sigmask;
- } ucontext_t;
-#elif defined(__i386__)
- #include <asm/sigcontext.h>
- #include <asm/ucontext.h>
- typedef struct ucontext ucontext_t;
-#elif !defined(__mips__) && !defined(__aarch64__)
- #error Unsupported architecture.
-#endif
-
//-------------------------------------------------------------------------
// UnwindCurrent functions.
//-------------------------------------------------------------------------
@@ -158,7 +138,7 @@
context->regs[13] = uc->uc_mcontext.arm_sp;
context->regs[14] = uc->uc_mcontext.arm_lr;
context->regs[15] = uc->uc_mcontext.arm_pc;
-#elif defined(__mips__) || defined(__i386__)
+#else
context->uc_mcontext = uc->uc_mcontext;
#endif
}
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 03bb192..8268db6 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -45,7 +45,7 @@
pthread_mutex_lock(&g_map_mutex);
if (--g_map_references == 0) {
// Clear the local address space map.
- unw_map_set(unw_local_addr_space, NULL);
+ unw_map_local_set(NULL);
unw_map_cursor_destroy(&map_cursor_);
}
pthread_mutex_unlock(&g_map_mutex);
@@ -61,8 +61,8 @@
if (g_map_references == 0) {
return_value = (unw_map_cursor_create(&map_cursor_, pid_) == 0);
if (return_value) {
- // Set the local address space to this cursor map.
- unw_map_set(unw_local_addr_space, &map_cursor_);
+ // Set the local address space map to our new map.
+ unw_map_local_set(&map_cursor_);
g_map_references = 1;
g_map_cursor = map_cursor_;
}
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index e275317..8f3b68c 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -30,6 +30,8 @@
arch-x86/backtrace-x86.c \
arch-x86/ptrace-x86.c
+ifneq ($(TARGET_IS_64_BIT),true)
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(generic_src_files)
@@ -66,9 +68,9 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
+endif # TARGET_IS_64_BIT == false
-# TODO: reenable darwin-x86
-# ifeq ($(HOST_ARCH),x86)
+
ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
# Build libcorkscrew.
@@ -95,4 +97,4 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_EXECUTABLE)
-endif # HOST_ARCH == x86
+endif # $(HOST_OS)-$(HOST_ARCH) == linux-x86
diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c
index 7bd0d8f..751efbf 100644
--- a/libcorkscrew/arch-arm/backtrace-arm.c
+++ b/libcorkscrew/arch-arm/backtrace-arm.c
@@ -62,19 +62,7 @@
#include <elf.h>
#include <cutils/log.h>
-#if !defined(__BIONIC_HAVE_UCONTEXT_T)
-/* Old versions of the Android <signal.h> didn't define ucontext_t. */
-#include <asm/sigcontext.h> /* Ensure 'struct sigcontext' is defined. */
-
-/* Machine context at the time a signal was raised. */
-typedef struct ucontext {
- uint32_t uc_flags;
- struct ucontext* uc_link;
- stack_t uc_stack;
- struct sigcontext uc_mcontext;
- uint32_t uc_sigmask;
-} ucontext_t;
-#endif /* !__BIONIC_HAVE_UCONTEXT_T */
+#include <ucontext.h>
/* Unwind state. */
typedef struct {
diff --git a/libcorkscrew/arch-mips/backtrace-mips.c b/libcorkscrew/arch-mips/backtrace-mips.c
index 57cb324..832fb86 100644
--- a/libcorkscrew/arch-mips/backtrace-mips.c
+++ b/libcorkscrew/arch-mips/backtrace-mips.c
@@ -36,18 +36,7 @@
#include <sys/ptrace.h>
#include <cutils/log.h>
-#if defined(__BIONIC__)
-
-#if defined(__BIONIC_HAVE_UCONTEXT_T)
-
-// Bionic offers the Linux kernel headers.
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-typedef struct ucontext ucontext_t;
-
-#else /* __BIONIC_HAVE_UCONTEXT_T */
-
-/* Old versions of the Android <signal.h> didn't define ucontext_t. */
+#include <sys/ucontext.h>
/* For PTRACE_GETREGS */
typedef struct {
@@ -71,30 +60,6 @@
REG_GP, REG_SP, REG_S8, REG_RA,
};
-/* Machine context at the time a signal was raised. */
-typedef struct ucontext {
- unsigned int sc_regmask;
- unsigned int sc_status;
- unsigned long long sc_pc;
- unsigned long long sc_regs[32];
- unsigned long long sc_fpregs[32];
- unsigned int sc_acx;
- unsigned int sc_fpc_csr;
- unsigned int sc_fpc_eir;
- unsigned int sc_used_math;
- unsigned int sc_dsp;
- unsigned long long sc_mdhi;
- unsigned long long sc_mdlo;
- unsigned long sc_hi1;
- unsigned long sc_lo1;
- unsigned long sc_hi2;
- unsigned long sc_lo2;
- unsigned long sc_hi3;
- unsigned long sc_lo3;
-} ucontext_t;
-
-#endif /* __BIONIC_HAVE_UCONTEXT_T */
-#endif
/* Unwind state. */
typedef struct {
@@ -896,10 +861,10 @@
const ucontext_t* uc = (const ucontext_t*)sigcontext;
unwind_state_t state;
- state.reg[DWARF_PC] = uc->sc_pc;
- state.reg[DWARF_RA] = uc->sc_regs[REG_RA];
- state.reg[DWARF_FP] = uc->sc_regs[REG_S8];
- state.reg[DWARF_SP] = uc->sc_regs[REG_SP];
+ state.reg[DWARF_PC] = uc->uc_mcontext.pc;
+ state.reg[DWARF_RA] = uc->uc_mcontext.gregs[REG_RA];
+ state.reg[DWARF_FP] = uc->uc_mcontext.gregs[REG_S8];
+ state.reg[DWARF_SP] = uc->uc_mcontext.gregs[REG_SP];
ALOGV("unwind_backtrace_signal_arch: "
"ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index ef22821..df486de 100755
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -36,46 +36,7 @@
#include <sys/ptrace.h>
#include <cutils/log.h>
-#if defined(__BIONIC__)
-
-#if defined(__BIONIC_HAVE_UCONTEXT_T)
-
-// Bionic offers the Linux kernel headers.
-#include <asm/sigcontext.h>
-#include <asm/ucontext.h>
-typedef struct ucontext ucontext_t;
-
-#else /* __BIONIC_HAVE_UCONTEXT_T */
-
-/* Old versions of the Android <signal.h> didn't define ucontext_t. */
-
-typedef struct {
- uint32_t gregs[32];
- void* fpregs;
- uint32_t oldmask;
- uint32_t cr2;
-} mcontext_t;
-
-enum {
- REG_GS = 0, REG_FS, REG_ES, REG_DS,
- REG_EDI, REG_ESI, REG_EBP, REG_ESP,
- REG_EBX, REG_EDX, REG_ECX, REG_EAX,
- REG_TRAPNO, REG_ERR, REG_EIP, REG_CS,
- REG_EFL, REG_UESP, REG_SS
-};
-
-/* Machine context at the time a signal was raised. */
-typedef struct ucontext {
- uint32_t uc_flags;
- struct ucontext* uc_link;
- stack_t uc_stack;
- mcontext_t uc_mcontext;
- uint32_t uc_sigmask;
-} ucontext_t;
-
-#endif /* __BIONIC_HAVE_UCONTEXT_T */
-
-#elif defined(__APPLE__)
+#if defined(__APPLE__)
#define _XOPEN_SOURCE
#include <ucontext.h>
diff --git a/libcutils/klog.c b/libcutils/klog.c
index d69fb10..fbb7b72 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -28,6 +28,10 @@
static int klog_fd = -1;
static int klog_level = KLOG_DEFAULT_LEVEL;
+int klog_get_level(void) {
+ return klog_level;
+}
+
void klog_set_level(int level) {
klog_level = level;
}
@@ -49,18 +53,24 @@
#define LOG_BUF_MAX 512
-void klog_write(int level, const char *fmt, ...)
+void klog_vwrite(int level, const char *fmt, va_list ap)
{
char buf[LOG_BUF_MAX];
- va_list ap;
if (level > klog_level) return;
if (klog_fd < 0) klog_init();
if (klog_fd < 0) return;
- va_start(ap, fmt);
vsnprintf(buf, LOG_BUF_MAX, fmt, ap);
buf[LOG_BUF_MAX - 1] = 0;
- va_end(ap);
+
write(klog_fd, buf, strlen(buf));
}
+
+void klog_write(int level, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ klog_vwrite(level, fmt, ap);
+ va_end(ap);
+}
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 5bb8176..899a7b4 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -19,14 +19,16 @@
#define LOG_TAG "qtaguid"
-#include <cutils/qtaguid.h>
-#include <cutils/log.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
+#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include <pthread.h>
+
+#include <cutils/qtaguid.h>
+#include <log/log.h>
static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl";
static const int CTRL_MAX_INPUT_LEN = 128;
@@ -103,13 +105,13 @@
pthread_once(&resTrackInitDone, qtaguid_resTrack);
- snprintf(lineBuf, sizeof(lineBuf), "t %d %llu %d", sockfd, kTag, uid);
+ snprintf(lineBuf, sizeof(lineBuf), "t %d %" PRIu64 " %d", sockfd, kTag, uid);
- ALOGV("Tagging socket %d with tag %llx{%u,0} for uid %d", sockfd, kTag, tag, uid);
+ ALOGV("Tagging socket %d with tag %" PRIx64 "{%u,0} for uid %d", sockfd, kTag, tag, uid);
res = write_ctrl(lineBuf);
if (res < 0) {
- ALOGI("Tagging socket %d with tag %llx(%d) for uid %d failed errno=%d",
+ ALOGI("Tagging socket %d with tag %" PRIx64 "(%d) for uid %d failed errno=%d",
sockfd, kTag, tag, uid, res);
}
@@ -147,14 +149,14 @@
int fd, cnt = 0, res = 0;
uint64_t kTag = (uint64_t)tag << 32;
- ALOGV("Deleting tag data with tag %llx{%d,0} for uid %d", kTag, tag, uid);
+ ALOGV("Deleting tag data with tag %" PRIx64 "{%d,0} for uid %d", kTag, tag, uid);
pthread_once(&resTrackInitDone, qtaguid_resTrack);
- snprintf(lineBuf, sizeof(lineBuf), "d %llu %d", kTag, uid);
+ snprintf(lineBuf, sizeof(lineBuf), "d %" PRIu64 " %d", kTag, uid);
res = write_ctrl(lineBuf);
if (res < 0) {
- ALOGI("Deleteing tag data with tag %llx/%d for uid %d failed with cnt=%d errno=%d",
+ ALOGI("Deleting tag data with tag %" PRIx64 "/%d for uid %d failed with cnt=%d errno=%d",
kTag, tag, uid, cnt, errno);
}
diff --git a/libcutils/socket_local_server.c b/libcutils/socket_local_server.c
index 4971b1b..7628fe4 100644
--- a/libcutils/socket_local_server.c
+++ b/libcutils/socket_local_server.c
@@ -43,6 +43,8 @@
#define LISTEN_BACKLOG 4
+/* Only the bottom bits are really the socket type; there are flags too. */
+#define SOCK_TYPE_MASK 0xf
/**
* Binds a pre-created socket(AF_LOCAL) 's' to 'name'
@@ -107,7 +109,7 @@
return -1;
}
- if (type == SOCK_STREAM) {
+ if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
int ret;
ret = listen(s, LISTEN_BACKLOG);
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
deleted file mode 100644
index 6571161..0000000
--- a/libcutils/tests/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(all-subdir-makefiles)
diff --git a/libcutils/tests/memset_mips/Android.mk b/libcutils/tests/memset_mips/Android.mk
deleted file mode 100644
index c22fca9..0000000
--- a/libcutils/tests/memset_mips/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-
-ifeq ($(TARGET_ARCH),mips)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- test_memset.c \
- android_memset_dumb.S \
- android_memset_test.S \
- memset_cmips.S \
- memset_omips.S
-
-LOCAL_MODULE:= test_memset
-
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_STATIC_LIBRARIES := libcutils libc
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/libcutils/tests/memset_mips/android_memset_dumb.S b/libcutils/tests/memset_mips/android_memset_dumb.S
deleted file mode 100644
index c8a1a37..0000000
--- a/libcutils/tests/memset_mips/android_memset_dumb.S
+++ /dev/null
@@ -1,36 +0,0 @@
- .global android_memset16_dumb
- .type android_memset16_dumb, @function
-android_memset16_dumb:
- .ent android_memset16_dumb
-
- .set noreorder
- beqz $a2,9f
- srl $a2,1
-
-1: sh $a1,($a0)
- subu $a2,1
- bnez $a2,1b
- addu $a0,2
- .set reorder
-
-9: j $ra
- .end android_memset16_dumb
- .size android_memset16_dumb,.-android_memset16_dumb
-
- .global android_memset32_dumb
- .type android_memset32_dumb, @function
-android_memset32_dumb:
- .ent android_memset32_dumb
- .set noreorder
- beqz $a2,9f
- srl $a2,2
-
-1: sw $a1,($a0)
- subu $a2,1
- bnez $a2,1b
- addu $a0,4
- .set reorder
-
-9: j $ra
- .end android_memset32_dumb
- .size android_memset32_dumb,.-android_memset32_dumb
diff --git a/libcutils/tests/memset_mips/android_memset_test.S b/libcutils/tests/memset_mips/android_memset_test.S
deleted file mode 100644
index e918843..0000000
--- a/libcutils/tests/memset_mips/android_memset_test.S
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2006 The android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef NDEBUG
-#define DBG #
-#else
-#define DBG
-#endif
-
- .text
- .align
-
- /*
- * Optimized memset16 for MIPS
- *
- * void android_memset16_test(uint16_t* dst, uint16_t value, size_t size);
- *
- */
-
- .global android_memset16_test
- .type android_memset16_test, @function
-android_memset16_test:
- .ent android_memset16_test
- .set noreorder
-
- /* Check parameters */
-DBG andi $t0,$a0,1 /* $a0 must be halfword aligned */
-DBG tne $t0
-DBG lui $t1,0xffff /* $a1 must be 16bits */
-DBG and $t1,$a1
-DBG tne $t1
-DBG andi $t2,$a2,1 /* $a2 must be even */
-DBG tne $t2
-
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins $a2,$0,0,1
-#else
- li $t0,~1
- and $a2,$t0
-#endif
-
- move $t8,$ra
- blez $a2,9f /* Anything to do? */
- andi $t0,$a0,2 /* Check dst alignment */
- /* Expand value to 32 bits and check destination alignment */
-#if (__mips==32) && (__mips_isa_rev>=2)
- beqz $t0,.Laligned32 /* dst is 32 bit aligned */
- ins $a1,$a1,16,16
-#else
- sll $t2,$a1,16
- beqz $t0,.Laligned32 /* dst is 32 bit aligned */
- or $a1,$t2
-#endif
- sh $a1,($a0) /* do one halfword to get aligned */
- subu $a2,2
- addu $a0,2
-
-.Laligned32:
- and $t1,$a2,63 /* is there enough left to do a full 64 byte loop? */
- beq $a2,$t1,1f
- subu $t2,$a2,$t1 /* $t2 is the number of bytes to do in loop64 */
- addu $t3,$a0,$t2 /* $t3 is the end marker for loop64 */
- subu $a2,$t2
-.Lloop64:
- addu $a0,64
- sw $a1,-64($a0)
- sw $a1,-60($a0)
- sw $a1,-56($a0)
- sw $a1,-52($a0)
- sw $a1,-48($a0)
- sw $a1,-44($a0)
- sw $a1,-40($a0)
- sw $a1,-36($a0)
- sw $a1,-32($a0)
- sw $a1,-28($a0)
- sw $a1,-24($a0)
- sw $a1,-20($a0)
- sw $a1,-16($a0)
- sw $a1,-12($a0)
- sw $a1,-8($a0)
- bne $a0,$t3,.Lloop64
- sw $a1,-4($a0)
-
- /* Do the last 0..62 bytes */
-1: li $t0,64+12
- andi $t1,$a2,0x3c /* $t1 how many bytes to store using sw */
- bal 1f
- subu $t0,$t1 /* 64+12-$t0 is offset to jump from 1f */
-1: addu $ra,$t0
- j $ra
- subu $a2,$t1
-2: sw $a1,60($a0)
- sw $a1,56($a0)
- sw $a1,52($a0)
- sw $a1,48($a0)
- sw $a1,44($a0)
- sw $a1,40($a0)
- sw $a1,36($a0)
- sw $a1,32($a0)
- sw $a1,28($a0)
- sw $a1,24($a0)
- sw $a1,20($a0)
- sw $a1,16($a0)
- sw $a1,12($a0)
- sw $a1,8($a0)
- sw $a1,4($a0)
- sw $a1,0($a0)
-
- beqz $a2,9f
- addu $a0,$t1
- sh $a1,($a0)
-
-9: j $t8
- nop
- .end android_memset16_test
- .size android_memset16_test,.-android_memset16_test
-
- /*
- * Optimized memset32 for MIPS
- *
- * void android_memset32_test(uint32_t* dst, uint32_t value, size_t size);
- *
- */
- .global android_memset32_test
- .type android_memset32_test, @function
-android_memset32_test:
- .ent android_memset32_test
- .set noreorder
-
- /* Check parameters */
-DBG andi $t0,$a0,3 /* $a0 must be word aligned */
-DBG tne $t0
-DBG andi $t2,$a2,3 /* $a2 must be a multiple of 4 bytes */
-DBG tne $t2
-
- b .Laligned32
- move $t8,$ra
- .end android_memset32_test
- .size android_memset32_test,.-android_memset32_test
diff --git a/libcutils/tests/memset_mips/memset_cmips.S b/libcutils/tests/memset_mips/memset_cmips.S
deleted file mode 100644
index f8f3a91..0000000
--- a/libcutils/tests/memset_mips/memset_cmips.S
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (c) 2009
- * MIPS Technologies, Inc., California.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/************************************************************************
- *
- * memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
- * Version: "043009"
- *
- ************************************************************************/
-
-
-/************************************************************************
- * Include files
- ************************************************************************/
-
-#include "machine/asm.h"
-
-/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
- */
-
-#if defined(__MIPSEB__)
-# define SWHI swl /* high part is left in big-endian */
-#endif
-
-#if defined(__MIPSEL__)
-# define SWHI swr /* high part is right in little-endian */
-#endif
-
-#if !(defined(XGPROF) || defined(XPROF))
-#undef SETUP_GP
-#define SETUP_GP
-#endif
-
-LEAF(memset_cmips,0)
-
- .set noreorder
- .set noat
-
- addu t0,a0,a2 # t0 is the "past the end" address
- slti AT,a2,4 # is a2 less than 4?
- bne AT,zero,.Llast4 # if yes, go to last4
- move v0,a0 # memset returns the dst pointer
-
- beq a1,zero,.Lset0
- subu v1,zero,a0
-
- # smear byte into 32 bit word
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins a1, a1, 8, 8 # Replicate fill byte into half-word.
- ins a1, a1, 16, 16 # Replicate fill byte into word.
-#else
- and a1,0xff
- sll AT,a1,8
- or a1,AT
- sll AT,a1,16
- or a1,AT
-#endif
-
-.Lset0: andi v1,v1,0x3 # word-unaligned address?
- beq v1,zero,.Laligned # v1 is the unalignment count
- subu a2,a2,v1
- SWHI a1,0(a0)
- addu a0,a0,v1
-
-# Here we have the "word-aligned" a0 (until the "last4")
-.Laligned:
- andi t8,a2,0x3f # any 64-byte chunks?
- # t8 is the byte count past 64-byte chunks
- beq a2,t8,.Lchk8w # when a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk then
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
-# Find out, if there are any 64-byte chunks after which will be still at least
-# 96 bytes left. The value "96" is calculated as needed buffer for
-# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
-# incrementing "a0" by 64.
-# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
-#
- sltiu v1,a2,160
- bgtz v1,.Lloop16w_nopref30 # skip "pref 30,0(a0)"
- subu t7,a2,96 # subtract "pref 30 unsafe" region
- # below we have at least 1 64-byte chunk which is "pref 30 safe"
- andi t6,t7,0x3f # t6 is past "64-byte safe chunks" reminder
- subu t5,t7,t6 # subtract from t7 the reminder
- # Here t5 counts bytes in 16w "safe" chunks
- addu t4,a0,t5 # Now t4 is the dst after 64-byte "safe" chunks
-
-# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
-# pref 30,0(a0)
-# Here we are in the region, where it is safe to use "pref 30,64(a0)"
-.Lloop16w:
- addiu a0,a0,64
- pref 30,-32(a0) # continue setting up the dest, addr 64-32
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- nop
- nop # the extra nop instructions help to balance
- nop # cycles needed for "store" + "fill" + "evict"
- nop # For 64byte store there are needed 8 fill
- nop # and 8 evict cycles, i.e. at least 32 instr.
- nop
- nop
- pref 30,0(a0) # continue setting up the dest, addr 64-0
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- sw a1,-4(a0)
- nop
- nop
- nop
- nop # NOTE: adding 14 nop-s instead of 12 nop-s
- nop # gives better results for "fast" memory
- nop
- bne a0,t4,.Lloop16w
- nop
-
- beq a0,a3,.Lchk8w # maybe no more 64-byte chunks?
- nop # this "delayed slot" is useless ...
-
-.Lloop16w_nopref30: # there could be up to 3 "64-byte nopref30" chunks
- addiu a0,a0,64
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- bne a0,a3,.Lloop16w_nopref30
- sw a1,-4(a0)
-
-.Lchk8w: # t8 here is the byte count past 64-byte chunks
-
- andi t7,t8,0x1f # is there a 32-byte chunk?
- # the t7 is the reminder count past 32-bytes
- beq t8,t7,.Lchk1w # when t8==t7, no 32-byte chunk
- move a2,t7
-
- sw a1,0(a0)
- sw a1,4(a0)
- sw a1,8(a0)
- sw a1,12(a0)
- sw a1,16(a0)
- sw a1,20(a0)
- sw a1,24(a0)
- sw a1,28(a0)
- addiu a0,a0,32
-
-.Lchk1w:
- andi t8,a2,0x3 # now t8 is the reminder past 1w chunks
- beq a2,t8,.Llast4
- subu a3,a2,t8 # a3 is the count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
- addiu a0,a0,4
- bne a0,a3,.LwordCopy_loop
- sw a1,-4(a0)
-
-.Llast4:beq a0,t0,.Llast4e
-.Llast4l:addiu a0,a0,1
- bne a0,t0,.Llast4l
- sb a1,-1(a0)
-
-.Llast4e:
- j ra
- nop
-
- .set at
- .set reorder
-
-END(memset_cmips)
-
-
-/************************************************************************
- * Implementation : Static functions
- ************************************************************************/
-
diff --git a/libcutils/tests/memset_mips/memset_omips.S b/libcutils/tests/memset_mips/memset_omips.S
deleted file mode 100644
index 4c47001..0000000
--- a/libcutils/tests/memset_mips/memset_omips.S
+++ /dev/null
@@ -1,90 +0,0 @@
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
-
-/* void *memset_omips(void *s, int c, size_t n). */
-
-#include "machine/asm.h"
-
-#ifdef __mips64
-#error mips32 code being compiled for mips64!
-#endif
-
-#if defined(__MIPSEB__)
-#error big-endian is not supported in Broadcom MIPS Android platform
-# define SWHI swl /* high part is left in big-endian */
-#else
-# define SWHI swr /* high part is right in little-endian */
-#endif
-
-LEAF (memset_omips,0)
- .set noreorder
-
- slti t1, a2, 8 # Less than 8?
- bne t1, zero, .Llast8
- move v0, a0 # Setup exit value before too late
-
- beq a1, zero, .Lueven # If zero pattern, no need to extend
- andi a1, 0xff # Avoid problems with bogus arguments
- sll t0, a1, 8
- or a1, t0
- sll t0, a1, 16
- or a1, t0 # a1 is now pattern in full word
-
-.Lueven:
- subu t0, zero, a0 # Unaligned address?
- andi t0, 0x3
- beq t0, zero, .Lchkw
- subu a2, t0
- SWHI a1, 0(a0) # Yes, handle first unaligned part
- addu a0, t0 # Now both a0 and a2 are updated
-
-.Lchkw:
- andi t0, a2, 0x7 # Enough left for one loop iteration?
- beq t0, a2, .Lchkl
- subu a3, a2, t0
- addu a3, a0 # a3 is last loop address +1
- move a2, t0 # a2 is now # of bytes left after loop
-.Lloopw:
- addiu a0, 8 # Handle 2 words pr. iteration
- sw a1, -8(a0)
- bne a0, a3, .Lloopw
- sw a1, -4(a0)
-
-.Lchkl:
- andi t0, a2, 0x4 # Check if there is at least a full
- beq t0, zero, .Llast8 # word remaining after the loop
- subu a2, t0
- sw a1, 0(a0) # Yes...
- addiu a0, 4
-
-.Llast8:
- blez a2, .Lexit # Handle last 8 bytes (if cnt>0)
- addu a3, a2, a0 # a3 is last address +1
-.Llst8l:
- addiu a0, 1
- bne a0, a3, .Llst8l
- sb a1, -1(a0)
-.Lexit:
- j ra # Bye, bye
- nop
-
- .set reorder
-END (memset_omips)
-
-
diff --git a/libcutils/tests/memset_mips/test_memset.c b/libcutils/tests/memset_mips/test_memset.c
deleted file mode 100644
index 9705c65..0000000
--- a/libcutils/tests/memset_mips/test_memset.c
+++ /dev/null
@@ -1,235 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <cutils/memory.h>
-#include <time.h>
-
-/*
- * All systems must implement or emulate the rdhwr instruction to read
- * the userlocal register. Systems that emulate also return teh count register
- * when accessing register $2 so this should work on most systems
- */
-#define USE_RDHWR
-
-#ifdef USE_RDHWR
-#define UNITS "cycles"
-#define SCALE 2 /* Most CPU's */
-static inline uint32_t
-get_count(void)
-{
- uint32_t res;
- asm volatile (".set push; .set mips32r2; rdhwr %[res],$2; .set pop" : [res] "=r" (res) : : "memory");
- return res;
-}
-#else
-#define UNITS "ns"
-#define SCALE 1
-static inline uint32_t
-get_count(void)
-{
- struct timespec now;
- uint32_t res;
- clock_gettime(CLOCK_REALTIME, &now);
- res = (uint32_t)(now.tv_sec * 1000000000LL + now.tv_nsec);
- // printf ("now=%d.%09d res=%d\n", (int)now.tv_sec, (int)now.tv_nsec, res);
- return res;
-}
-#endif
-
-uint32_t overhead;
-void
-measure_overhead(void)
-{
- int i;
- uint32_t start, stop, delta;
- for (i = 0; i < 32; i++) {
- start = get_count();
- stop = get_count();
- delta = stop - start;
- if (overhead == 0 || delta < overhead)
- overhead = delta;
- }
- printf("overhead is %d"UNITS"\n", overhead);
-}
-
-uint32_t
-timeone(void (*fn)(), void *d, uint32_t val, uint32_t bytes)
-{
- uint32_t start, stop, delta;
- start = get_count();
- (*fn)(d, val, bytes);
- stop = get_count();
- delta = stop - start - overhead;
- // printf ("start=0x%08x stop=0x%08x delta=0x%08x\n", start, stop, delta);
- return delta * SCALE;
-}
-
-/* define VERIFY to check that memset only touches the bytes it's supposed to */
-/*#define VERIFY*/
-
-/*
- * Using a big arena means that memset will most likely miss in the cache
- * NB Enabling verification effectively warms up the cache...
- */
-#define ARENASIZE 0x1000000
-#ifdef VERIFY
-char arena[ARENASIZE+8]; /* Allow space for guard words */
-#else
-char arena[ARENASIZE];
-#endif
-
-void
-testone(char *tag, void (*fn)(), int trials, int minbytes, int maxbytes, int size, int threshold)
-{
- int offset;
- void *d;
- void *p;
- uint32_t v, notv = 0;
- uint32_t n;
- int i, units;
- int totalunits = 0, totalbytes = 0, samples = 0;
-
- /* Reset RNG to ensure each test uses same random values */
- srand(0); /* FIXME should be able to use some other seed than 0 */
-
- for (i = 0; i < trials; i++) {
- n = minbytes + (rand() % (maxbytes-minbytes)); /* How many bytes to do */
- offset = ((rand() % (ARENASIZE-n))); /* Where to start */
-
-#ifdef VERIFY
- offset += 4; /* Allow space for guard word at beginning */
-#endif
- v = rand();
-
- /* Adjust alignment and sizes based on transfer size */
- switch (size) {
- case 1:
- v &= 0xff;
- notv = ~v & 0xff;
- break;
- case 2:
- v &= 0xffff;
- notv = ~v & 0xffff;
- offset &= ~1;
- n &= ~1;
- break;
- case 4:
- notv = ~v;
- offset &= ~3;
- n &= ~3;
- break;
- }
-
- d = &arena[offset];
-
-#ifdef VERIFY
- /* Initialise the area and guard words */
- for (p = &arena[offset-4]; p < (void *)&arena[offset+n+4]; p = (void *)((uint32_t)p + size)) {
- if (size == 1)
- *(uint8_t *)p = notv;
- else if (size == 2)
- *(uint16_t *)p = notv;
- else if (size == 4)
- *(uint32_t *)p = notv;
- }
-#endif
- units = timeone(fn, d, v, n);
-#ifdef VERIFY
- /* Check the area and guard words */
- for (p = &arena[offset-4]; p < (void *)&arena[offset+n+4]; p = (void *)((uint32_t)p + size)) {
- uint32_t got = 0;
- if (size == 1)
- got = *(uint8_t *)p;
- else if (size == 2)
- got = *(uint16_t *)p;
- else if (size == 4)
- got = *(uint32_t *)p;
- if (p < (void *)&arena[offset]) {
- if (got != notv)
- printf ("%s: verify failure: preguard:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, got, n);
- }
- else if (p < (void *)&arena[offset+n]) {
- if (got != v)
- printf ("%s: verify failure: arena:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, n);
- }
- else {
- if (got != notv)
- printf ("%s: verify failure: postguard:%p d=%p v=%08x got=%08x n=%d\n", tag, p, d, v, n);
- }
- }
-#endif
-
- /* If the cycle count looks reasonable include it in the statistics */
- if (units < threshold) {
- totalbytes += n;
- totalunits += units;
- samples++;
- }
- }
-
- printf("%s: samples=%d avglen=%d avg" UNITS "=%d bp"UNITS"=%g\n",
- tag, samples, totalbytes/samples, totalunits/samples, (double)totalbytes/(double)totalunits);
-}
-
-extern void android_memset32_dumb(uint32_t* dst, uint32_t value, size_t size);
-extern void android_memset16_dumb(uint32_t* dst, uint16_t value, size_t size);
-extern void android_memset32_test(uint32_t* dst, uint32_t value, size_t size);
-extern void android_memset16_test(uint32_t* dst, uint16_t value, size_t size);
-extern void memset_cmips(void* dst, int value, size_t size);
-extern void memset_omips(void* dst, int value, size_t size);
-
-int
-main(int argc, char **argv)
-{
- int i;
- struct {
- char *type;
- int trials;
- int minbytes, maxbytes;
- } *pp, params[] = {
- {"small", 10000, 0, 64},
- {"medium", 10000, 64, 512},
- {"large", 10000, 512, 1280},
- {"varied", 10000, 0, 1280},
- };
-#define NPARAMS (sizeof(params)/sizeof(params[0]))
- struct {
- char *name;
- void (*fn)();
- int size;
- } *fp, functions[] = {
- {"dmemset16", (void (*)())android_memset16_dumb, 2},
- {"tmemset16", (void (*)())android_memset16_test, 2},
- {"lmemset16", (void (*)())android_memset16, 2},
-
- {"dmemset32", (void (*)())android_memset32_dumb, 4},
- {"tmemset32", (void (*)())android_memset32_test, 4},
- {"lmemset32", (void (*)())android_memset32, 4},
-
- {"cmemset", (void (*)())memset_cmips, 1},
- {"omemset", (void (*)())memset_omips, 1},
- {"lmemset", (void (*)())memset, 1},
- };
-#define NFUNCTIONS (sizeof(functions)/sizeof(functions[0]))
- char tag[40];
- int threshold;
-
- measure_overhead();
-
- /* Warm up the page cache */
- memset(arena, 0xff, ARENASIZE); /* use 0xff now to avoid COW later */
-
- for (fp = functions; fp < &functions[NFUNCTIONS]; fp++) {
- (fp->fn)(arena, 0xffffffff, ARENASIZE); /* one call to get the code into Icache */
- for (pp = params; pp < ¶ms[NPARAMS]; pp++) {
- sprintf(tag, "%10s: %7s %4d-%4d", fp->name, pp->type, pp->minbytes, pp->maxbytes);
-
- /* Set the cycle threshold */
- threshold = pp->maxbytes * 4 * 10; /* reasonable for cycles and ns */
- testone(tag, fp->fn, pp->trials, pp->minbytes, pp->maxbytes, fp->size, threshold);
- }
- printf ("\n");
- }
-
- return 0;
-}
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 0d6c970..4fe20db 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -16,7 +16,15 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
+ifneq ($(TARGET_USES_LOGD),false)
liblog_sources := logd_write.c
+else
+liblog_sources := logd_write_kern.c
+endif
+
+ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
+liblog_cflags := -DUSERDEBUG_BUILD=1
+endif
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
@@ -42,7 +50,11 @@
endif
liblog_host_sources := $(liblog_sources) fake_log_device.c
+ifneq ($(TARGET_USES_LOGD),false)
liblog_target_sources = $(liblog_sources) log_read.c
+else
+liblog_target_sources = $(liblog_sources) log_read_kern.c
+endif
# Shared and static library for host
# ========================================================
@@ -72,11 +84,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_target_sources)
+LOCAL_CFLAGS := $(liblog_cflags)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_WHOLE_STATIC_LIBRARIES := liblog
+LOCAL_CFLAGS := $(liblog_cflags)
include $(BUILD_SHARED_LIBRARY)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 47aa711..e4acac2 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -14,37 +14,176 @@
** limitations under the License.
*/
-#define _GNU_SOURCE /* asprintf for x86 host */
#include <errno.h>
#include <fcntl.h>
-#include <poll.h>
-#include <string.h>
-#include <stdio.h>
+#include <signal.h>
+#include <stddef.h>
+#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
#include <cutils/list.h>
+#include <cutils/sockets.h>
#include <log/log.h>
#include <log/logger.h>
-#include <sys/ioctl.h>
+/* branchless on many architectures. */
+#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
-#define __LOGGERIO 0xAE
+#define WEAK __attribute__((weak))
+#define UNUSED __attribute__((unused))
-#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
-#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
-#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
+/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
-typedef char bool;
-#define false (const bool)0
-#define true (const bool)1
+#ifdef HAVE_WINSOCK
-#define LOG_FILE_DIR "/dev/log/"
+int WEAK socket_local_client(const char *name, int namespaceId, int type)
+{
+ errno = ENOSYS;
+ return -ENOSYS;
+}
-/* timeout in milliseconds */
-#define LOG_TIMEOUT_FLUSH 5
-#define LOG_TIMEOUT_NEVER -1
+#else /* !HAVE_WINSOCK */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <sys/types.h>
+
+/* Private copy of ../libcutils/socket_local.h prevent library loops */
+#define FILESYSTEM_SOCKET_PREFIX "/tmp/"
+#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
+/* End of ../libcutils/socket_local.h */
+
+#define LISTEN_BACKLOG 4
+
+/* Documented in header file. */
+int WEAK socket_make_sockaddr_un(const char *name, int namespaceId,
+ struct sockaddr_un *p_addr, socklen_t *alen)
+{
+ memset (p_addr, 0, sizeof (*p_addr));
+ size_t namelen;
+
+ switch (namespaceId) {
+ case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
+#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE
+ namelen = strlen(name);
+
+ /* Test with length +1 for the *initial* '\0'. */
+ if ((namelen + 1) > sizeof(p_addr->sun_path)) {
+ goto error;
+ }
+
+ /*
+ * Note: The path in this case is *not* supposed to be
+ * '\0'-terminated. ("man 7 unix" for the gory details.)
+ */
+
+ p_addr->sun_path[0] = 0;
+ memcpy(p_addr->sun_path + 1, name, namelen);
+#else /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+ /* this OS doesn't have the Linux abstract namespace */
+
+ namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+#endif /*HAVE_LINUX_LOCAL_SOCKET_NAMESPACE*/
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_RESERVED:
+ namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
+ strcat(p_addr->sun_path, name);
+ break;
+
+ case ANDROID_SOCKET_NAMESPACE_FILESYSTEM:
+ namelen = strlen(name);
+ /* unix_path_max appears to be missing on linux */
+ if (namelen > sizeof(*p_addr)
+ - offsetof(struct sockaddr_un, sun_path) - 1) {
+ goto error;
+ }
+
+ strcpy(p_addr->sun_path, name);
+ break;
+
+ default:
+ /* invalid namespace id */
+ return -1;
+ }
+
+ p_addr->sun_family = AF_LOCAL;
+ *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
+ return 0;
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name" on fd
+ * returns same fd or -1 on error.
+ * fd is not closed on error. that's your job.
+ *
+ * Used by AndroidSocketImpl
+ */
+int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId,
+ int type UNUSED)
+{
+ struct sockaddr_un addr;
+ socklen_t alen;
+ size_t namelen;
+ int err;
+
+ err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
+
+ if (err < 0) {
+ goto error;
+ }
+
+ if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
+ goto error;
+ }
+
+ return fd;
+
+error:
+ return -1;
+}
+
+/**
+ * connect to peer named "name"
+ * returns fd or -1 on error
+ */
+int WEAK socket_local_client(const char *name, int namespaceId, int type)
+{
+ int s;
+
+ s = socket(AF_LOCAL, type, 0);
+ if(s < 0) return -1;
+
+ if ( 0 > socket_local_client_connect(s, name, namespaceId, type)) {
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+#endif /* !HAVE_WINSOCK */
+/* End of ../libcutils/socket_local_client.c */
#define logger_for_each(logger, logger_list) \
for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
@@ -59,44 +198,17 @@
[LOG_ID_SYSTEM] = "system"
};
-const char *android_log_id_to_name(log_id_t log_id) {
+const char *android_log_id_to_name(log_id_t log_id)
+{
if (log_id >= LOG_ID_MAX) {
log_id = LOG_ID_MAIN;
}
return LOG_NAME[log_id];
}
-static int accessmode(int mode)
+log_id_t android_name_to_log_id(const char *logName)
{
- if ((mode & O_ACCMODE) == O_WRONLY) {
- return W_OK;
- }
- if ((mode & O_ACCMODE) == O_RDWR) {
- return R_OK | W_OK;
- }
- return R_OK;
-}
-
-/* repeated fragment */
-static int check_allocate_accessible(char **n, const char *b, int mode)
-{
- *n = NULL;
-
- if (!b) {
- return -EINVAL;
- }
-
- asprintf(n, LOG_FILE_DIR "%s", b);
- if (!*n) {
- return -1;
- }
-
- return access(*n, accessmode(mode));
-}
-
-log_id_t android_name_to_log_id(const char *logName) {
const char *b;
- char *n;
int ret;
if (!logName) {
@@ -109,12 +221,6 @@
++b;
}
- ret = check_allocate_accessible(&n, b, O_RDONLY);
- free(n);
- if (ret) {
- return ret;
- }
-
for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
const char *l = LOG_NAME[ret];
if (l && !strcmp(b, l)) {
@@ -129,26 +235,13 @@
int mode;
unsigned int tail;
pid_t pid;
- unsigned int queued_lines;
- int timeout_ms;
- int error;
- bool flush;
- bool valid_entry; /* valiant(?) effort to deal with memory starvation */
- struct log_msg entry;
-};
-
-struct log_list {
- struct listnode node;
- struct log_msg entry; /* Truncated to event->len() + 1 to save space */
+ int sock;
};
struct logger {
struct listnode node;
struct logger_list *top;
- int fd;
log_id_t id;
- short *revents;
- struct listnode log_list;
};
/* android_logger_alloc unimplemented, no use case */
@@ -159,93 +252,182 @@
return;
}
- while (!list_empty(&logger->log_list)) {
- struct log_list *entry = node_to_item(
- list_head(&logger->log_list), struct log_list, node);
- list_remove(&entry->node);
- free(entry);
- if (logger->top->queued_lines) {
- logger->top->queued_lines--;
- }
- }
-
- if (logger->fd >= 0) {
- close(logger->fd);
- }
-
list_remove(&logger->node);
free(logger);
}
+/* android_logger_alloc unimplemented, no use case */
+
+/* method for getting the associated sublog id */
log_id_t android_logger_get_id(struct logger *logger)
{
return logger->id;
}
/* worker for sending the command to the logger */
-static int logger_ioctl(struct logger *logger, int cmd, int mode)
+static ssize_t send_log_msg(struct logger *logger,
+ const char *msg, char *buf, size_t buf_size)
{
- char *n;
- int f, ret;
-
- if (!logger || !logger->top) {
- return -EFAULT;
+ ssize_t ret;
+ int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (sock < 0) {
+ ret = sock;
+ goto done;
}
- if (((mode & O_ACCMODE) == O_RDWR)
- || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
- return ioctl(logger->fd, cmd);
+ if (msg) {
+ snprintf(buf, buf_size, msg, logger ? logger->id : (unsigned) -1);
}
- /* We go here if android_logger_list_open got mode wrong for this ioctl */
- ret = check_allocate_accessible(&n, android_log_id_to_name(logger->id), mode);
- if (ret) {
- free(n);
+ ret = write(sock, buf, strlen(buf) + 1);
+ if (ret <= 0) {
+ goto done;
+ }
+
+ ret = read(sock, buf, buf_size);
+
+done:
+ if ((ret == -1) && errno) {
+ ret = -errno;
+ }
+ close(sock);
+ return ret;
+}
+
+static int check_log_success(char *buf, ssize_t ret)
+{
+ if (ret < 0) {
return ret;
}
- f = open(n, mode);
- free(n);
- if (f < 0) {
- return f;
+ if (strncmp(buf, "success", 7)) {
+ return -1;
}
- ret = ioctl(f, cmd);
- close (f);
-
- return ret;
+ return 0;
}
int android_logger_clear(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+ char buf[512];
+
+ return check_log_success(buf,
+ send_log_msg(logger, "clear %d", buf, sizeof(buf)));
}
/* returns the total size of the log's ring buffer */
-int android_logger_get_log_size(struct logger *logger)
+long android_logger_get_log_size(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+ char buf[512];
+
+ ssize_t ret = send_log_msg(logger, "getLogSize %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
+
+ return atol(buf);
}
+#ifdef USERDEBUG_BUILD
+
+int android_logger_set_log_size(struct logger *logger, unsigned long size)
+{
+ char buf[512];
+
+ snprintf(buf, sizeof(buf), "setLogSize %d %lu",
+ logger ? logger->id : (unsigned) -1, size);
+
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
+}
+
+#endif /* USERDEBUG_BUILD */
+
/*
* returns the readable size of the log's ring buffer (that is, amount of the
* log consumed)
*/
-int android_logger_get_log_readable_size(struct logger *logger)
+long android_logger_get_log_readable_size(struct logger *logger)
{
- return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+ char buf[512];
+
+ ssize_t ret = send_log_msg(logger, "getLogSizeUsed %d", buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if ((buf[0] < '0') || ('9' < buf[0])) {
+ return -1;
+ }
+
+ return atol(buf);
}
/*
* returns the logger version
*/
-int android_logger_get_log_version(struct logger *logger)
+int android_logger_get_log_version(struct logger *logger UNUSED)
{
- int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
- return (ret < 0) ? 1 : ret;
+ return 3;
}
+/*
+ * returns statistics
+ */
+ssize_t android_logger_get_statistics(struct logger_list *logger_list,
+ char *buf, size_t len)
+{
+ struct listnode *node;
+ struct logger *logger;
+ char *cp = buf;
+ size_t remaining = len;
+ size_t n;
+
+ n = snprintf(cp, remaining, "getStatistics");
+ n = min(n, remaining);
+ remaining -= n;
+ cp += n;
+
+ logger_for_each(logger, logger_list) {
+ n = snprintf(cp, remaining, " %d", logger->id);
+ n = min(n, remaining);
+ remaining -= n;
+ cp += n;
+ }
+ return send_log_msg(NULL, NULL, buf, len);
+}
+
+#ifdef USERDEBUG_BUILD
+
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
+ char *buf, size_t len)
+{
+ return send_log_msg(NULL, "getPruneList", buf, len);
+}
+
+int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
+ char *buf, size_t len)
+{
+ const char cmd[] = "setPruneList ";
+ const size_t cmdlen = sizeof(cmd) - 1;
+
+ if (strlen(buf) > (len - cmdlen)) {
+ return -ENOMEM; /* KISS */
+ }
+ memmove(buf + cmdlen, buf, len - cmdlen);
+ buf[len - 1] = '\0';
+ memcpy(buf, cmd, cmdlen);
+
+ return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
+}
+
+#endif /* USERDEBUG_BUILD */
+
struct logger_list *android_logger_list_alloc(int mode,
unsigned int tail,
pid_t pid)
@@ -256,10 +438,13 @@
if (!logger_list) {
return NULL;
}
+
list_init(&logger_list->node);
logger_list->mode = mode;
logger_list->tail = tail;
logger_list->pid = pid;
+ logger_list->sock = -1;
+
return logger_list;
}
@@ -289,28 +474,11 @@
goto err;
}
- if (check_allocate_accessible(&n, android_log_id_to_name(id),
- logger_list->mode)) {
- goto err_name;
- }
-
- logger->fd = open(n, logger_list->mode);
- if (logger->fd < 0) {
- goto err_name;
- }
-
- free(n);
logger->id = id;
- list_init(&logger->log_list);
list_add_tail(&logger_list->node, &logger->node);
logger->top = logger_list;
- logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
goto ok;
-err_name:
- free(n);
-err_logger:
- free(logger);
err:
logger = NULL;
ok:
@@ -336,315 +504,137 @@
return logger_list;
}
-/* prevent memory starvation when backfilling */
-static unsigned int queue_threshold(struct logger_list *logger_list)
+static void caught_signal(int signum UNUSED)
{
- return (logger_list->tail < 64) ? 64 : logger_list->tail;
-}
-
-static bool low_queue(struct listnode *node)
-{
- /* low is considered less than 2 */
- return list_head(node) == list_tail(node);
-}
-
-/* Flush queues in sequential order, one at a time */
-static int android_logger_list_flush(struct logger_list *logger_list,
- struct log_msg *log_msg)
-{
- int ret = 0;
- struct log_list *firstentry = NULL;
-
- while ((ret == 0)
- && (logger_list->flush
- || (logger_list->queued_lines > logger_list->tail))) {
- struct logger *logger;
-
- /* Merge sort */
- bool at_least_one_is_low = false;
- struct logger *firstlogger = NULL;
- firstentry = NULL;
-
- logger_for_each(logger, logger_list) {
- struct listnode *node;
- struct log_list *oldest = NULL;
-
- /* kernel logger channels not necessarily time-sort order */
- list_for_each(node, &logger->log_list) {
- struct log_list *entry = node_to_item(node,
- struct log_list, node);
- if (!oldest
- || (entry->entry.entry.sec < oldest->entry.entry.sec)
- || ((entry->entry.entry.sec == oldest->entry.entry.sec)
- && (entry->entry.entry.nsec < oldest->entry.entry.nsec))) {
- oldest = entry;
- }
- }
-
- if (!oldest) {
- at_least_one_is_low = true;
- continue;
- } else if (low_queue(&logger->log_list)) {
- at_least_one_is_low = true;
- }
-
- if (!firstentry
- || (oldest->entry.entry.sec < firstentry->entry.entry.sec)
- || ((oldest->entry.entry.sec == firstentry->entry.entry.sec)
- && (oldest->entry.entry.nsec < firstentry->entry.entry.nsec))) {
- firstentry = oldest;
- firstlogger = logger;
- }
- }
-
- if (!firstentry) {
- break;
- }
-
- /* when trimming list, tries to keep one entry behind in each bucket */
- if (!logger_list->flush
- && at_least_one_is_low
- && (logger_list->queued_lines < queue_threshold(logger_list))) {
- break;
- }
-
- /* within tail?, send! */
- if ((logger_list->tail == 0)
- || (logger_list->queued_lines <= logger_list->tail)) {
- ret = firstentry->entry.entry.hdr_size;
- if (!ret) {
- ret = sizeof(firstentry->entry.entry_v1);
- }
- ret += firstentry->entry.entry.len;
-
- memcpy(log_msg->buf, firstentry->entry.buf, ret + 1);
- log_msg->extra.id = firstlogger->id;
- }
-
- /* next entry */
- list_remove(&firstentry->node);
- free(firstentry);
- if (logger_list->queued_lines) {
- logger_list->queued_lines--;
- }
- }
-
- /* Flushed the list, no longer in tail mode for continuing content */
- if (logger_list->flush && !firstentry) {
- logger_list->tail = 0;
- }
- return ret;
}
/* Read from the selected logs */
int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
{
+ int ret, e;
struct logger *logger;
- nfds_t nfds;
- struct pollfd *p, *pollfds = NULL;
- int error = 0, ret = 0;
-
- memset(log_msg, 0, sizeof(struct log_msg));
+ struct sigaction ignore;
+ struct sigaction old_sigaction;
+ unsigned int old_alarm = 0;
if (!logger_list) {
- return -ENODEV;
+ return -EINVAL;
}
- if (!(accessmode(logger_list->mode) & R_OK)) {
- logger_list->error = EPERM;
- goto done;
+ if (logger_list->mode & O_NONBLOCK) {
+ memset(&ignore, 0, sizeof(ignore));
+ ignore.sa_handler = caught_signal;
+ sigemptyset(&ignore.sa_mask);
}
- nfds = 0;
- logger_for_each(logger, logger_list) {
- ++nfds;
- }
- if (nfds <= 0) {
- error = ENODEV;
- goto done;
- }
+ if (logger_list->sock < 0) {
+ char buffer[256], *cp, c;
- /* Do we have anything to offer from the buffer or state? */
- if (logger_list->valid_entry) { /* implies we are also in a flush state */
- goto flush;
- }
-
- ret = android_logger_list_flush(logger_list, log_msg);
- if (ret) {
- goto done;
- }
-
- if (logger_list->error) { /* implies we are also in a flush state */
- goto done;
- }
-
- /* Lets start grinding on metal */
- pollfds = calloc(nfds, sizeof(struct pollfd));
- if (!pollfds) {
- error = ENOMEM;
- goto flush;
- }
-
- p = pollfds;
- logger_for_each(logger, logger_list) {
- p->fd = logger->fd;
- p->events = POLLIN;
- logger->revents = &p->revents;
- ++p;
- }
-
- while (!ret && !error) {
- int result;
-
- /* If we oversleep it's ok, i.e. ignore EINTR. */
- result = TEMP_FAILURE_RETRY(
- poll(pollfds, nfds, logger_list->timeout_ms));
-
- if (result <= 0) {
- if (result) {
- error = errno;
- } else if (logger_list->mode & O_NDELAY) {
- error = EAGAIN;
- } else {
- logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
+ int sock = socket_local_client("logdr",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_SEQPACKET);
+ if (sock < 0) {
+ if ((sock == -1) && errno) {
+ return -errno;
}
-
- logger_list->flush = true;
- goto try_flush;
+ return sock;
}
- logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+ strcpy(buffer,
+ (logger_list->mode & O_NONBLOCK) ? "dumpAndClose" : "stream");
+ cp = buffer + strlen(buffer);
- /* Anti starvation */
- if (!logger_list->flush
- && (logger_list->queued_lines > (queue_threshold(logger_list) / 2))) {
- /* Any queues with input pending that is low? */
- bool starving = false;
- logger_for_each(logger, logger_list) {
- if ((*(logger->revents) & POLLIN)
- && low_queue(&logger->log_list)) {
- starving = true;
- break;
- }
- }
-
- /* pushback on any queues that are not low */
- if (starving) {
- logger_for_each(logger, logger_list) {
- if ((*(logger->revents) & POLLIN)
- && !low_queue(&logger->log_list)) {
- *(logger->revents) &= ~POLLIN;
- }
- }
- }
- }
-
+ strcpy(cp, " lids");
+ cp += 5;
+ c = '=';
+ int remaining = sizeof(buffer) - (cp - buffer);
logger_for_each(logger, logger_list) {
- unsigned int hdr_size;
- struct log_list *entry;
+ ret = snprintf(cp, remaining, "%c%u", c, logger->id);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ c = ',';
+ }
- if (!(*(logger->revents) & POLLIN)) {
- continue;
+ if (logger_list->tail) {
+ ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+
+ if (logger_list->pid) {
+ ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
+ ret = min(ret, remaining);
+ remaining -= ret;
+ cp += ret;
+ }
+
+ if (logger_list->mode & O_NONBLOCK) {
+ /* Deal with an unresponsive logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+ ret = write(sock, buffer, cp - buffer);
+ e = errno;
+ if (logger_list->mode & O_NONBLOCK) {
+ if (e == EINTR) {
+ e = ETIMEDOUT;
}
-
- memset(logger_list->entry.buf, 0, sizeof(struct log_msg));
- /* NOTE: driver guarantees we read exactly one full entry */
- result = read(logger->fd, logger_list->entry.buf,
- LOGGER_ENTRY_MAX_LEN);
- if (result <= 0) {
- if (!result) {
- error = EIO;
- } else if (errno != EINTR) {
- error = errno;
- }
- continue;
- }
-
- if (logger_list->pid
- && (logger_list->pid != logger_list->entry.entry.pid)) {
- continue;
- }
-
- hdr_size = logger_list->entry.entry.hdr_size;
- if (!hdr_size) {
- hdr_size = sizeof(logger_list->entry.entry_v1);
- }
-
- if ((hdr_size > sizeof(struct log_msg))
- || (logger_list->entry.entry.len
- > sizeof(logger_list->entry.buf) - hdr_size)
- || (logger_list->entry.entry.len != result - hdr_size)) {
- error = EINVAL;
- continue;
- }
-
- logger_list->entry.extra.id = logger->id;
-
- /* speedup: If not tail, and only one list, send directly */
- if (!logger_list->tail
- && (list_head(&logger_list->node)
- == list_tail(&logger_list->node))) {
- ret = result;
- memcpy(log_msg->buf, logger_list->entry.buf, result + 1);
- log_msg->extra.id = logger->id;
- break;
- }
-
- entry = malloc(sizeof(*entry) - sizeof(entry->entry) + result + 1);
-
- if (!entry) {
- logger_list->valid_entry = true;
- error = ENOMEM;
- break;
- }
-
- logger_list->queued_lines++;
-
- memcpy(entry->entry.buf, logger_list->entry.buf, result);
- entry->entry.buf[result] = '\0';
- list_add_tail(&logger->log_list, &entry->node);
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
}
if (ret <= 0) {
-try_flush:
- ret = android_logger_list_flush(logger_list, log_msg);
- }
- }
-
- free(pollfds);
-
-flush:
- if (error) {
- logger_list->flush = true;
- }
-
- if (ret <= 0) {
- ret = android_logger_list_flush(logger_list, log_msg);
-
- if (!ret && logger_list->valid_entry) {
- ret = logger_list->entry.entry.hdr_size;
- if (!ret) {
- ret = sizeof(logger_list->entry.entry_v1);
+ close(sock);
+ if ((ret == -1) && e) {
+ return -e;
}
- ret += logger_list->entry.entry.len;
-
- memcpy(log_msg->buf, logger_list->entry.buf,
- sizeof(struct log_msg));
- logger_list->valid_entry = false;
+ if (ret == 0) {
+ return -EIO;
+ }
+ return ret;
}
+
+ logger_list->sock = sock;
}
-done:
- if (logger_list->error) {
- error = logger_list->error;
- }
- if (error) {
- logger_list->error = error;
- if (!ret) {
- ret = -error;
+ ret = 0;
+ while(1) {
+ memset(log_msg, 0, sizeof(*log_msg));
+
+ if (logger_list->mode & O_NONBLOCK) {
+ /* particularily useful if tombstone is reporting for logd */
+ sigaction(SIGALRM, &ignore, &old_sigaction);
+ old_alarm = alarm(30);
+ }
+ /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
+ ret = recv(logger_list->sock, log_msg, LOGGER_ENTRY_MAX_LEN, 0);
+ e = errno;
+ if (logger_list->mode & O_NONBLOCK) {
+ if ((ret == 0) || (e == EINTR)) {
+ e = EAGAIN;
+ ret = -1;
+ }
+ alarm(old_alarm);
+ sigaction(SIGALRM, &old_sigaction, NULL);
+ }
+
+ if (ret <= 0) {
+ if ((ret == -1) && e) {
+ return -e;
+ }
+ return ret;
+ }
+
+ logger_for_each(logger, logger_list) {
+ if (log_msg->entry.lid == logger->id) {
+ return ret;
+ }
}
}
+ /* NOTREACH */
return ret;
}
@@ -661,5 +651,9 @@
android_logger_free(logger);
}
+ if (logger_list->sock >= 0) {
+ close (logger_list->sock);
+ }
+
free(logger_list);
}
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
new file mode 100644
index 0000000..483b6b6
--- /dev/null
+++ b/liblog/log_read_kern.c
@@ -0,0 +1,738 @@
+/*
+** Copyright 2013-2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define _GNU_SOURCE /* asprintf for x86 host */
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cutils/list.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+#include <sys/ioctl.h>
+
+#define __LOGGERIO 0xAE
+
+#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
+#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
+#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
+#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
+#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
+#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
+
+typedef char bool;
+#define false (const bool)0
+#define true (const bool)1
+
+#define LOG_FILE_DIR "/dev/log/"
+
+/* timeout in milliseconds */
+#define LOG_TIMEOUT_FLUSH 5
+#define LOG_TIMEOUT_NEVER -1
+
+#define logger_for_each(logger, logger_list) \
+ for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
+ logger != node_to_item(&(logger_list)->node, struct logger, node); \
+ logger = node_to_item((logger)->node.next, struct logger, node))
+
+#define UNUSED __attribute__((unused))
+
+/* In the future, we would like to make this list extensible */
+static const char *LOG_NAME[LOG_ID_MAX] = {
+ [LOG_ID_MAIN] = "main",
+ [LOG_ID_RADIO] = "radio",
+ [LOG_ID_EVENTS] = "events",
+ [LOG_ID_SYSTEM] = "system"
+};
+
+const char *android_log_id_to_name(log_id_t log_id)
+{
+ if (log_id >= LOG_ID_MAX) {
+ log_id = LOG_ID_MAIN;
+ }
+ return LOG_NAME[log_id];
+}
+
+static int accessmode(int mode)
+{
+ if ((mode & O_ACCMODE) == O_WRONLY) {
+ return W_OK;
+ }
+ if ((mode & O_ACCMODE) == O_RDWR) {
+ return R_OK | W_OK;
+ }
+ return R_OK;
+}
+
+/* repeated fragment */
+static int check_allocate_accessible(char **n, const char *b, int mode)
+{
+ *n = NULL;
+
+ if (!b) {
+ return -EINVAL;
+ }
+
+ asprintf(n, LOG_FILE_DIR "%s", b);
+ if (!*n) {
+ return -1;
+ }
+
+ return access(*n, accessmode(mode));
+}
+
+log_id_t android_name_to_log_id(const char *logName)
+{
+ const char *b;
+ char *n;
+ int ret;
+
+ if (!logName) {
+ return -1; /* NB: log_id_t is unsigned */
+ }
+ b = strrchr(logName, '/');
+ if (!b) {
+ b = logName;
+ } else {
+ ++b;
+ }
+
+ ret = check_allocate_accessible(&n, b, O_RDONLY);
+ free(n);
+ if (ret) {
+ return ret;
+ }
+
+ for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
+ const char *l = LOG_NAME[ret];
+ if (l && !strcmp(b, l)) {
+ return ret;
+ }
+ }
+ return -1; /* should never happen */
+}
+
+struct logger_list {
+ struct listnode node;
+ int mode;
+ unsigned int tail;
+ pid_t pid;
+ unsigned int queued_lines;
+ int timeout_ms;
+ int error;
+ bool flush;
+ bool valid_entry; /* valiant(?) effort to deal with memory starvation */
+ struct log_msg entry;
+};
+
+struct log_list {
+ struct listnode node;
+ struct log_msg entry; /* Truncated to event->len() + 1 to save space */
+};
+
+struct logger {
+ struct listnode node;
+ struct logger_list *top;
+ int fd;
+ log_id_t id;
+ short *revents;
+ struct listnode log_list;
+};
+
+/* android_logger_alloc unimplemented, no use case */
+/* android_logger_free not exported */
+static void android_logger_free(struct logger *logger)
+{
+ if (!logger) {
+ return;
+ }
+
+ while (!list_empty(&logger->log_list)) {
+ struct log_list *entry = node_to_item(
+ list_head(&logger->log_list), struct log_list, node);
+ list_remove(&entry->node);
+ free(entry);
+ if (logger->top->queued_lines) {
+ logger->top->queued_lines--;
+ }
+ }
+
+ if (logger->fd >= 0) {
+ close(logger->fd);
+ }
+
+ list_remove(&logger->node);
+
+ free(logger);
+}
+
+log_id_t android_logger_get_id(struct logger *logger)
+{
+ return logger->id;
+}
+
+/* worker for sending the command to the logger */
+static int logger_ioctl(struct logger *logger, int cmd, int mode)
+{
+ char *n;
+ int f, ret;
+
+ if (!logger || !logger->top) {
+ return -EFAULT;
+ }
+
+ if (((mode & O_ACCMODE) == O_RDWR)
+ || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
+ return ioctl(logger->fd, cmd);
+ }
+
+ /* We go here if android_logger_list_open got mode wrong for this ioctl */
+ ret = check_allocate_accessible(&n, android_log_id_to_name(logger->id), mode);
+ if (ret) {
+ free(n);
+ return ret;
+ }
+
+ f = open(n, mode);
+ free(n);
+ if (f < 0) {
+ return f;
+ }
+
+ ret = ioctl(f, cmd);
+ close (f);
+
+ return ret;
+}
+
+int android_logger_clear(struct logger *logger)
+{
+ return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+}
+
+/* returns the total size of the log's ring buffer */
+long android_logger_get_log_size(struct logger *logger)
+{
+ return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+}
+
+#ifdef USERDEBUG_BUILD
+
+int android_logger_set_log_size(struct logger *logger UNUSED,
+ unsigned long size UNUSED)
+{
+ return -ENOTSUP;
+}
+
+#endif /* USERDEBUG_BUILD */
+
+/*
+ * returns the readable size of the log's ring buffer (that is, amount of the
+ * log consumed)
+ */
+long android_logger_get_log_readable_size(struct logger *logger)
+{
+ return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+}
+
+/*
+ * returns the logger version
+ */
+int android_logger_get_log_version(struct logger *logger)
+{
+ int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
+ return (ret < 0) ? 1 : ret;
+}
+
+/*
+ * returns statistics
+ */
+static const char unsupported[] = "18\nNot Supported\n\f";
+
+ssize_t android_logger_get_statistics(struct logger_list *logger_list UNUSED,
+ char *buf, size_t len)
+{
+ strncpy(buf, unsupported, len);
+ return -ENOTSUP;
+}
+
+#ifdef USERDEBUG_BUILD
+
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
+ char *buf, size_t len)
+{
+ strncpy(buf, unsupported, len);
+ return -ENOTSUP;
+}
+
+int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
+ char *buf, size_t len)
+{
+ static const char unsupported_error[] = "Unsupported";
+ strncpy(buf, unsupported, len);
+ return -ENOTSUP;
+}
+
+#endif /* USERDEBUG_BUILD */
+
+struct logger_list *android_logger_list_alloc(int mode,
+ unsigned int tail,
+ pid_t pid)
+{
+ struct logger_list *logger_list;
+
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
+ list_init(&logger_list->node);
+ logger_list->mode = mode;
+ logger_list->tail = tail;
+ logger_list->pid = pid;
+ return logger_list;
+}
+
+/* android_logger_list_register unimplemented, no use case */
+/* android_logger_list_unregister unimplemented, no use case */
+
+/* Open the named log and add it to the logger list */
+struct logger *android_logger_open(struct logger_list *logger_list,
+ log_id_t id)
+{
+ struct listnode *node;
+ struct logger *logger;
+ char *n;
+
+ if (!logger_list || (id >= LOG_ID_MAX)) {
+ goto err;
+ }
+
+ logger_for_each(logger, logger_list) {
+ if (logger->id == id) {
+ goto ok;
+ }
+ }
+
+ logger = calloc(1, sizeof(*logger));
+ if (!logger) {
+ goto err;
+ }
+
+ if (check_allocate_accessible(&n, android_log_id_to_name(id),
+ logger_list->mode)) {
+ goto err_name;
+ }
+
+ logger->fd = open(n, logger_list->mode);
+ if (logger->fd < 0) {
+ goto err_name;
+ }
+
+ free(n);
+ logger->id = id;
+ list_init(&logger->log_list);
+ list_add_tail(&logger_list->node, &logger->node);
+ logger->top = logger_list;
+ logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+ goto ok;
+
+err_name:
+ free(n);
+err_logger:
+ free(logger);
+err:
+ logger = NULL;
+ok:
+ return logger;
+}
+
+/* Open the single named log and make it part of a new logger list */
+struct logger_list *android_logger_list_open(log_id_t id,
+ int mode,
+ unsigned int tail,
+ pid_t pid)
+{
+ struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid);
+ if (!logger_list) {
+ return NULL;
+ }
+
+ if (!android_logger_open(logger_list, id)) {
+ android_logger_list_free(logger_list);
+ return NULL;
+ }
+
+ return logger_list;
+}
+
+/* prevent memory starvation when backfilling */
+static unsigned int queue_threshold(struct logger_list *logger_list)
+{
+ return (logger_list->tail < 64) ? 64 : logger_list->tail;
+}
+
+static bool low_queue(struct listnode *node)
+{
+ /* low is considered less than 2 */
+ return list_head(node) == list_tail(node);
+}
+
+/* Flush queues in sequential order, one at a time */
+static int android_logger_list_flush(struct logger_list *logger_list,
+ struct log_msg *log_msg)
+{
+ int ret = 0;
+ struct log_list *firstentry = NULL;
+
+ while ((ret == 0)
+ && (logger_list->flush
+ || (logger_list->queued_lines > logger_list->tail))) {
+ struct logger *logger;
+
+ /* Merge sort */
+ bool at_least_one_is_low = false;
+ struct logger *firstlogger = NULL;
+ firstentry = NULL;
+
+ logger_for_each(logger, logger_list) {
+ struct listnode *node;
+ struct log_list *oldest = NULL;
+
+ /* kernel logger channels not necessarily time-sort order */
+ list_for_each(node, &logger->log_list) {
+ struct log_list *entry = node_to_item(node,
+ struct log_list, node);
+ if (!oldest
+ || (entry->entry.entry.sec < oldest->entry.entry.sec)
+ || ((entry->entry.entry.sec == oldest->entry.entry.sec)
+ && (entry->entry.entry.nsec < oldest->entry.entry.nsec))) {
+ oldest = entry;
+ }
+ }
+
+ if (!oldest) {
+ at_least_one_is_low = true;
+ continue;
+ } else if (low_queue(&logger->log_list)) {
+ at_least_one_is_low = true;
+ }
+
+ if (!firstentry
+ || (oldest->entry.entry.sec < firstentry->entry.entry.sec)
+ || ((oldest->entry.entry.sec == firstentry->entry.entry.sec)
+ && (oldest->entry.entry.nsec < firstentry->entry.entry.nsec))) {
+ firstentry = oldest;
+ firstlogger = logger;
+ }
+ }
+
+ if (!firstentry) {
+ break;
+ }
+
+ /* when trimming list, tries to keep one entry behind in each bucket */
+ if (!logger_list->flush
+ && at_least_one_is_low
+ && (logger_list->queued_lines < queue_threshold(logger_list))) {
+ break;
+ }
+
+ /* within tail?, send! */
+ if ((logger_list->tail == 0)
+ || (logger_list->queued_lines <= logger_list->tail)) {
+ int diff;
+ ret = firstentry->entry.entry.hdr_size;
+ if (!ret) {
+ ret = sizeof(firstentry->entry.entry_v1);
+ }
+
+ /* Promote entry to v3 format */
+ memcpy(log_msg->buf, firstentry->entry.buf, ret);
+ diff = sizeof(firstentry->entry.entry_v3) - ret;
+ if (diff < 0) {
+ diff = 0;
+ } else if (diff > 0) {
+ memset(log_msg->buf + ret, 0, diff);
+ }
+ memcpy(log_msg->buf + ret + diff, firstentry->entry.buf + ret,
+ firstentry->entry.entry.len + 1);
+ ret += diff;
+ log_msg->entry.hdr_size = ret;
+ log_msg->entry.lid = firstlogger->id;
+
+ ret += firstentry->entry.entry.len;
+ }
+
+ /* next entry */
+ list_remove(&firstentry->node);
+ free(firstentry);
+ if (logger_list->queued_lines) {
+ logger_list->queued_lines--;
+ }
+ }
+
+ /* Flushed the list, no longer in tail mode for continuing content */
+ if (logger_list->flush && !firstentry) {
+ logger_list->tail = 0;
+ }
+ return ret;
+}
+
+/* Read from the selected logs */
+int android_logger_list_read(struct logger_list *logger_list,
+ struct log_msg *log_msg)
+{
+ struct logger *logger;
+ nfds_t nfds;
+ struct pollfd *p, *pollfds = NULL;
+ int error = 0, ret = 0;
+
+ memset(log_msg, 0, sizeof(struct log_msg));
+
+ if (!logger_list) {
+ return -ENODEV;
+ }
+
+ if (!(accessmode(logger_list->mode) & R_OK)) {
+ logger_list->error = EPERM;
+ goto done;
+ }
+
+ nfds = 0;
+ logger_for_each(logger, logger_list) {
+ ++nfds;
+ }
+ if (nfds <= 0) {
+ error = ENODEV;
+ goto done;
+ }
+
+ /* Do we have anything to offer from the buffer or state? */
+ if (logger_list->valid_entry) { /* implies we are also in a flush state */
+ goto flush;
+ }
+
+ ret = android_logger_list_flush(logger_list, log_msg);
+ if (ret) {
+ goto done;
+ }
+
+ if (logger_list->error) { /* implies we are also in a flush state */
+ goto done;
+ }
+
+ /* Lets start grinding on metal */
+ pollfds = calloc(nfds, sizeof(struct pollfd));
+ if (!pollfds) {
+ error = ENOMEM;
+ goto flush;
+ }
+
+ p = pollfds;
+ logger_for_each(logger, logger_list) {
+ p->fd = logger->fd;
+ p->events = POLLIN;
+ logger->revents = &p->revents;
+ ++p;
+ }
+
+ while (!ret && !error) {
+ int result;
+
+ /* If we oversleep it's ok, i.e. ignore EINTR. */
+ result = TEMP_FAILURE_RETRY(
+ poll(pollfds, nfds, logger_list->timeout_ms));
+
+ if (result <= 0) {
+ if (result) {
+ error = errno;
+ } else if (logger_list->mode & O_NDELAY) {
+ error = EAGAIN;
+ } else {
+ logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
+ }
+
+ logger_list->flush = true;
+ goto try_flush;
+ }
+
+ logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+
+ /* Anti starvation */
+ if (!logger_list->flush
+ && (logger_list->queued_lines > (queue_threshold(logger_list) / 2))) {
+ /* Any queues with input pending that is low? */
+ bool starving = false;
+ logger_for_each(logger, logger_list) {
+ if ((*(logger->revents) & POLLIN)
+ && low_queue(&logger->log_list)) {
+ starving = true;
+ break;
+ }
+ }
+
+ /* pushback on any queues that are not low */
+ if (starving) {
+ logger_for_each(logger, logger_list) {
+ if ((*(logger->revents) & POLLIN)
+ && !low_queue(&logger->log_list)) {
+ *(logger->revents) &= ~POLLIN;
+ }
+ }
+ }
+ }
+
+ logger_for_each(logger, logger_list) {
+ unsigned int hdr_size;
+ struct log_list *entry;
+ int diff;
+
+ if (!(*(logger->revents) & POLLIN)) {
+ continue;
+ }
+
+ memset(logger_list->entry.buf, 0, sizeof(struct log_msg));
+ /* NOTE: driver guarantees we read exactly one full entry */
+ result = read(logger->fd, logger_list->entry.buf,
+ LOGGER_ENTRY_MAX_LEN);
+ if (result <= 0) {
+ if (!result) {
+ error = EIO;
+ } else if (errno != EINTR) {
+ error = errno;
+ }
+ continue;
+ }
+
+ if (logger_list->pid
+ && (logger_list->pid != logger_list->entry.entry.pid)) {
+ continue;
+ }
+
+ hdr_size = logger_list->entry.entry.hdr_size;
+ if (!hdr_size) {
+ hdr_size = sizeof(logger_list->entry.entry_v1);
+ }
+
+ if ((hdr_size > sizeof(struct log_msg))
+ || (logger_list->entry.entry.len
+ > sizeof(logger_list->entry.buf) - hdr_size)
+ || (logger_list->entry.entry.len != result - hdr_size)) {
+ error = EINVAL;
+ continue;
+ }
+
+ /* Promote entry to v3 format */
+ diff = sizeof(logger_list->entry.entry_v3) - hdr_size;
+ if (diff > 0) {
+ if (logger_list->entry.entry.len
+ > sizeof(logger_list->entry.buf) - hdr_size - diff) {
+ error = EINVAL;
+ continue;
+ }
+ result += diff;
+ memmove(logger_list->entry.buf + hdr_size + diff,
+ logger_list->entry.buf + hdr_size,
+ logger_list->entry.entry.len + 1);
+ memset(logger_list->entry.buf + hdr_size, 0, diff);
+ logger_list->entry.entry.hdr_size = hdr_size + diff;
+ }
+ logger_list->entry.entry.lid = logger->id;
+
+ /* speedup: If not tail, and only one list, send directly */
+ if (!logger_list->tail
+ && (list_head(&logger_list->node)
+ == list_tail(&logger_list->node))) {
+ ret = result;
+ memcpy(log_msg->buf, logger_list->entry.buf, result + 1);
+ break;
+ }
+
+ entry = malloc(sizeof(*entry) - sizeof(entry->entry) + result + 1);
+
+ if (!entry) {
+ logger_list->valid_entry = true;
+ error = ENOMEM;
+ break;
+ }
+
+ logger_list->queued_lines++;
+
+ memcpy(entry->entry.buf, logger_list->entry.buf, result);
+ entry->entry.buf[result] = '\0';
+ list_add_tail(&logger->log_list, &entry->node);
+ }
+
+ if (ret <= 0) {
+try_flush:
+ ret = android_logger_list_flush(logger_list, log_msg);
+ }
+ }
+
+ free(pollfds);
+
+flush:
+ if (error) {
+ logger_list->flush = true;
+ }
+
+ if (ret <= 0) {
+ ret = android_logger_list_flush(logger_list, log_msg);
+
+ if (!ret && logger_list->valid_entry) {
+ ret = logger_list->entry.entry.hdr_size;
+ if (!ret) {
+ ret = sizeof(logger_list->entry.entry_v1);
+ }
+ ret += logger_list->entry.entry.len;
+
+ memcpy(log_msg->buf, logger_list->entry.buf,
+ sizeof(struct log_msg));
+ logger_list->valid_entry = false;
+ }
+ }
+
+done:
+ if (logger_list->error) {
+ error = logger_list->error;
+ }
+ if (error) {
+ logger_list->error = error;
+ if (!ret) {
+ ret = -error;
+ }
+ }
+ return ret;
+}
+
+/* Close all the logs */
+void android_logger_list_free(struct logger_list *logger_list)
+{
+ if (logger_list == NULL) {
+ return;
+ }
+
+ while (!list_empty(&logger_list->node)) {
+ struct listnode *node = list_head(&logger_list->node);
+ struct logger *logger = node_to_item(node, struct logger, node);
+ android_logger_free(logger);
+ }
+
+ free(logger_list);
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 5766f8c..c3efc33 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -13,41 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <time.h>
-#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
#include <stdarg.h>
-#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#if (FAKE_LOG_DEVICE == 0)
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+#include <time.h>
+#include <unistd.h>
-#include <log/logger.h>
#include <log/logd.h>
-#include <log/log.h>
-
-#define LOGGER_LOG_MAIN "log/main"
-#define LOGGER_LOG_RADIO "log/radio"
-#define LOGGER_LOG_EVENTS "log/events"
-#define LOGGER_LOG_SYSTEM "log/system"
+#include <log/logger.h>
+#include <log/log_read.h>
+#include <private/android_filesystem_config.h>
#define LOG_BUF_SIZE 1024
#if FAKE_LOG_DEVICE
-// This will be defined when building for the host.
+/* This will be defined when building for the host. */
#include "fake_log_device.h"
-#define log_open(pathname, flags) fakeLogOpen(pathname, flags)
-#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
-#define log_close(filedes) fakeLogClose(filedes)
-#else
-#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)
-#define log_writev(filedes, vector, count) writev(filedes, vector, count)
-#define log_close(filedes) close(filedes)
#endif
static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
@@ -58,11 +51,15 @@
#define UNUSED __attribute__((__unused__))
+static int logd_fd = -1;
+#if FAKE_LOG_DEVICE
+#define WEAK __attribute__((weak))
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
+#endif
/*
* This is used by the C++ code to decide if it should write logs through
- * the C code. Basically, if /dev/log/... is available, we're running in
+ * the C code. Basically, if /dev/socket/logd is available, we're running in
* the simulator rather than a desktop tool and want to use the device.
*/
static enum {
@@ -71,7 +68,7 @@
int __android_log_dev_available(void)
{
if (g_log_status == kLogUninitialized) {
- if (access("/dev/"LOGGER_LOG_MAIN, W_OK) == 0)
+ if (access("/dev/socket/logdw", W_OK) == 0)
g_log_status = kLogAvailable;
else
g_log_status = kLogNotAvailable;
@@ -81,13 +78,14 @@
}
static int __write_to_log_null(log_id_t log_fd UNUSED, struct iovec *vec UNUSED,
- size_t nr UNUSED)
+ size_t nr UNUSED)
{
return -1;
}
static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
{
+#if FAKE_LOG_DEVICE
ssize_t ret;
int log_fd;
@@ -96,14 +94,66 @@
} else {
return EBADF;
}
-
do {
- ret = log_writev(log_fd, vec, nr);
+ ret = fakeLogWritev(log_fd, vec, nr);
} while (ret < 0 && errno == EINTR);
return ret;
+#else
+ if (logd_fd == -1) {
+ return -1;
+ }
+ if (getuid() == AID_LOGD) {
+ /*
+ * ignore log messages we send to ourself.
+ * Such log messages are often generated by libraries we depend on
+ * which use standard Android logging.
+ */
+ return 0;
+ }
+ struct iovec newVec[nr + 2];
+ typeof_log_id_t log_id_buf = log_id;
+
+ newVec[0].iov_base = (unsigned char *) &log_id_buf;
+ newVec[0].iov_len = sizeof_log_id_t;
+
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ log_time realtime_ts;
+ realtime_ts.tv_sec = ts.tv_sec;
+ realtime_ts.tv_nsec = ts.tv_nsec;
+
+ newVec[1].iov_base = (unsigned char *) &realtime_ts;
+ newVec[1].iov_len = sizeof(log_time);
+
+ size_t i;
+ for (i = 2; i < nr + 2; i++) {
+ newVec[i].iov_base = vec[i-2].iov_base;
+ newVec[i].iov_len = vec[i-2].iov_len;
+ }
+
+ /* The write below could be lost, but will never block. */
+ return writev(logd_fd, newVec, nr + 2);
+#endif
}
+#if FAKE_LOG_DEVICE
+static const char *LOG_NAME[LOG_ID_MAX] = {
+ [LOG_ID_MAIN] = "main",
+ [LOG_ID_RADIO] = "radio",
+ [LOG_ID_EVENTS] = "events",
+ [LOG_ID_SYSTEM] = "system"
+};
+
+const WEAK char *android_log_id_to_name(log_id_t log_id)
+{
+ if (log_id >= LOG_ID_MAX) {
+ log_id = LOG_ID_MAIN;
+ }
+ return LOG_NAME[log_id];
+}
+#endif
+
static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
{
#ifdef HAVE_PTHREADS
@@ -111,27 +161,35 @@
#endif
if (write_to_log == __write_to_log_init) {
- log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
- log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
- log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
- log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
-
write_to_log = __write_to_log_kernel;
- if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
- log_fds[LOG_ID_EVENTS] < 0) {
- log_close(log_fds[LOG_ID_MAIN]);
- log_close(log_fds[LOG_ID_RADIO]);
- log_close(log_fds[LOG_ID_EVENTS]);
- log_fds[LOG_ID_MAIN] = -1;
- log_fds[LOG_ID_RADIO] = -1;
- log_fds[LOG_ID_EVENTS] = -1;
+#if FAKE_LOG_DEVICE
+ int i;
+ for (i = 0; i < LOG_ID_MAX; i++) {
+ char buf[sizeof("/dev/log_system")];
+ snprintf(buf, sizeof(buf), "/dev/log_%s", android_log_id_to_name(i));
+ log_fds[i] = fakeLogOpen(buf, O_WRONLY);
+ }
+#else
+ int sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (sock != -1) {
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
+ /* NB: Loss of content */
+ close(sock);
+ sock = -1;
+ } else {
+ struct sockaddr_un un;
+ memset(&un, 0, sizeof(struct sockaddr_un));
+ un.sun_family = AF_UNIX;
+ strcpy(un.sun_path, "/dev/socket/logdw");
+
+ connect(sock, (struct sockaddr *)&un, sizeof(struct sockaddr_un));
+ }
+ } else {
write_to_log = __write_to_log_null;
}
-
- if (log_fds[LOG_ID_SYSTEM] < 0) {
- log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
- }
+ logd_fd = sock;
+#endif
}
#ifdef HAVE_PTHREADS
@@ -288,7 +346,7 @@
* handy if we just want to dump an integer into the log.
*/
int __android_log_btwrite(int32_t tag, char type, const void *payload,
- size_t len)
+ size_t len)
{
struct iovec vec[3];
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
new file mode 100644
index 0000000..32a202b
--- /dev/null
+++ b/liblog/logd_write_kern.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2007-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PTHREADS
+#include <pthread.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <log/log.h>
+#include <log/logd.h>
+#include <log/logger.h>
+
+#define LOGGER_LOG_MAIN "log/main"
+#define LOGGER_LOG_RADIO "log/radio"
+#define LOGGER_LOG_EVENTS "log/events"
+#define LOGGER_LOG_SYSTEM "log/system"
+
+#define LOG_BUF_SIZE 1024
+
+#if FAKE_LOG_DEVICE
+/* This will be defined when building for the host. */
+#include "fake_log_device.h"
+#define log_open(pathname, flags) fakeLogOpen(pathname, flags)
+#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
+#define log_close(filedes) fakeLogClose(filedes)
+#else
+#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)
+#define log_writev(filedes, vector, count) writev(filedes, vector, count)
+#define log_close(filedes) close(filedes)
+#endif
+
+static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
+static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
+#ifdef HAVE_PTHREADS
+static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#define UNUSED __attribute__((__unused__))
+
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
+
+/*
+ * This is used by the C++ code to decide if it should write logs through
+ * the C code. Basically, if /dev/log/... is available, we're running in
+ * the simulator rather than a desktop tool and want to use the device.
+ */
+static enum {
+ kLogUninitialized, kLogNotAvailable, kLogAvailable
+} g_log_status = kLogUninitialized;
+int __android_log_dev_available(void)
+{
+ if (g_log_status == kLogUninitialized) {
+ if (access("/dev/"LOGGER_LOG_MAIN, W_OK) == 0)
+ g_log_status = kLogAvailable;
+ else
+ g_log_status = kLogNotAvailable;
+ }
+
+ return (g_log_status == kLogAvailable);
+}
+
+static int __write_to_log_null(log_id_t log_fd UNUSED, struct iovec *vec UNUSED,
+ size_t nr UNUSED)
+{
+ return -1;
+}
+
+static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+ ssize_t ret;
+ int log_fd;
+
+ if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) {
+ log_fd = log_fds[(int)log_id];
+ } else {
+ return EBADF;
+ }
+
+ do {
+ ret = log_writev(log_fd, vec, nr);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
+{
+#ifdef HAVE_PTHREADS
+ pthread_mutex_lock(&log_init_lock);
+#endif
+
+ if (write_to_log == __write_to_log_init) {
+ log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
+ log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
+ log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
+ log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
+
+ write_to_log = __write_to_log_kernel;
+
+ if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
+ log_fds[LOG_ID_EVENTS] < 0) {
+ log_close(log_fds[LOG_ID_MAIN]);
+ log_close(log_fds[LOG_ID_RADIO]);
+ log_close(log_fds[LOG_ID_EVENTS]);
+ log_fds[LOG_ID_MAIN] = -1;
+ log_fds[LOG_ID_RADIO] = -1;
+ log_fds[LOG_ID_EVENTS] = -1;
+ write_to_log = __write_to_log_null;
+ }
+
+ if (log_fds[LOG_ID_SYSTEM] < 0) {
+ log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
+ }
+ }
+
+#ifdef HAVE_PTHREADS
+ pthread_mutex_unlock(&log_init_lock);
+#endif
+
+ return write_to_log(log_id, vec, nr);
+}
+
+int __android_log_write(int prio, const char *tag, const char *msg)
+{
+ struct iovec vec[3];
+ log_id_t log_id = LOG_ID_MAIN;
+ char tmp_tag[32];
+
+ if (!tag)
+ tag = "";
+
+ /* XXX: This needs to go! */
+ if (!strcmp(tag, "HTC_RIL") ||
+ !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+ !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+ !strcmp(tag, "AT") ||
+ !strcmp(tag, "GSM") ||
+ !strcmp(tag, "STK") ||
+ !strcmp(tag, "CDMA") ||
+ !strcmp(tag, "PHONE") ||
+ !strcmp(tag, "SMS")) {
+ log_id = LOG_ID_RADIO;
+ /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+ snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+ tag = tmp_tag;
+ }
+
+ vec[0].iov_base = (unsigned char *) &prio;
+ vec[0].iov_len = 1;
+ vec[1].iov_base = (void *) tag;
+ vec[1].iov_len = strlen(tag) + 1;
+ vec[2].iov_base = (void *) msg;
+ vec[2].iov_len = strlen(msg) + 1;
+
+ return write_to_log(log_id, vec, 3);
+}
+
+int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
+{
+ struct iovec vec[3];
+ char tmp_tag[32];
+
+ if (!tag)
+ tag = "";
+
+ /* XXX: This needs to go! */
+ if ((bufID != LOG_ID_RADIO) &&
+ (!strcmp(tag, "HTC_RIL") ||
+ !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
+ !strncmp(tag, "IMS", 3) || /* Any log tag with "IMS" as the prefix */
+ !strcmp(tag, "AT") ||
+ !strcmp(tag, "GSM") ||
+ !strcmp(tag, "STK") ||
+ !strcmp(tag, "CDMA") ||
+ !strcmp(tag, "PHONE") ||
+ !strcmp(tag, "SMS"))) {
+ bufID = LOG_ID_RADIO;
+ /* Inform third party apps/ril/radio.. to use Rlog or RLOG */
+ snprintf(tmp_tag, sizeof(tmp_tag), "use-Rlog/RLOG-%s", tag);
+ tag = tmp_tag;
+ }
+
+ vec[0].iov_base = (unsigned char *) &prio;
+ vec[0].iov_len = 1;
+ vec[1].iov_base = (void *) tag;
+ vec[1].iov_len = strlen(tag) + 1;
+ vec[2].iov_base = (void *) msg;
+ vec[2].iov_len = strlen(msg) + 1;
+
+ return write_to_log(bufID, vec, 3);
+}
+
+int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap)
+{
+ char buf[LOG_BUF_SIZE];
+
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+
+ return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_print(int prio, const char *tag, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[LOG_BUF_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ return __android_log_write(prio, tag, buf);
+}
+
+int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[LOG_BUF_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ return __android_log_buf_write(bufID, prio, tag, buf);
+}
+
+void __android_log_assert(const char *cond, const char *tag,
+ const char *fmt, ...)
+{
+ char buf[LOG_BUF_SIZE];
+
+ if (fmt) {
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
+ va_end(ap);
+ } else {
+ /* Msg not provided, log condition. N.B. Do not use cond directly as
+ * format string as it could contain spurious '%' syntax (e.g.
+ * "%d" in "blocks%devs == 0").
+ */
+ if (cond)
+ snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
+ else
+ strcpy(buf, "Unspecified assertion failed");
+ }
+
+ __android_log_write(ANDROID_LOG_FATAL, tag, buf);
+
+ __builtin_trap(); /* trap so we have a chance to debug the situation */
+}
+
+int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
+{
+ struct iovec vec[2];
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = (void*)payload;
+ vec[1].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 2);
+}
+
+/*
+ * Like __android_log_bwrite, but takes the type as well. Doesn't work
+ * for the general case where we're generating lists of stuff, but very
+ * handy if we just want to dump an integer into the log.
+ */
+int __android_log_btwrite(int32_t tag, char type, const void *payload,
+ size_t len)
+{
+ struct iovec vec[3];
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = (void*)payload;
+ vec[2].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 3);
+}
diff --git a/liblog/tests/benchmark_main.cpp b/liblog/tests/benchmark_main.cpp
index 02df460..090394c 100644
--- a/liblog/tests/benchmark_main.cpp
+++ b/liblog/tests/benchmark_main.cpp
@@ -16,6 +16,7 @@
#include <benchmark.h>
+#include <inttypes.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
@@ -158,10 +159,10 @@
sdev = (sqrt((double)nXvariance) / gBenchmarkNum / gBenchmarkNum) + 0.5;
}
if (mean > (10000 * sdev)) {
- printf("%-25s %10llu %10llu%s\n", full_name,
+ printf("%-25s %10" PRIu64 " %10" PRIu64 "%s\n", full_name,
static_cast<uint64_t>(iterations), mean, throughput);
} else {
- printf("%-25s %10llu %10llu(\317\203%llu)%s\n", full_name,
+ printf("%-25s %10" PRIu64 " %10" PRIu64 "(\317\203%" PRIu64 ")%s\n", full_name,
static_cast<uint64_t>(iterations), mean, sdev, throughput);
}
fflush(stdout);
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 19406fb..39fe2ad 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -143,7 +143,7 @@
for (int j = 0, i = 0; i < iters && j < 10*iters; ++i, ++j) {
log_time ts;
LOG_FAILURE_RETRY((
- clock_gettime(CLOCK_REALTIME, &ts),
+ ts = log_time(CLOCK_REALTIME),
android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts))));
for (;;) {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 9ae8f22..ffb7fd1 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -15,6 +15,7 @@
*/
#include <fcntl.h>
+#include <inttypes.h>
#include <signal.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -85,8 +86,8 @@
static void* ConcurrentPrintFn(void *arg) {
int ret = __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_print", "Concurrent %d",
- reinterpret_cast<int>(arg));
+ "TEST__android_log_print", "Concurrent %" PRIuPTR,
+ reinterpret_cast<uintptr_t>(arg));
return reinterpret_cast<void*>(ret);
}
@@ -106,8 +107,9 @@
for (i=0; i < NUM_CONCURRENT; i++) {
void* result;
ASSERT_EQ(0, pthread_join(t[i], &result));
- if ((0 == ret) && (0 != reinterpret_cast<int>(result))) {
- ret = reinterpret_cast<int>(result);
+ int this_result = reinterpret_cast<uintptr_t>(result);
+ if ((0 == ret) && (0 != this_result)) {
+ ret = this_result;
}
}
ASSERT_LT(0, ret);
@@ -169,7 +171,7 @@
++signaled;
if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
- clock_gettime(CLOCK_MONOTONIC, &signal_time);
+ signal_time = log_time(CLOCK_MONOTONIC);
signal_time.tv_sec += 2;
}
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
index deac9de..3721fc6 100644
--- a/libnl_2/Android.mk
+++ b/libnl_2/Android.mk
@@ -26,6 +26,7 @@
# Static Library
LOCAL_MODULE := libnl_2
LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -34,4 +35,5 @@
LOCAL_SHARED_LIBRARIES:= liblog
LOCAL_MODULE := libnl_2
LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
include $(BUILD_SHARED_LIBRARY)
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index fe50cc6..484cf50 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -7,13 +7,13 @@
include $(CLEAR_VARS)
PIXELFLINGER_SRC_FILES:= \
- codeflinger/ARMAssemblerInterface.cpp \
- codeflinger/ARMAssemblerProxy.cpp \
- codeflinger/CodeCache.cpp \
- codeflinger/GGLAssembler.cpp \
- codeflinger/load_store.cpp \
- codeflinger/blending.cpp \
- codeflinger/texturing.cpp \
+ codeflinger/ARMAssemblerInterface.cpp \
+ codeflinger/ARMAssemblerProxy.cpp \
+ codeflinger/CodeCache.cpp \
+ codeflinger/GGLAssembler.cpp \
+ codeflinger/load_store.cpp \
+ codeflinger/blending.cpp \
+ codeflinger/texturing.cpp \
codeflinger/tinyutils/SharedBuffer.cpp \
codeflinger/tinyutils/VectorImpl.cpp \
fixed.cpp.arm \
@@ -26,39 +26,28 @@
raster.cpp \
buffer.cpp
-ifeq ($(TARGET_ARCH),arm)
-ifeq ($(TARGET_ARCH_VERSION),armv7-a)
-PIXELFLINGER_SRC_FILES += col32cb16blend_neon.S
-PIXELFLINGER_SRC_FILES += col32cb16blend.S
-else
-PIXELFLINGER_SRC_FILES += t32cb16blend.S
-PIXELFLINGER_SRC_FILES += col32cb16blend.S
-endif
+PIXELFLINGER_CFLAGS := -fstrict-aliasing -fomit-frame-pointer
+
+PIXELFLINGER_SRC_FILES_arm := \
+ codeflinger/ARMAssembler.cpp \
+ codeflinger/disassem.c \
+ col32cb16blend.S \
+ t32cb16blend.S \
+
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+PIXELFLINGER_SRC_FILES_arm += col32cb16blend_neon.S
endif
-ifeq ($(TARGET_ARCH),arm)
-PIXELFLINGER_SRC_FILES += codeflinger/ARMAssembler.cpp
-PIXELFLINGER_SRC_FILES += codeflinger/disassem.c
-# special optimization flags for pixelflinger
-PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
-endif
+PIXELFLINGER_SRC_FILES_arm64 := \
+ codeflinger/Arm64Assembler.cpp \
+ codeflinger/Arm64Disassembler.cpp \
+ arch-arm64/col32cb16blend.S \
+ arch-arm64/t32cb16blend.S \
-ifeq ($(TARGET_ARCH),mips)
-PIXELFLINGER_SRC_FILES += codeflinger/MIPSAssembler.cpp
-PIXELFLINGER_SRC_FILES += codeflinger/mips_disassem.c
-PIXELFLINGER_SRC_FILES += arch-mips/t32cb16blend.S
-PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
-endif
-
-LOCAL_SHARED_LIBRARIES := libcutils liblog
-
-ifeq ($(TARGET_ARCH),arm64)
-PIXELFLINGER_SRC_FILES += arch-arm64/t32cb16blend.S
-PIXELFLINGER_SRC_FILES += arch-arm64/col32cb16blend.S
-PIXELFLINGER_SRC_FILES += codeflinger/Arm64Assembler.cpp
-PIXELFLINGER_SRC_FILES += codeflinger/Arm64Disassembler.cpp
-PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
-endif
+PIXELFLINGER_SRC_FILES_mips := \
+ codeflinger/MIPSAssembler.cpp \
+ codeflinger/mips_disassem.c \
+ arch-mips/t32cb16blend.S \
#
# Shared library
@@ -66,7 +55,11 @@
LOCAL_MODULE:= libpixelflinger
LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
+LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
+LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
+LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+LOCAL_SHARED_LIBRARIES := libcutils liblog
ifneq ($(BUILD_TINY_ANDROID),true)
# Really this should go away entirely or at least not depend on
@@ -83,6 +76,9 @@
include $(CLEAR_VARS)
LOCAL_MODULE:= libpixelflinger_static
LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
+LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
+LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
+LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
include $(BUILD_STATIC_LIBRARY)
diff --git a/libpixelflinger/buffer.cpp b/libpixelflinger/buffer.cpp
index cbdab5a..dcb95c5 100644
--- a/libpixelflinger/buffer.cpp
+++ b/libpixelflinger/buffer.cpp
@@ -130,7 +130,7 @@
}
}
-void readRGB565(const surface_t* s, context_t* c,
+void readRGB565(const surface_t* s, context_t* /*c*/,
uint32_t x, uint32_t y, pixel_t* pixel)
{
uint16_t v = *(reinterpret_cast<uint16_t*>(s->data) + (x + (s->stride * y)));
@@ -144,7 +144,7 @@
pixel->s[3] = 5;
}
-void readABGR8888(const surface_t* s, context_t* c,
+void readABGR8888(const surface_t* s, context_t* /*c*/,
uint32_t x, uint32_t y, pixel_t* pixel)
{
uint32_t v = *(reinterpret_cast<uint32_t*>(s->data) + (x + (s->stride * y)));
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
index f37072a..bd11818 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -273,7 +273,7 @@
*mPC++ = (0x54 << 24) | cc;
}
-void ArmToArm64Assembler::BL(int cc, const char* label)
+void ArmToArm64Assembler::BL(int /*cc*/, const char* /*label*/)
{
NOT_IMPLEMENTED(); //Not Required
}
@@ -289,7 +289,7 @@
*mPC++ = A64_MOVZ_X(mZeroReg,0,0);
}
-void ArmToArm64Assembler::epilog(uint32_t touched)
+void ArmToArm64Assembler::epilog(uint32_t /*touched*/)
{
// write epilog code
static const int XLR = 30;
@@ -530,23 +530,23 @@
if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
*mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
}
-void ArmToArm64Assembler::UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::UMULL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::UMUAL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::SMULL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs)
+void ArmToArm64Assembler::SMUAL(int /*cc*/, int /*s*/,
+ int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
{
NOT_IMPLEMENTED(); //Not required
}
@@ -554,15 +554,15 @@
// ----------------------------------------------------------------------------
// branches relative to PC...
// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::B(int cc, uint32_t* pc){
+void ArmToArm64Assembler::B(int /*cc*/, uint32_t* /*pc*/){
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::BL(int cc, uint32_t* pc){
+void ArmToArm64Assembler::BL(int /*cc*/, uint32_t* /*pc*/){
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::BX(int cc, int Rn){
+void ArmToArm64Assembler::BX(int /*cc*/, int /*Rn*/){
NOT_IMPLEMENTED(); //Not required
}
@@ -661,11 +661,11 @@
{
return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
}
-void ArmToArm64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSB(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSH(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
{
NOT_IMPLEMENTED(); //Not required
}
@@ -723,15 +723,15 @@
// ----------------------------------------------------------------------------
// special...
// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::SWP(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWP(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::SWPB(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWPB(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::SWI(int cc, uint32_t comment)
+void ArmToArm64Assembler::SWI(int /*cc*/, uint32_t /*comment*/)
{
NOT_IMPLEMENTED(); //Not required
}
@@ -739,31 +739,31 @@
// ----------------------------------------------------------------------------
// DSP instructions...
// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::PLD(int Rn, uint32_t offset) {
+void ArmToArm64Assembler::PLD(int /*Rn*/, uint32_t /*offset*/) {
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::CLZ(int cc, int Rd, int Rm)
+void ArmToArm64Assembler::CLZ(int /*cc*/, int /*Rd*/, int /*Rm*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::QADD(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::QDADD(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::QSUB(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToArm64Assembler::QDSUB(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
{
NOT_IMPLEMENTED(); //Not required
}
@@ -817,15 +817,15 @@
*mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
}
-void ArmToArm64Assembler::SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm)
+void ArmToArm64Assembler::SMLAL(int /*cc*/, int /*xy*/,
+ int /*RdHi*/, int /*RdLo*/, int /*Rs*/, int /*Rm*/)
{
NOT_IMPLEMENTED(); //Not required
return;
}
-void ArmToArm64Assembler::SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn)
+void ArmToArm64Assembler::SMLAW(int /*cc*/, int /*y*/,
+ int /*Rd*/, int /*Rm*/, int /*Rs*/, int /*Rn*/)
{
NOT_IMPLEMENTED(); //Not required
return;
@@ -890,13 +890,13 @@
return OPERAND_REG_IMM;
}
-uint32_t ArmToArm64Assembler::reg_rrx(int Rm)
+uint32_t ArmToArm64Assembler::reg_rrx(int /*Rm*/)
{
NOT_IMPLEMENTED();
return OPERAND_UNSUPPORTED;
}
-uint32_t ArmToArm64Assembler::reg_reg(int Rm, int type, int Rs)
+uint32_t ArmToArm64Assembler::reg_reg(int /*Rm*/, int /*type*/, int /*Rs*/)
{
NOT_IMPLEMENTED(); //Not required
return OPERAND_UNSUPPORTED;
@@ -937,7 +937,7 @@
}
}
-uint32_t ArmToArm64Assembler::reg_scale_post(int Rm, int type, uint32_t shift)
+uint32_t ArmToArm64Assembler::reg_scale_post(int /*Rm*/, int /*type*/, uint32_t /*shift*/)
{
NOT_IMPLEMENTED(); //Not required
return OPERAND_UNSUPPORTED;
@@ -975,7 +975,7 @@
}
}
-uint32_t ArmToArm64Assembler::reg_post(int Rm)
+uint32_t ArmToArm64Assembler::reg_post(int /*Rm*/)
{
NOT_IMPLEMENTED(); //Not required
return OPERAND_UNSUPPORTED;
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 4fe30d9..7446da2 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -201,13 +201,9 @@
mCacheInUse += assemblySize;
mWhen++;
// synchronize caches...
-#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
const long base = long(assembly->base());
const long curr = base + long(assembly->size());
- err = cacheflush(base, curr, 0);
- ALOGE_IF(err, "cacheflush error %s\n",
- strerror(errno));
-#endif
+ __builtin___clear_cache((void*)base, (void*)curr);
}
pthread_mutex_unlock(&mLock);
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 2422d7b..325caba 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -694,7 +694,7 @@
// ---------------------------------------------------------------------------
void GGLAssembler::build_alpha_test(component_t& fragment,
- const fragment_parts_t& parts)
+ const fragment_parts_t& /*parts*/)
{
if (mAlphaTest != GGL_ALWAYS) {
comment("Alpha Test");
@@ -796,7 +796,7 @@
}
}
-void GGLAssembler::build_iterate_f(const fragment_parts_t& parts)
+void GGLAssembler::build_iterate_f(const fragment_parts_t& /*parts*/)
{
const needs_t& needs = mBuilderContext.needs;
if (GGL_READ_NEEDS(P_FOG, needs.p)) {
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
index b2cfbb3..81950bf 100644
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ b/libpixelflinger/codeflinger/texturing.cpp
@@ -694,7 +694,7 @@
}
void GGLAssembler::filter8(
- const fragment_parts_t& parts,
+ const fragment_parts_t& /*parts*/,
pixel_t& texel, const texture_unit_t& tmu,
int U, int V, pointer_t& txPtr,
int FRAC_BITS)
@@ -761,7 +761,7 @@
}
void GGLAssembler::filter16(
- const fragment_parts_t& parts,
+ const fragment_parts_t& /*parts*/,
pixel_t& texel, const texture_unit_t& tmu,
int U, int V, pointer_t& txPtr,
int FRAC_BITS)
@@ -879,10 +879,10 @@
}
void GGLAssembler::filter24(
- const fragment_parts_t& parts,
- pixel_t& texel, const texture_unit_t& tmu,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS)
+ const fragment_parts_t& /*parts*/,
+ pixel_t& texel, const texture_unit_t& /*tmu*/,
+ int /*U*/, int /*V*/, pointer_t& txPtr,
+ int /*FRAC_BITS*/)
{
// not supported yet (currently disabled)
load(txPtr, texel, 0);
@@ -989,8 +989,8 @@
}
#else
void GGLAssembler::filter32(
- const fragment_parts_t& parts,
- pixel_t& texel, const texture_unit_t& tmu,
+ const fragment_parts_t& /*parts*/,
+ pixel_t& texel, const texture_unit_t& /*tmu*/,
int U, int V, pointer_t& txPtr,
int FRAC_BITS)
{
diff --git a/libpixelflinger/picker.cpp b/libpixelflinger/picker.cpp
index 030ef19..aa55229 100644
--- a/libpixelflinger/picker.cpp
+++ b/libpixelflinger/picker.cpp
@@ -26,7 +26,7 @@
// ----------------------------------------------------------------------------
-void ggl_init_picker(context_t* c)
+void ggl_init_picker(context_t* /*c*/)
{
}
diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp
index 84e584e..ea5bc8e 100644
--- a/libpixelflinger/pixelflinger.cpp
+++ b/libpixelflinger/pixelflinger.cpp
@@ -662,7 +662,7 @@
}
}
-void ggl_enable_stencil_test(context_t* c, int enable)
+void ggl_enable_stencil_test(context_t* /*c*/, int /*enable*/)
{
}
diff --git a/libpixelflinger/raster.cpp b/libpixelflinger/raster.cpp
index 32b2a97..26d8e45 100644
--- a/libpixelflinger/raster.cpp
+++ b/libpixelflinger/raster.cpp
@@ -51,7 +51,7 @@
}
void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
- GGLsizei width, GGLsizei height, GGLenum type)
+ GGLsizei width, GGLsizei height, GGLenum /*type*/)
{
GGL_CONTEXT(c, con);
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index aa23ca6..f84a28a 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -26,6 +26,10 @@
#include <cutils/memory.h>
#include <cutils/log.h>
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+
#include "buffer.h"
#include "scanline.h"
@@ -408,10 +412,10 @@
GGLAssembler assembler( new ArmToArm64Assembler(a) );
#endif
// generate the scanline code for the given needs
- int err = assembler.scanline(c->state.needs, c);
+ bool err = assembler.scanline(c->state.needs, c) != 0;
if (ggl_likely(!err)) {
// finally, cache this assembly
- err = gCodeCache.cache(a->key(), a);
+ err = gCodeCache.cache(a->key(), a) < 0;
}
if (ggl_unlikely(err)) {
ALOGE("error generating or caching assembly. Reverting to NOP.");
@@ -534,7 +538,7 @@
return x;
}
-void blend_factor(context_t* c, pixel_t* r,
+void blend_factor(context_t* /*c*/, pixel_t* r,
uint32_t factor, const pixel_t* src, const pixel_t* dst)
{
switch (factor) {
@@ -1161,7 +1165,7 @@
* blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
*/
struct blender_32to16 {
- blender_32to16(context_t* c) { }
+ blender_32to16(context_t* /*c*/) { }
void write(uint32_t s, uint16_t* dst) {
if (s == 0)
return;
@@ -1218,7 +1222,7 @@
* where dstFactor=srcA*(1-srcA) srcFactor=srcA
*/
struct blender_32to16_srcA {
- blender_32to16_srcA(const context_t* c) { }
+ blender_32to16_srcA(const context_t* /*c*/) { }
void write(uint32_t s, uint16_t* dst) {
if (!s) {
return;
@@ -2317,7 +2321,7 @@
memset(dst, 0xFF, size);
}
-void scanline_noop(context_t* c)
+void scanline_noop(context_t* /*c*/)
{
}
diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
index 84381d5..456be58 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
@@ -405,11 +405,11 @@
};
-int flushcache()
+void flushcache()
{
const long base = long(instrMem);
const long curr = base + long(instrMemSize);
- return cacheflush(base, curr, 0);
+ __builtin___clear_cache((void*)base, (void*)curr);
}
void dataOpTest(dataOpTest_t test, ARMAssemblerInterface *a64asm, uint32_t Rd = 0,
uint32_t Rn = 1, uint32_t Rm = 2, uint32_t Rs = 3)
diff --git a/libpixelflinger/tests/gglmul/gglmul_test.cpp b/libpixelflinger/tests/gglmul/gglmul_test.cpp
index 073368e..5d460d6 100644
--- a/libpixelflinger/tests/gglmul/gglmul_test.cpp
+++ b/libpixelflinger/tests/gglmul/gglmul_test.cpp
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdint.h>
+#include <inttypes.h>
#include "private/pixelflinger/ggl_fixed.h"
@@ -260,12 +261,12 @@
if(actual == expected)
printf(" Passed\n");
else
- printf(" Failed Actual(%ld) Expected(%ld)\n",
+ printf(" Failed Actual(%" PRId64 ") Expected(%" PRId64 ")\n",
actual, expected);
}
}
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
gglClampx_test();
gglClz_test();
diff --git a/libsparse/defs.h b/libsparse/defs.h
new file mode 100644
index 0000000..34e63c5
--- /dev/null
+++ b/libsparse/defs.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBSPARSE_DEFS_H_
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
+#endif /* _LIBSPARSE_DEFS_H_ */
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index e63c4a9..1cf8d8d 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <zlib.h>
+#include "defs.h"
#include "output_file.h"
#include "sparse_format.h"
#include "sparse_crc32.h"
@@ -264,7 +265,7 @@
.close = gz_file_close,
};
-static int callback_file_open(struct output_file *out, int fd)
+static int callback_file_open(struct output_file *out __unused, int fd __unused)
{
return 0;
}
@@ -287,7 +288,7 @@
return 0;
}
-static int callback_file_pad(struct output_file *out, int64_t len)
+static int callback_file_pad(struct output_file *out __unused, int64_t len __unused)
{
return -1;
}
@@ -631,8 +632,8 @@
}
struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
- void *priv, unsigned int block_size, int64_t len, int gz, int sparse,
- int chunks, int crc)
+ void *priv, unsigned int block_size, int64_t len,
+ int gz __unused, int sparse, int chunks, int crc)
{
int ret;
struct output_file_callback *outc;
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index 741e8c6..0f107b0 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -19,6 +19,7 @@
#include <sparse/sparse.h>
+#include "defs.h"
#include "sparse_file.h"
#include "output_file.h"
@@ -189,7 +190,7 @@
return ret;
}
-static int out_counter_write(void *priv, const void *data, int len)
+static int out_counter_write(void *priv, const void *data __unused, int len)
{
int64_t *count = priv;
*count += len;
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index 704bcfa..873c87c 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -29,6 +29,8 @@
#include <sparse/sparse.h>
+#include "defs.h"
+#include "output_file.h"
#include "sparse_crc32.h"
#include "sparse_file.h"
#include "sparse_format.h"
@@ -175,7 +177,8 @@
}
static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
- int fd, unsigned int blocks, unsigned int block, uint32_t *crc32)
+ int fd __unused, unsigned int blocks,
+ unsigned int block __unused, uint32_t *crc32)
{
int ret;
int chunk;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 3625d93..d3ce8f5 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -1,10 +1,11 @@
#include <alloca.h>
#include <errno.h>
-#include <sys/socket.h>
-#include <sys/types.h>
#include <pthread.h>
+#include <signal.h>
#include <string.h>
#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#define LOG_TAG "SocketClient"
#include <cutils/log.h>
@@ -43,8 +44,7 @@
}
}
-SocketClient::~SocketClient()
-{
+SocketClient::~SocketClient() {
if (mSocketOwned) {
close(mSocket);
}
@@ -180,10 +180,19 @@
return 0;
}
+ int ret = 0;
+ int e = 0; // SLOGW and sigaction are not inert regarding errno
int current = 0;
+ struct sigaction new_action, old_action;
+ memset(&new_action, 0, sizeof(new_action));
+ new_action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &new_action, &old_action);
+
for (;;) {
- ssize_t rc = writev(mSocket, iov + current, iovcnt - current);
+ ssize_t rc = TEMP_FAILURE_RETRY(
+ writev(mSocket, iov + current, iovcnt - current));
+
if (rc > 0) {
size_t written = rc;
while ((current < iovcnt) && (written >= iov[current].iov_len)) {
@@ -198,18 +207,21 @@
continue;
}
- if (rc < 0 && errno == EINTR)
- continue;
-
if (rc == 0) {
+ e = EIO;
SLOGW("0 length write :(");
- errno = EIO;
} else {
- SLOGW("write error (%s)", strerror(errno));
+ e = errno;
+ SLOGW("write error (%s)", strerror(e));
}
- return -1;
+ ret = -1;
+ break;
}
- return 0;
+
+ sigaction(SIGPIPE, &old_action, &new_action);
+
+ errno = e;
+ return ret;
}
void SocketClient::incRef() {
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 5c75206..527a6a0 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -70,6 +70,10 @@
}
int SocketListener::startListener() {
+ return startListener(4);
+}
+
+int SocketListener::startListener(int backlog) {
if (!mSocketName && mSock == -1) {
SLOGE("Failed to start unbound listener");
@@ -84,7 +88,7 @@
SLOGV("got mSock = %d for %s", mSock, mSocketName);
}
- if (mListen && listen(mSock, 4) < 0) {
+ if (mListen && listen(mSock, backlog) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index 9565cc5..acfc020 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -14,7 +14,7 @@
# limitations under the License.
#
-LOCAL_PATH := $(my-dir)
+LOCAL_PATH := $(call my-dir)
# Static library for Linux host
# ========================================================
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index e852d77..8acb4d4 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -323,8 +323,17 @@
status_t String8::appendFormatV(const char* fmt, va_list args)
{
- int result = NO_ERROR;
- int n = vsnprintf(NULL, 0, fmt, args);
+ int n, result = NO_ERROR;
+ va_list tmp_args;
+
+ /* args is undefined after vsnprintf.
+ * So we need a copy here to avoid the
+ * second vsnprintf access undefined args.
+ */
+ va_copy(tmp_args, args);
+ n = vsnprintf(NULL, 0, fmt, tmp_args);
+ va_end(tmp_args);
+
if (n != 0) {
size_t oldLength = length();
char* buf = lockBuffer(oldLength + n);
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index a23d4ae..01f9249 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -279,7 +279,7 @@
ent = (ent + 1) & (hash_table_size - 1);
}
- ALOGV("Zip: Unable to find entry %.*s", name_length, name);
+ ALOGV("Zip: Unable to find entry %.*s", length, name);
return kEntryNotFound;
}
@@ -591,13 +591,7 @@
archive->directory_map->release();
}
free(archive->hash_table);
-
- /* ensure nobody tries to use the ZipArchive after it's closed */
- archive->directory_offset = -1;
- archive->fd = -1;
- archive->num_entries = -1;
- archive->hash_table_size = -1;
- archive->hash_table = NULL;
+ free(archive);
}
static int32_t UpdateEntryFromDataDescriptor(int fd,
diff --git a/logcat/Android.mk b/logcat/Android.mk
index b5e27eb..dd15cb3 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -3,6 +3,10 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
+LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
+endif
+
LOCAL_SRC_FILES:= logcat.cpp event.logtags
LOCAL_SHARED_LIBRARIES := liblog
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 3c33938..00b5ba9 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -225,11 +225,23 @@
" -t <count> print only the most recent <count> lines (implies -d)\n"
" -T <count> print only the most recent <count> lines (does not imply -d)\n"
" -g get the size of the log's ring buffer and exit\n"
- " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio'\n"
- " or 'events'. Multiple -b parameters are allowed and the\n"
+ " -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
+ " 'events' or 'all'. Multiple -b parameters are allowed and\n"
" results are interleaved. The default is -b main -b system.\n"
- " -B output the log in binary");
+ " -B output the log in binary.\n"
+ " -S output statistics.\n");
+#ifdef USERDEBUG_BUILD
+
+ fprintf(stderr, "--------------------- eng & userdebug builds only ---------------------------\n"
+ " -G <count> set size of log's ring buffer and exit\n"
+ " -p output prune white and ~black list\n"
+ " -P '<list> ...' set prune white and ~black list; UID, /PID or !(worst UID)\n"
+ " default is ~!, prune worst UID.\n"
+ "-----------------------------------------------------------------------------\n"
+ );
+
+#endif
fprintf(stderr,"\nfilterspecs are a series of \n"
" <tag>[:priority]\n\n"
@@ -278,6 +290,12 @@
int hasSetLogFormat = 0;
int clearLog = 0;
int getLogSize = 0;
+#ifdef USERDEBUG_BUILD
+ unsigned long setLogSize = 0;
+ int getPruneList = 0;
+ char *setPruneList = NULL;
+#endif
+ int printStatistics = 0;
int mode = O_RDONLY;
const char *forceFilters = NULL;
log_device_t* devices = NULL;
@@ -303,7 +321,13 @@
for (;;) {
int ret;
- ret = getopt(argc, argv, "cdt:T:gsQf:r::n:v:b:B");
+ ret = getopt(argc, argv,
+#ifdef USERDEBUG_BUILD
+ "cdt:T:gG:sQf:r::n:v:b:BSpP:"
+#else
+ "cdt:T:gsQf:r::n:v:b:BS"
+#endif
+ );
if (ret < 0) {
break;
@@ -335,7 +359,89 @@
getLogSize = 1;
break;
+#ifdef USERDEBUG_BUILD
+
+ case 'G': {
+ // would use atol if not for the multiplier
+ char *cp = optarg;
+ setLogSize = 0;
+ while (('0' <= *cp) && (*cp <= '9')) {
+ setLogSize *= 10;
+ setLogSize += *cp - '0';
+ ++cp;
+ }
+
+ switch(*cp) {
+ case 'g':
+ case 'G':
+ setLogSize *= 1024;
+ /* FALLTHRU */
+ case 'm':
+ case 'M':
+ setLogSize *= 1024;
+ /* FALLTHRU */
+ case 'k':
+ case 'K':
+ setLogSize *= 1024;
+ /* FALLTHRU */
+ case '\0':
+ break;
+
+ default:
+ setLogSize = 0;
+ }
+
+ if (!setLogSize) {
+ fprintf(stderr, "ERROR: -G <num><multiplier>\n");
+ exit(1);
+ }
+ }
+ break;
+
+ case 'p':
+ getPruneList = 1;
+ break;
+
+ case 'P':
+ setPruneList = optarg;
+ break;
+
+#endif
+
case 'b': {
+ if (strcmp(optarg, "all") == 0) {
+ while (devices) {
+ dev = devices;
+ devices = dev->next;
+ delete dev;
+ }
+
+ dev = devices = new log_device_t("main", false, 'm');
+ android::g_devCount = 1;
+ if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
+ dev->next = new log_device_t("system", false, 's');
+ if (dev->next) {
+ dev = dev->next;
+ android::g_devCount++;
+ }
+ }
+ if (android_name_to_log_id("radio") == LOG_ID_RADIO) {
+ dev->next = new log_device_t("radio", false, 'r');
+ if (dev->next) {
+ dev = dev->next;
+ android::g_devCount++;
+ }
+ }
+ if (android_name_to_log_id("events") == LOG_ID_EVENTS) {
+ dev->next = new log_device_t("events", true, 'e');
+ if (dev->next) {
+ android::g_devCount++;
+ needBinary = true;
+ }
+ }
+ break;
+ }
+
bool binary = strcmp(optarg, "events") == 0;
if (binary) {
needBinary = true;
@@ -470,6 +576,10 @@
}
break;
+ case 'S':
+ printStatistics = 1;
+ break;
+
default:
fprintf(stderr,"Unrecognized Option\n");
android::show_help(argv[0]);
@@ -563,8 +673,17 @@
}
}
+#ifdef USERDEBUG_BUILD
+
+ if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
+ perror("setLogSize");
+ exit(EXIT_FAILURE);
+ }
+
+#endif
+
if (getLogSize) {
- int size, readable;
+ long size, readable;
size = android_logger_get_log_size(dev->logger);
if (size < 0) {
@@ -578,7 +697,7 @@
exit(EXIT_FAILURE);
}
- printf("%s: ring buffer is %dKb (%dKb consumed), "
+ printf("%s: ring buffer is %ldKb (%ldKb consumed), "
"max entry is %db, max payload is %db\n", dev->device,
size / 1024, readable / 1024,
(int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
@@ -587,9 +706,95 @@
dev = dev->next;
}
+#ifdef USERDEBUG_BUILD
+
+ if (setPruneList) {
+ size_t len = strlen(setPruneList) + 32; // margin to allow rc
+ char *buf = (char *) malloc(len);
+
+ strcpy(buf, setPruneList);
+ int ret = android_logger_set_prune_list(logger_list, buf, len);
+ free(buf);
+
+ if (ret) {
+ perror("setPruneList");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+#endif
+
+ if (
+#ifdef USERDEBUG_BUILD
+ printStatistics || getPruneList
+#else
+ printStatistics
+#endif
+ ) {
+ size_t len = 8192;
+ char *buf;
+
+ for(int retry = 32;
+ (retry >= 0) && ((buf = new char [len]));
+ delete [] buf, --retry) {
+#ifdef USERDEBUG_BUILD
+ if (getPruneList) {
+ android_logger_get_prune_list(logger_list, buf, len);
+ } else {
+ android_logger_get_statistics(logger_list, buf, len);
+ }
+#else
+ android_logger_get_statistics(logger_list, buf, len);
+#endif
+ buf[len-1] = '\0';
+ size_t ret = atol(buf) + 1;
+ if (ret < 4) {
+ delete [] buf;
+ buf = NULL;
+ break;
+ }
+ bool check = ret <= len;
+ len = ret;
+ if (check) {
+ break;
+ }
+ }
+
+ if (!buf) {
+ perror("response read");
+ exit(EXIT_FAILURE);
+ }
+
+ // remove trailing FF
+ char *cp = buf + len - 1;
+ *cp = '\0';
+ bool truncated = *--cp != '\f';
+ if (!truncated) {
+ *cp = '\0';
+ }
+
+ // squash out the byte count
+ cp = buf;
+ if (!truncated) {
+ while (isdigit(*cp) || (*cp == '\n')) {
+ ++cp;
+ }
+ }
+
+ printf("%s", cp);
+ delete [] buf;
+ exit(0);
+ }
+
+
if (getLogSize) {
exit(0);
}
+#ifdef USERDEBUG_BUILD
+ if (setLogSize || setPruneList) {
+ exit(0);
+ }
+#endif
if (clearLog) {
exit(0);
}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index f963a3a..fc696bb 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -319,12 +319,16 @@
TEST(logcat, blocking) {
FILE *fp;
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
+ unsigned long long v = 0xDEADBEEFA55F0000ULL;
pid_t pid = getpid();
v += pid & 0xFFFF;
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+
+ v &= 0xFFFFFFFFFFFAFFFFULL;
+
ASSERT_EQ(0, NULL == (fp = popen(
"( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
" logcat -b events 2>&1",
@@ -341,12 +345,12 @@
while (fgets(buffer, sizeof(buffer), fp)) {
alarm(2);
- ++count;
-
if (!strncmp(buffer, "DONE", 4)) {
break;
}
+ ++count;
+
int p;
unsigned long long l;
@@ -369,7 +373,7 @@
pclose(fp);
- ASSERT_LT(10, count);
+ ASSERT_LE(2, count);
ASSERT_EQ(1, signals);
}
@@ -385,12 +389,16 @@
TEST(logcat, blocking_tail) {
FILE *fp;
- unsigned long long v = 0xA55ADEADBEEF0000ULL;
+ unsigned long long v = 0xA55FDEADBEEF0000ULL;
pid_t pid = getpid();
v += pid & 0xFFFF;
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+
+ v &= 0xFFFAFFFFFFFFFFFFULL;
+
ASSERT_EQ(0, NULL == (fp = popen(
"( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
" logcat -b events -T 5 2>&1",
@@ -407,12 +415,12 @@
while (fgets(buffer, sizeof(buffer), fp)) {
alarm(2);
- ++count;
-
if (!strncmp(buffer, "DONE", 4)) {
break;
}
+ ++count;
+
int p;
unsigned long long l;
@@ -431,13 +439,91 @@
alarm(0);
signal(SIGALRM, SIG_DFL);
- /* Generate SIGPIPE */
+ // Generate SIGPIPE
fclose(fp);
caught_blocking_tail(0);
pclose(fp);
- ASSERT_LT(5, count);
+ ASSERT_LE(2, count);
+
+ ASSERT_EQ(1, signals);
+}
+
+static void caught_blocking_clear(int signum)
+{
+ unsigned long long v = 0xDEADBEEFA55C0000ULL;
+
+ v += getpid() & 0xFFFF;
+
+ LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+}
+
+TEST(logcat, blocking_clear) {
+ FILE *fp;
+ unsigned long long v = 0xDEADBEEFA55C0000ULL;
+
+ pid_t pid = getpid();
+
+ v += pid & 0xFFFF;
+
+ // This test is racey; an event occurs between clear and dump.
+ // We accept that we will get a false positive, but never a false negative.
+ ASSERT_EQ(0, NULL == (fp = popen(
+ "( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
+ " logcat -b events -c 2>&1 ;"
+ " logcat -b events 2>&1",
+ "r")));
+
+ char buffer[5120];
+
+ int count = 0;
+
+ int signals = 0;
+
+ signal(SIGALRM, caught_blocking_clear);
+ alarm(2);
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ alarm(2);
+
+ if (!strncmp(buffer, "clearLog: ", 10)) {
+ fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
+ count = signals = 1;
+ break;
+ }
+
+ if (!strncmp(buffer, "DONE", 4)) {
+ break;
+ }
+
+ ++count;
+
+ int p;
+ unsigned long long l;
+
+ if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l))
+ || (p != pid)) {
+ continue;
+ }
+
+ if (l == v) {
+ if (count > 1) {
+ fprintf(stderr, "WARNING: Possible false positive\n");
+ }
+ ++signals;
+ break;
+ }
+ }
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+
+ // Generate SIGPIPE
+ fclose(fp);
+ caught_blocking_clear(0);
+
+ pclose(fp);
+
+ ASSERT_LE(1, count);
ASSERT_EQ(1, signals);
}
diff --git a/logd/Android.mk b/logd/Android.mk
new file mode 100644
index 0000000..b0bc746
--- /dev/null
+++ b/logd/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= logd
+
+ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
+LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
+endif
+
+LOCAL_SRC_FILES := \
+ main.cpp \
+ LogCommand.cpp \
+ CommandListener.cpp \
+ LogListener.cpp \
+ LogReader.cpp \
+ FlushCommand.cpp \
+ LogBuffer.cpp \
+ LogBufferElement.cpp \
+ LogTimes.cpp \
+ LogStatistics.cpp \
+ LogWhiteBlackList.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libsysutils \
+ liblog \
+ libcutils \
+ libutils
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
new file mode 100644
index 0000000..12b10ca
--- /dev/null
+++ b/logd/CommandListener.cpp
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <private/android_filesystem_config.h>
+#include <sysutils/SocketClient.h>
+
+#include "CommandListener.h"
+#include "LogCommand.h"
+
+CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
+ LogListener * /*swl*/)
+ : FrameworkListener("logd")
+ , mBuf(*buf) {
+ // registerCmd(new ShutdownCmd(buf, writer, swl));
+ registerCmd(new ClearCmd(buf));
+ registerCmd(new GetBufSizeCmd(buf));
+#ifdef USERDEBUG_BUILD
+ registerCmd(new SetBufSizeCmd(buf));
+#endif
+ registerCmd(new GetBufSizeUsedCmd(buf));
+ registerCmd(new GetStatisticsCmd(buf));
+#ifdef USERDEBUG_BUILD
+ registerCmd(new SetPruneListCmd(buf));
+ registerCmd(new GetPruneListCmd(buf));
+#endif
+}
+
+CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
+ LogListener *swl)
+ : LogCommand("shutdown")
+ , mBuf(*buf)
+ , mReader(*reader)
+ , mSwl(*swl)
+{ }
+
+int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
+ int /*argc*/,
+ char ** /*argv*/) {
+ mSwl.stopListener();
+ mReader.stopListener();
+ exit(0);
+}
+
+CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
+ : LogCommand("clear")
+ , mBuf(*buf)
+{ }
+
+int CommandListener::ClearCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (!clientHasLogCredentials(cli)) {
+ cli->sendMsg("Permission Denied");
+ return 0;
+ }
+
+ if (argc < 2) {
+ cli->sendMsg("Missing Argument");
+ return 0;
+ }
+
+ int id = atoi(argv[1]);
+ if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+ cli->sendMsg("Range Error");
+ return 0;
+ }
+
+ mBuf.clear((log_id_t) id);
+ cli->sendMsg("success");
+ return 0;
+}
+
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
+ : LogCommand("getLogSize")
+ , mBuf(*buf)
+{ }
+
+int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc < 2) {
+ cli->sendMsg("Missing Argument");
+ return 0;
+ }
+
+ int id = atoi(argv[1]);
+ if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+ cli->sendMsg("Range Error");
+ return 0;
+ }
+
+ unsigned long size = mBuf.getSize((log_id_t) id);
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%lu", size);
+ cli->sendMsg(buf);
+ return 0;
+}
+
+#ifdef USERDEBUG_BUILD
+
+CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
+ : LogCommand("setLogSize")
+ , mBuf(*buf)
+{ }
+
+int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (!clientHasLogCredentials(cli)) {
+ cli->sendMsg("Permission Denied");
+ return 0;
+ }
+
+ if (argc < 3) {
+ cli->sendMsg("Missing Argument");
+ return 0;
+ }
+
+ int id = atoi(argv[1]);
+ if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+ cli->sendMsg("Range Error");
+ return 0;
+ }
+
+ unsigned long size = atol(argv[2]);
+ if (mBuf.setSize((log_id_t) id, size)) {
+ cli->sendMsg("Range Error");
+ return 0;
+ }
+
+ cli->sendMsg("success");
+ return 0;
+}
+
+#endif // USERDEBUG_BUILD
+
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
+ : LogCommand("getLogSizeUsed")
+ , mBuf(*buf)
+{ }
+
+int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc < 2) {
+ cli->sendMsg("Missing Argument");
+ return 0;
+ }
+
+ int id = atoi(argv[1]);
+ if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+ cli->sendMsg("Range Error");
+ return 0;
+ }
+
+ unsigned long size = mBuf.getSizeUsed((log_id_t) id);
+ char buf[512];
+ snprintf(buf, sizeof(buf), "%lu", size);
+ cli->sendMsg(buf);
+ return 0;
+}
+
+CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
+ : LogCommand("getStatistics")
+ , mBuf(*buf)
+{ }
+
+static void package_string(char **strp) {
+ const char *a = *strp;
+ if (!a) {
+ a = "";
+ }
+
+ // Calculate total buffer size prefix, count is the string length w/o nul
+ char fmt[32];
+ for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
+ snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
+ }
+
+ char *b = *strp;
+ *strp = NULL;
+ asprintf(strp, fmt, a);
+ free(b);
+}
+
+int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ uid_t uid = cli->getUid();
+ gid_t gid = cli->getGid();
+ if (clientHasLogCredentials(cli)) {
+ uid = AID_ROOT;
+ }
+
+ unsigned int logMask = -1;
+ if (argc > 1) {
+ logMask = 0;
+ for (int i = 1; i < argc; ++i) {
+ int id = atoi(argv[i]);
+ if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
+ cli->sendMsg("Range Error");
+ return 0;
+ }
+ logMask |= 1 << id;
+ }
+ }
+
+ char *buf = NULL;
+
+ mBuf.formatStatistics(&buf, uid, logMask);
+ if (!buf) {
+ cli->sendMsg("Failed");
+ } else {
+ package_string(&buf);
+ cli->sendMsg(buf);
+ free(buf);
+ }
+ return 0;
+}
+
+#ifdef USERDEBUG_BUILD
+
+CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
+ : LogCommand("getPruneList")
+ , mBuf(*buf)
+{ }
+
+int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
+ int /*argc*/, char ** /*argv*/) {
+ char *buf = NULL;
+ mBuf.formatPrune(&buf);
+ if (!buf) {
+ cli->sendMsg("Failed");
+ } else {
+ package_string(&buf);
+ cli->sendMsg(buf);
+ free(buf);
+ }
+ return 0;
+}
+
+CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
+ : LogCommand("setPruneList")
+ , mBuf(*buf)
+{ }
+
+int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (!clientHasLogCredentials(cli)) {
+ cli->sendMsg("Permission Denied");
+ return 0;
+ }
+
+ char *cp = NULL;
+ for (int i = 1; i < argc; ++i) {
+ char *p = cp;
+ if (p) {
+ cp = NULL;
+ asprintf(&cp, "%s %s", p, argv[i]);
+ free(p);
+ } else {
+ asprintf(&cp, "%s", argv[i]);
+ }
+ }
+
+ int ret = mBuf.initPrune(cp);
+ free(cp);
+
+ if (ret) {
+ cli->sendMsg("Invalid");
+ return 0;
+ }
+
+ cli->sendMsg("success");
+
+ return 0;
+}
+
+#endif // USERDEBUG_BUILD
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
new file mode 100644
index 0000000..de1dcb9
--- /dev/null
+++ b/logd/CommandListener.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _COMMANDLISTENER_H__
+#define _COMMANDLISTENER_H__
+
+#include <sysutils/FrameworkListener.h>
+#include "LogCommand.h"
+#include "LogBuffer.h"
+#include "LogReader.h"
+#include "LogListener.h"
+
+class CommandListener : public FrameworkListener {
+ LogBuffer &mBuf;
+
+public:
+ CommandListener(LogBuffer *buf, LogReader *reader, LogListener *swl);
+ virtual ~CommandListener() {}
+
+private:
+ class ShutdownCmd : public LogCommand {
+ LogBuffer &mBuf;
+ LogReader &mReader;
+ LogListener &mSwl;
+
+ public:
+ ShutdownCmd(LogBuffer *buf, LogReader *reader, LogListener *swl);
+ virtual ~ShutdownCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+#define LogBufferCmd(name) \
+ class name##Cmd : public LogCommand { \
+ LogBuffer &mBuf; \
+ public: \
+ name##Cmd(LogBuffer *buf); \
+ virtual ~name##Cmd() {} \
+ int runCommand(SocketClient *c, int argc, char ** argv); \
+ };
+
+ LogBufferCmd(Clear)
+ LogBufferCmd(GetBufSize)
+#ifdef USERDEBUG_BUILD
+ LogBufferCmd(SetBufSize)
+#endif
+ LogBufferCmd(GetBufSizeUsed)
+ LogBufferCmd(GetStatistics)
+#ifdef USERDEBUG_BUILD
+ LogBufferCmd(GetPruneList)
+ LogBufferCmd(SetPruneList)
+#endif
+};
+
+#endif
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
new file mode 100644
index 0000000..0b8c31b
--- /dev/null
+++ b/logd/FlushCommand.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "FlushCommand.h"
+#include "LogBufferElement.h"
+#include "LogCommand.h"
+#include "LogReader.h"
+#include "LogTimes.h"
+
+FlushCommand::FlushCommand(LogReader &reader,
+ bool nonBlock,
+ unsigned long tail,
+ unsigned int logMask,
+ pid_t pid)
+ : mReader(reader)
+ , mNonBlock(nonBlock)
+ , mTail(tail)
+ , mLogMask(logMask)
+ , mPid(pid)
+{ }
+
+// runSocketCommand is called once for every open client on the
+// log reader socket. Here we manage and associated the reader
+// client tracking and log region locks LastLogTimes list of
+// LogTimeEntrys, and spawn a transitory per-client thread to
+// work at filing data to the socket.
+//
+// global LogTimeEntry::lock() is used to protect access,
+// reference counts are used to ensure that individual
+// LogTimeEntry lifetime is managed when not protected.
+void FlushCommand::runSocketCommand(SocketClient *client) {
+ LogTimeEntry *entry = NULL;
+ LastLogTimes × = mReader.logbuf().mTimes;
+
+ LogTimeEntry::lock();
+ LastLogTimes::iterator it = times.begin();
+ while(it != times.end()) {
+ entry = (*it);
+ if (entry->mClient == client) {
+ entry->triggerReader_Locked();
+ if (entry->runningReader_Locked()) {
+ LogTimeEntry::unlock();
+ return;
+ }
+ entry->incRef_Locked();
+ break;
+ }
+ it++;
+ }
+
+ if (it == times.end()) {
+ // Create LogTimeEntry in notifyNewLog() ?
+ if (mTail == (unsigned long) -1) {
+ LogTimeEntry::unlock();
+ return;
+ }
+ entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid);
+ times.push_back(entry);
+ }
+
+ client->incRef();
+
+ // release client and entry reference counts once done
+ entry->startReader_Locked();
+ LogTimeEntry::unlock();
+}
+
+bool FlushCommand::hasReadLogs(SocketClient *client) {
+ return clientHasLogCredentials(client);
+}
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
new file mode 100644
index 0000000..715daac
--- /dev/null
+++ b/logd/FlushCommand.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _FLUSH_COMMAND_H
+#define _FLUSH_COMMAND_H
+
+#include <sysutils/SocketClientCommand.h>
+
+class LogReader;
+
+class FlushCommand : public SocketClientCommand {
+ LogReader &mReader;
+ bool mNonBlock;
+ unsigned long mTail;
+ unsigned int mLogMask;
+ pid_t mPid;
+
+public:
+ FlushCommand(LogReader &mReader,
+ bool nonBlock = false,
+ unsigned long tail = -1,
+ unsigned int logMask = -1,
+ pid_t pid = 0);
+ virtual void runSocketCommand(SocketClient *client);
+
+ static bool hasReadLogs(SocketClient *client);
+};
+
+#endif
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
new file mode 100644
index 0000000..197b7e8
--- /dev/null
+++ b/logd/LogBuffer.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <log/logger.h>
+
+#include "LogBuffer.h"
+#include "LogStatistics.h"
+#include "LogWhiteBlackList.h"
+#include "LogReader.h"
+
+// Default
+#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
+#ifdef USERDEBUG_BUILD
+#define log_buffer_size(id) mMaxSize[id]
+#else
+#define log_buffer_size(id) LOG_BUFFER_SIZE
+#endif
+
+LogBuffer::LogBuffer(LastLogTimes *times)
+ : mTimes(*times) {
+ pthread_mutex_init(&mLogElementsLock, NULL);
+#ifdef USERDEBUG_BUILD
+ log_id_for_each(i) {
+ mMaxSize[i] = LOG_BUFFER_SIZE;
+ }
+#endif
+}
+
+void LogBuffer::log(log_id_t log_id, log_time realtime,
+ uid_t uid, pid_t pid, const char *msg,
+ unsigned short len) {
+ if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
+ return;
+ }
+ LogBufferElement *elem = new LogBufferElement(log_id, realtime,
+ uid, pid, msg, len);
+
+ pthread_mutex_lock(&mLogElementsLock);
+
+ // Insert elements in time sorted order if possible
+ // NB: if end is region locked, place element at end of list
+ LogBufferElementCollection::iterator it = mLogElements.end();
+ LogBufferElementCollection::iterator last = it;
+ while (--it != mLogElements.begin()) {
+ if ((*it)->getRealTime() <= realtime) {
+ break;
+ }
+ last = it;
+ }
+
+ if (last == mLogElements.end()) {
+ mLogElements.push_back(elem);
+ } else {
+ log_time end;
+ bool end_set = false;
+ bool end_always = false;
+
+ LogTimeEntry::lock();
+
+ LastLogTimes::iterator t = mTimes.begin();
+ while(t != mTimes.end()) {
+ LogTimeEntry *entry = (*t);
+ if (entry->owned_Locked()) {
+ if (!entry->mNonBlock) {
+ end_always = true;
+ break;
+ }
+ if (!end_set || (end <= entry->mEnd)) {
+ end = entry->mEnd;
+ end_set = true;
+ }
+ }
+ t++;
+ }
+
+ if (end_always
+ || (end_set && (end >= (*last)->getMonotonicTime()))) {
+ mLogElements.push_back(elem);
+ } else {
+ mLogElements.insert(last,elem);
+ }
+
+ LogTimeEntry::unlock();
+ }
+
+ stats.add(len, log_id, uid, pid);
+ maybePrune(log_id);
+ pthread_mutex_unlock(&mLogElementsLock);
+}
+
+// If we're using more than 256K of memory for log entries, prune
+// at least 10% of the log entries.
+//
+// mLogElementsLock must be held when this function is called.
+void LogBuffer::maybePrune(log_id_t id) {
+ size_t sizes = stats.sizes(id);
+ if (sizes > log_buffer_size(id)) {
+ size_t sizeOver90Percent = sizes - ((log_buffer_size(id) * 9) / 10);
+ size_t elements = stats.elements(id);
+ unsigned long pruneRows = elements * sizeOver90Percent / sizes;
+ elements /= 10;
+ if (pruneRows <= elements) {
+ pruneRows = elements;
+ }
+ prune(id, pruneRows);
+ }
+}
+
+// prune "pruneRows" of type "id" from the buffer.
+//
+// mLogElementsLock must be held when this function is called.
+void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
+ LogTimeEntry *oldest = NULL;
+
+ LogTimeEntry::lock();
+
+ // Region locked?
+ LastLogTimes::iterator t = mTimes.begin();
+ while(t != mTimes.end()) {
+ LogTimeEntry *entry = (*t);
+ if (entry->owned_Locked()
+ && (!oldest || (oldest->mStart > entry->mStart))) {
+ oldest = entry;
+ }
+ t++;
+ }
+
+ LogBufferElementCollection::iterator it;
+
+ // prune by worst offender by uid
+ while (pruneRows > 0) {
+ // recalculate the worst offender on every batched pass
+ uid_t worst = (uid_t) -1;
+ size_t worst_sizes = 0;
+ size_t second_worst_sizes = 0;
+
+#ifdef USERDEBUG_BUILD
+ if (mPrune.worstUidEnabled())
+#endif
+ {
+ LidStatistics &l = stats.id(id);
+ UidStatisticsCollection::iterator iu;
+ for (iu = l.begin(); iu != l.end(); ++iu) {
+ UidStatistics *u = (*iu);
+ size_t sizes = u->sizes();
+ if (worst_sizes < sizes) {
+ second_worst_sizes = worst_sizes;
+ worst_sizes = sizes;
+ worst = u->getUid();
+ }
+ if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) {
+ second_worst_sizes = sizes;
+ }
+ }
+ }
+
+ bool kick = false;
+ for(it = mLogElements.begin(); it != mLogElements.end();) {
+ LogBufferElement *e = *it;
+
+ if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+ break;
+ }
+
+ if (e->getLogId() != id) {
+ ++it;
+ continue;
+ }
+
+ uid_t uid = e->getUid();
+
+ if (uid == worst) {
+ it = mLogElements.erase(it);
+ unsigned short len = e->getMsgLen();
+ stats.subtract(len, id, worst, e->getPid());
+ delete e;
+ kick = true;
+ pruneRows--;
+ if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
+ break;
+ }
+ worst_sizes -= len;
+ }
+#ifdef USERDEBUG_BUILD
+ else if (mPrune.naughty(e)) { // BlackListed
+ it = mLogElements.erase(it);
+ stats.subtract(e->getMsgLen(), id, uid, e->getPid());
+ delete e;
+ pruneRows--;
+ if (pruneRows == 0) {
+ break;
+ }
+ }
+#endif
+ else {
+ ++it;
+ }
+ }
+
+ if (!kick
+#ifdef USERDEBUG_BUILD
+ || !mPrune.worstUidEnabled()
+#endif
+ ) {
+ break; // the following loop will ask bad clients to skip/drop
+ }
+ }
+
+#ifdef USERDEBUG_BUILD
+ bool whitelist = false;
+#endif
+ it = mLogElements.begin();
+ while((pruneRows > 0) && (it != mLogElements.end())) {
+ LogBufferElement *e = *it;
+ if (e->getLogId() == id) {
+ if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+#ifdef USERDEBUG_BUILD
+ if (!whitelist)
+#endif
+ {
+ if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+ // kick a misbehaving log reader client off the island
+ oldest->release_Locked();
+ } else {
+ oldest->triggerSkip_Locked(pruneRows);
+ }
+ }
+ break;
+ }
+#ifdef USERDEBUG_BUILD
+ if (mPrune.nice(e)) { // WhiteListed
+ whitelist = true;
+ it++;
+ continue;
+ }
+#endif
+ it = mLogElements.erase(it);
+ stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
+ delete e;
+ pruneRows--;
+ } else {
+ it++;
+ }
+ }
+
+#ifdef USERDEBUG_BUILD
+ if (whitelist && (pruneRows > 0)) {
+ it = mLogElements.begin();
+ while((it != mLogElements.end()) && (pruneRows > 0)) {
+ LogBufferElement *e = *it;
+ if (e->getLogId() == id) {
+ if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+ if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+ // kick a misbehaving log reader client off the island
+ oldest->release_Locked();
+ } else {
+ oldest->triggerSkip_Locked(pruneRows);
+ }
+ break;
+ }
+ it = mLogElements.erase(it);
+ stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
+ delete e;
+ pruneRows--;
+ } else {
+ it++;
+ }
+ }
+ }
+#endif
+
+ LogTimeEntry::unlock();
+}
+
+// clear all rows of type "id" from the buffer.
+void LogBuffer::clear(log_id_t id) {
+ pthread_mutex_lock(&mLogElementsLock);
+ prune(id, ULONG_MAX);
+ pthread_mutex_unlock(&mLogElementsLock);
+}
+
+// get the used space associated with "id".
+unsigned long LogBuffer::getSizeUsed(log_id_t id) {
+ pthread_mutex_lock(&mLogElementsLock);
+ size_t retval = stats.sizes(id);
+ pthread_mutex_unlock(&mLogElementsLock);
+ return retval;
+}
+
+#ifdef USERDEBUG_BUILD
+
+// set the total space allocated to "id"
+int LogBuffer::setSize(log_id_t id, unsigned long size) {
+ // Reasonable limits ...
+ if ((size < (64 * 1024)) || ((256 * 1024 * 1024) < size)) {
+ return -1;
+ }
+ pthread_mutex_lock(&mLogElementsLock);
+ log_buffer_size(id) = size;
+ pthread_mutex_unlock(&mLogElementsLock);
+ return 0;
+}
+
+// get the total space allocated to "id"
+unsigned long LogBuffer::getSize(log_id_t id) {
+ pthread_mutex_lock(&mLogElementsLock);
+ size_t retval = log_buffer_size(id);
+ pthread_mutex_unlock(&mLogElementsLock);
+ return retval;
+}
+
+#else // ! USERDEBUG_BUILD
+
+// get the total space allocated to "id"
+unsigned long LogBuffer::getSize(log_id_t /*id*/) {
+ return log_buffer_size(id);
+}
+
+#endif
+
+log_time LogBuffer::flushTo(
+ SocketClient *reader, const log_time start, bool privileged,
+ bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
+ LogBufferElementCollection::iterator it;
+ log_time max = start;
+ uid_t uid = reader->getUid();
+
+ pthread_mutex_lock(&mLogElementsLock);
+ for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
+ LogBufferElement *element = *it;
+
+ if (!privileged && (element->getUid() != uid)) {
+ continue;
+ }
+
+ if (element->getMonotonicTime() <= start) {
+ continue;
+ }
+
+ // NB: calling out to another object with mLogElementsLock held (safe)
+ if (filter && !(*filter)(element, arg)) {
+ continue;
+ }
+
+ pthread_mutex_unlock(&mLogElementsLock);
+
+ // range locking in LastLogTimes looks after us
+ max = element->flushTo(reader);
+
+ if (max == element->FLUSH_ERROR) {
+ return max;
+ }
+
+ pthread_mutex_lock(&mLogElementsLock);
+ }
+ pthread_mutex_unlock(&mLogElementsLock);
+
+ return max;
+}
+
+void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
+ log_time oldest(CLOCK_MONOTONIC);
+
+ pthread_mutex_lock(&mLogElementsLock);
+
+ // Find oldest element in the log(s)
+ LogBufferElementCollection::iterator it;
+ for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
+ LogBufferElement *element = *it;
+
+ if ((logMask & (1 << element->getLogId()))) {
+ oldest = element->getMonotonicTime();
+ break;
+ }
+ }
+
+ stats.format(strp, uid, logMask, oldest);
+
+ pthread_mutex_unlock(&mLogElementsLock);
+}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
new file mode 100644
index 0000000..0745e56
--- /dev/null
+++ b/logd/LogBuffer.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_BUFFER_H__
+#define _LOGD_LOG_BUFFER_H__
+
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <sysutils/SocketClient.h>
+#include <utils/List.h>
+
+#include "LogBufferElement.h"
+#include "LogTimes.h"
+#include "LogStatistics.h"
+#include "LogWhiteBlackList.h"
+
+typedef android::List<LogBufferElement *> LogBufferElementCollection;
+
+class LogBuffer {
+ LogBufferElementCollection mLogElements;
+ pthread_mutex_t mLogElementsLock;
+
+ LogStatistics stats;
+
+#ifdef USERDEBUG_BUILD
+ PruneList mPrune;
+
+ unsigned long mMaxSize[LOG_ID_MAX];
+#endif
+
+public:
+ LastLogTimes &mTimes;
+
+ LogBuffer(LastLogTimes *times);
+
+ void log(log_id_t log_id, log_time realtime,
+ uid_t uid, pid_t pid, const char *msg, unsigned short len);
+ log_time flushTo(SocketClient *writer, const log_time start,
+ bool privileged,
+ bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
+ void *arg = NULL);
+
+ void clear(log_id_t id);
+ unsigned long getSize(log_id_t id);
+#ifdef USERDEBUG_BUILD
+ int setSize(log_id_t id, unsigned long size);
+#endif
+ unsigned long getSizeUsed(log_id_t id);
+ // *strp uses malloc, use free to release.
+ void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
+
+#ifdef USERDEBUG_BUILD
+ int initPrune(char *cp) { return mPrune.init(cp); }
+ // *strp uses malloc, use free to release.
+ void formatPrune(char **strp) { mPrune.format(strp); }
+#endif
+
+private:
+ void maybePrune(log_id_t id);
+ void prune(log_id_t id, unsigned long pruneRows);
+
+};
+
+#endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
new file mode 100644
index 0000000..01cc9de
--- /dev/null
+++ b/logd/LogBufferElement.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <log/logger.h>
+
+#include "LogBufferElement.h"
+#include "LogReader.h"
+
+const log_time LogBufferElement::FLUSH_ERROR(0, 0);
+
+LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
+ uid_t uid, pid_t pid, const char *msg,
+ unsigned short len)
+ : mLogId(log_id)
+ , mUid(uid)
+ , mPid(pid)
+ , mMsgLen(len)
+ , mMonotonicTime(CLOCK_MONOTONIC)
+ , mRealTime(realtime) {
+ mMsg = new char[len];
+ memcpy(mMsg, msg, len);
+}
+
+LogBufferElement::~LogBufferElement() {
+ delete [] mMsg;
+}
+
+log_time LogBufferElement::flushTo(SocketClient *reader) {
+ struct logger_entry_v3 entry;
+ memset(&entry, 0, sizeof(struct logger_entry_v3));
+ entry.hdr_size = sizeof(struct logger_entry_v3);
+ entry.len = mMsgLen;
+ entry.lid = mLogId;
+ entry.pid = mPid;
+ entry.sec = mRealTime.tv_sec;
+ entry.nsec = mRealTime.tv_nsec;
+
+ struct iovec iovec[2];
+ iovec[0].iov_base = &entry;
+ iovec[0].iov_len = sizeof(struct logger_entry_v3);
+ iovec[1].iov_base = mMsg;
+ iovec[1].iov_len = mMsgLen;
+ if (reader->sendDatav(iovec, 2)) {
+ return FLUSH_ERROR;
+ }
+
+ return mMonotonicTime;
+}
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
new file mode 100644
index 0000000..1da09ae
--- /dev/null
+++ b/logd/LogBufferElement.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_BUFFER_ELEMENT_H__
+#define _LOGD_LOG_BUFFER_ELEMENT_H__
+
+#include <sys/types.h>
+#include <sysutils/SocketClient.h>
+#include <log/log.h>
+#include <log/log_read.h>
+
+class LogBufferElement {
+ const log_id_t mLogId;
+ const uid_t mUid;
+ const pid_t mPid;
+ char *mMsg;
+ const unsigned short mMsgLen;
+ const log_time mMonotonicTime;
+ const log_time mRealTime;
+
+public:
+ LogBufferElement(log_id_t log_id, log_time realtime,
+ uid_t uid, pid_t pid, const char *msg, unsigned short len);
+ virtual ~LogBufferElement();
+
+ log_id_t getLogId() const { return mLogId; }
+ uid_t getUid(void) const { return mUid; }
+ pid_t getPid(void) const { return mPid; }
+ unsigned short getMsgLen() const { return mMsgLen; }
+ log_time getMonotonicTime(void) const { return mMonotonicTime; }
+ log_time getRealTime(void) const { return mRealTime; }
+
+ static const log_time FLUSH_ERROR;
+ log_time flushTo(SocketClient *writer);
+};
+
+#endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
new file mode 100644
index 0000000..0873e63
--- /dev/null
+++ b/logd/LogCommand.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "LogCommand.h"
+
+LogCommand::LogCommand(const char *cmd)
+ : FrameworkCommand(cmd) {
+}
+
+// gets a list of supplementary group IDs associated with
+// the socket peer. This is implemented by opening
+// /proc/PID/status and look for the "Group:" line.
+//
+// This function introduces races especially since status
+// can change 'shape' while reading, the net result is err
+// on lack of permission.
+//
+// Race-free alternative is to introduce pairs of sockets
+// and threads for each command and reading, one each that
+// has open permissions, and one that has restricted
+// permissions.
+
+static bool groupIsLog(char *buf) {
+ char *ptr;
+ static const char ws[] = " \n";
+ bool ret = false;
+
+ for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(NULL, ws, &ptr)) {
+ errno = 0;
+ gid_t Gid = strtol(buf, NULL, 10);
+ if (errno != 0) {
+ return false;
+ }
+ if (Gid == AID_LOG) {
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+bool clientHasLogCredentials(SocketClient * cli) {
+ uid_t uid = cli->getUid();
+ if (uid == AID_ROOT) {
+ return true;
+ }
+
+ gid_t gid = cli->getGid();
+ if ((gid == AID_ROOT) || (gid == AID_LOG)) {
+ return true;
+ }
+
+ // FYI We will typically be here for 'adb logcat'
+ bool ret = false;
+
+ char filename[1024];
+ snprintf(filename, sizeof(filename), "/proc/%d/status", cli->getPid());
+
+ FILE *file = fopen(filename, "r");
+ if (!file) {
+ return ret;
+ }
+
+ bool foundGid = false;
+ bool foundUid = false;
+
+ char line[1024];
+ while (fgets(line, sizeof(line), file)) {
+ static const char groups_string[] = "Groups:\t";
+ static const char uid_string[] = "Uid:\t";
+ static const char gid_string[] = "Gid:\t";
+
+ if (strncmp(groups_string, line, strlen(groups_string)) == 0) {
+ ret = groupIsLog(line + strlen(groups_string));
+ if (!ret) {
+ break;
+ }
+ } else if (strncmp(uid_string, line, strlen(uid_string)) == 0) {
+ uid_t u[4] = { (uid_t) -1, (uid_t) -1, (uid_t) -1, (uid_t) -1};
+
+ sscanf(line + strlen(uid_string), "%u\t%u\t%u\t%u",
+ &u[0], &u[1], &u[2], &u[3]);
+
+ // Protect against PID reuse by checking that the UID is the same
+ if ((uid != u[0]) || (uid != u[1]) || (uid != u[2]) || (uid != u[3])) {
+ ret = false;
+ break;
+ }
+ foundUid = true;
+ } else if (strncmp(gid_string, line, strlen(gid_string)) == 0) {
+ gid_t g[4] = { (gid_t) -1, (gid_t) -1, (gid_t) -1, (gid_t) -1};
+
+ sscanf(line + strlen(gid_string), "%u\t%u\t%u\t%u",
+ &g[0], &g[1], &g[2], &g[3]);
+
+ // Protect against PID reuse by checking that the GID is the same
+ if ((gid != g[0]) || (gid != g[1]) || (gid != g[2]) || (gid != g[3])) {
+ ret = false;
+ break;
+ }
+ foundGid = true;
+ }
+ }
+
+ fclose(file);
+
+ if (!foundGid || !foundUid) {
+ ret = false;
+ }
+
+ return ret;
+}
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
new file mode 100644
index 0000000..e3b96a2
--- /dev/null
+++ b/logd/LogCommand.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_COMMAND_H
+#define _LOGD_COMMAND_H
+
+#include <sysutils/SocketClient.h>
+#include <sysutils/FrameworkCommand.h>
+
+class LogCommand : public FrameworkCommand {
+public:
+ LogCommand(const char *cmd);
+ virtual ~LogCommand() {}
+};
+
+bool clientHasLogCredentials(SocketClient * cli);
+
+#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
new file mode 100644
index 0000000..c6b248b
--- /dev/null
+++ b/logd/LogListener.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <cutils/sockets.h>
+#include <log/logger.h>
+
+#include "LogListener.h"
+
+LogListener::LogListener(LogBuffer *buf, LogReader *reader)
+ : SocketListener(getLogSocket(), false)
+ , logbuf(buf)
+ , reader(reader)
+{ }
+
+bool LogListener::onDataAvailable(SocketClient *cli) {
+ char buffer[1024];
+ struct iovec iov = { buffer, sizeof(buffer) };
+ memset(buffer, 0, sizeof(buffer));
+
+ char control[CMSG_SPACE(sizeof(struct ucred))];
+ struct msghdr hdr = {
+ NULL,
+ 0,
+ &iov,
+ 1,
+ control,
+ sizeof(control),
+ 0,
+ };
+
+ int socket = cli->getSocket();
+
+ ssize_t n = recvmsg(socket, &hdr, 0);
+ if (n <= (ssize_t) sizeof_log_id_t) {
+ return false;
+ }
+
+ struct ucred *cred = NULL;
+
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(&hdr);
+ while (cmsg != NULL) {
+ if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == SCM_CREDENTIALS) {
+ cred = (struct ucred *)CMSG_DATA(cmsg);
+ break;
+ }
+ cmsg = CMSG_NXTHDR(&hdr, cmsg);
+ }
+
+ if (cred == NULL) {
+ return false;
+ }
+
+ if (cred->uid == getuid()) {
+ // ignore log messages we send to ourself.
+ // Such log messages are often generated by libraries we depend on
+ // which use standard Android logging.
+ return false;
+ }
+
+ // First log element is always log_id.
+ log_id_t log_id = (log_id_t) *((typeof_log_id_t *) buffer);
+ if (log_id < 0 || log_id >= LOG_ID_MAX) {
+ return false;
+ }
+
+ char *msg = ((char *)buffer) + sizeof_log_id_t;
+ n -= sizeof_log_id_t;
+
+ log_time realtime(msg);
+ msg += sizeof(log_time);
+ n -= sizeof(log_time);
+
+ unsigned short len = n;
+ if (len == n) {
+ logbuf->log(log_id, realtime, cred->uid, cred->pid, msg, len);
+ reader->notifyNewLog();
+ }
+
+ return true;
+}
+
+int LogListener::getLogSocket() {
+ int sock = android_get_control_socket("logdw");
+ int on = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
+ return -1;
+ }
+ return sock;
+}
diff --git a/logd/LogListener.h b/logd/LogListener.h
new file mode 100644
index 0000000..7099e13
--- /dev/null
+++ b/logd/LogListener.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_LISTENER_H__
+#define _LOGD_LOG_LISTENER_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogReader.h"
+
+class LogListener : public SocketListener {
+ LogBuffer *logbuf;
+ LogReader *reader;
+
+public:
+ LogListener(LogBuffer *buf, LogReader *reader);
+
+protected:
+ virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+ static int getLogSocket();
+};
+
+#endif
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
new file mode 100644
index 0000000..5b540bf
--- /dev/null
+++ b/logd/LogReader.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <poll.h>
+#include <sys/socket.h>
+#include <cutils/sockets.h>
+
+#include "LogReader.h"
+#include "FlushCommand.h"
+
+LogReader::LogReader(LogBuffer *logbuf)
+ : SocketListener("logdr", true)
+ , mLogbuf(*logbuf)
+{ }
+
+// When we are notified a new log entry is available, inform
+// all of our listening sockets.
+void LogReader::notifyNewLog() {
+ FlushCommand command(*this);
+ runOnEachSocket(&command);
+}
+
+bool LogReader::onDataAvailable(SocketClient *cli) {
+ char buffer[255];
+
+ int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
+ if (len <= 0) {
+ doSocketDelete(cli);
+ return false;
+ }
+ buffer[len] = '\0';
+
+ unsigned long tail = 0;
+ static const char _tail[] = " tail=";
+ char *cp = strstr(buffer, _tail);
+ if (cp) {
+ tail = atol(cp + sizeof(_tail) - 1);
+ }
+
+ unsigned int logMask = -1;
+ static const char _logIds[] = " lids=";
+ cp = strstr(buffer, _logIds);
+ if (cp) {
+ logMask = 0;
+ cp += sizeof(_logIds) - 1;
+ while (*cp && *cp != '\0') {
+ int val = 0;
+ while (('0' <= *cp) && (*cp <= '9')) {
+ val *= 10;
+ val += *cp - '0';
+ ++cp;
+ }
+ logMask |= 1 << val;
+ if (*cp != ',') {
+ break;
+ }
+ ++cp;
+ }
+ }
+
+ pid_t pid = 0;
+ static const char _pid[] = " pid=";
+ cp = strstr(buffer, _pid);
+ if (cp) {
+ pid = atol(cp + sizeof(_pid) - 1);
+ }
+
+ bool nonBlock = false;
+ if (strncmp(buffer, "dumpAndClose", 12) == 0) {
+ nonBlock = true;
+ }
+
+ FlushCommand command(*this, nonBlock, tail, logMask, pid);
+ command.runSocketCommand(cli);
+ return true;
+}
+
+void LogReader::doSocketDelete(SocketClient *cli) {
+ LastLogTimes × = mLogbuf.mTimes;
+ LogTimeEntry::lock();
+ LastLogTimes::iterator it = times.begin();
+ while(it != times.end()) {
+ LogTimeEntry *entry = (*it);
+ if (entry->mClient == cli) {
+ times.erase(it);
+ entry->release_Locked();
+ break;
+ }
+ it++;
+ }
+ LogTimeEntry::unlock();
+}
diff --git a/logd/LogReader.h b/logd/LogReader.h
new file mode 100644
index 0000000..b267c75
--- /dev/null
+++ b/logd/LogReader.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_WRITER_H__
+#define _LOGD_LOG_WRITER_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogBuffer.h"
+#include "LogTimes.h"
+
+class LogReader : public SocketListener {
+ LogBuffer &mLogbuf;
+
+public:
+ LogReader(LogBuffer *logbuf);
+ void notifyNewLog();
+
+ LogBuffer &logbuf(void) const { return mLogbuf; }
+
+protected:
+ virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+ void doSocketDelete(SocketClient *cli);
+
+};
+
+#endif
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
new file mode 100644
index 0000000..49ee50d
--- /dev/null
+++ b/logd/LogStatistics.cpp
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdarg.h>
+#include <time.h>
+
+#include <log/logger.h>
+#include <private/android_filesystem_config.h>
+#include <utils/String8.h>
+
+#include "LogStatistics.h"
+
+PidStatistics::PidStatistics(pid_t pid)
+ : pid(pid)
+ , mSizesTotal(0)
+ , mElementsTotal(0)
+ , mSizes(0)
+ , mElements(0) { }
+
+void PidStatistics::add(unsigned short size) {
+ mSizesTotal += size;
+ ++mElementsTotal;
+ mSizes += size;
+ ++mElements;
+}
+
+bool PidStatistics::subtract(unsigned short size) {
+ mSizes -= size;
+ --mElements;
+ return mElements == 0 && kill(pid, 0);
+}
+
+void PidStatistics::addTotal(size_t size, size_t element) {
+ if (pid == gone) {
+ mSizesTotal += size;
+ mElementsTotal += element;
+ }
+}
+
+UidStatistics::UidStatistics(uid_t uid)
+ : uid(uid) {
+ Pids.clear();
+}
+
+UidStatistics::~UidStatistics() {
+ PidStatisticsCollection::iterator it;
+ for (it = begin(); it != end();) {
+ delete (*it);
+ it = Pids.erase(it);
+ }
+}
+
+void UidStatistics::add(unsigned short size, pid_t pid) {
+ PidStatistics *p;
+ PidStatisticsCollection::iterator last;
+ PidStatisticsCollection::iterator it;
+ for (last = it = begin(); it != end(); last = it, ++it) {
+ p = *it;
+ if (pid == p->getPid()) {
+ p->add(size);
+ // poor-man sort, bubble upwards if bigger than last
+ if ((last != it) && ((*last)->sizesTotal() < p->sizesTotal())) {
+ Pids.erase(it);
+ Pids.insert(last, p);
+ }
+ return;
+ }
+ }
+ // poor-man sort, insert if bigger than last or last is the gone entry.
+ bool insert = (last != it)
+ && ((p->getPid() == p->gone)
+ || ((*last)->sizesTotal() < (size_t) size));
+ p = new PidStatistics(pid);
+ if (insert) {
+ Pids.insert(last, p);
+ } else {
+ Pids.push_back(p);
+ }
+ p->add(size);
+}
+
+void UidStatistics::subtract(unsigned short size, pid_t pid) {
+ PidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ PidStatistics *p = *it;
+ if (pid == p->getPid()) {
+ if (p->subtract(size)) {
+ size_t szsTotal = p->sizesTotal();
+ size_t elsTotal = p->elementsTotal();
+ delete p;
+ Pids.erase(it);
+ it = end();
+ --it;
+ if (it == end()) {
+ p = new PidStatistics(p->gone);
+ Pids.push_back(p);
+ } else {
+ p = *it;
+ if (p->getPid() != p->gone) {
+ p = new PidStatistics(p->gone);
+ Pids.push_back(p);
+ }
+ }
+ p->addTotal(szsTotal, elsTotal);
+ }
+ return;
+ }
+ }
+}
+
+size_t UidStatistics::sizes(pid_t pid) {
+ size_t sizes = 0;
+ PidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ PidStatistics *p = *it;
+ if ((pid == pid_all) || (pid == p->getPid())) {
+ sizes += p->sizes();
+ }
+ }
+ return sizes;
+}
+
+size_t UidStatistics::elements(pid_t pid) {
+ size_t elements = 0;
+ PidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ PidStatistics *p = *it;
+ if ((pid == pid_all) || (pid == p->getPid())) {
+ elements += p->elements();
+ }
+ }
+ return elements;
+}
+
+size_t UidStatistics::sizesTotal(pid_t pid) {
+ size_t sizes = 0;
+ PidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ PidStatistics *p = *it;
+ if ((pid == pid_all) || (pid == p->getPid())) {
+ sizes += p->sizesTotal();
+ }
+ }
+ return sizes;
+}
+
+size_t UidStatistics::elementsTotal(pid_t pid) {
+ size_t elements = 0;
+ PidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ PidStatistics *p = *it;
+ if ((pid == pid_all) || (pid == p->getPid())) {
+ elements += p->elementsTotal();
+ }
+ }
+ return elements;
+}
+
+LidStatistics::LidStatistics() {
+ Uids.clear();
+}
+
+LidStatistics::~LidStatistics() {
+ UidStatisticsCollection::iterator it;
+ for (it = begin(); it != end();) {
+ delete (*it);
+ it = Uids.erase(it);
+ }
+}
+
+void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
+ UidStatistics *u;
+ UidStatisticsCollection::iterator it;
+ UidStatisticsCollection::iterator last;
+
+ if (uid == (uid_t) -1) { // init
+ uid = (uid_t) AID_ROOT;
+ }
+
+ for (last = it = begin(); it != end(); last = it, ++it) {
+ u = *it;
+ if (uid == u->getUid()) {
+ u->add(size, pid);
+ if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
+ Uids.erase(it);
+ Uids.insert(last, u);
+ }
+ return;
+ }
+ }
+ u = new UidStatistics(uid);
+ if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
+ Uids.insert(last, u);
+ } else {
+ Uids.push_back(u);
+ }
+ u->add(size, pid);
+}
+
+void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
+ UidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ UidStatistics *u = *it;
+ if (uid == u->getUid()) {
+ u->subtract(size, pid);
+ return;
+ }
+ }
+}
+
+size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
+ size_t sizes = 0;
+ UidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ UidStatistics *u = *it;
+ if ((uid == uid_all) || (uid == u->getUid())) {
+ sizes += u->sizes(pid);
+ }
+ }
+ return sizes;
+}
+
+size_t LidStatistics::elements(uid_t uid, pid_t pid) {
+ size_t elements = 0;
+ UidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ UidStatistics *u = *it;
+ if ((uid == uid_all) || (uid == u->getUid())) {
+ elements += u->elements(pid);
+ }
+ }
+ return elements;
+}
+
+size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
+ size_t sizes = 0;
+ UidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ UidStatistics *u = *it;
+ if ((uid == uid_all) || (uid == u->getUid())) {
+ sizes += u->sizesTotal(pid);
+ }
+ }
+ return sizes;
+}
+
+size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
+ size_t elements = 0;
+ UidStatisticsCollection::iterator it;
+ for (it = begin(); it != end(); ++it) {
+ UidStatistics *u = *it;
+ if ((uid == uid_all) || (uid == u->getUid())) {
+ elements += u->elementsTotal(pid);
+ }
+ }
+ return elements;
+}
+
+LogStatistics::LogStatistics()
+ : start(CLOCK_MONOTONIC) {
+ log_id_for_each(i) {
+ mSizes[i] = 0;
+ mElements[i] = 0;
+ }
+}
+
+void LogStatistics::add(unsigned short size,
+ log_id_t log_id, uid_t uid, pid_t pid) {
+ mSizes[log_id] += size;
+ ++mElements[log_id];
+ id(log_id).add(size, uid, pid);
+}
+
+void LogStatistics::subtract(unsigned short size,
+ log_id_t log_id, uid_t uid, pid_t pid) {
+ mSizes[log_id] -= size;
+ --mElements[log_id];
+ id(log_id).subtract(size, uid, pid);
+}
+
+size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
+ if (log_id != log_id_all) {
+ return id(log_id).sizes(uid, pid);
+ }
+ size_t sizes = 0;
+ log_id_for_each(i) {
+ sizes += id(i).sizes(uid, pid);
+ }
+ return sizes;
+}
+
+size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
+ if (log_id != log_id_all) {
+ return id(log_id).elements(uid, pid);
+ }
+ size_t elements = 0;
+ log_id_for_each(i) {
+ elements += id(i).elements(uid, pid);
+ }
+ return elements;
+}
+
+size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
+ if (log_id != log_id_all) {
+ return id(log_id).sizesTotal(uid, pid);
+ }
+ size_t sizes = 0;
+ log_id_for_each(i) {
+ sizes += id(i).sizesTotal(uid, pid);
+ }
+ return sizes;
+}
+
+size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
+ if (log_id != log_id_all) {
+ return id(log_id).elementsTotal(uid, pid);
+ }
+ size_t elements = 0;
+ log_id_for_each(i) {
+ elements += id(i).elementsTotal(uid, pid);
+ }
+ return elements;
+}
+
+void LogStatistics::format(char **buf,
+ uid_t uid, unsigned int logMask, log_time oldest) {
+ const unsigned short spaces_current = 13;
+ const unsigned short spaces_total = 19;
+
+ if (*buf) {
+ free(buf);
+ *buf = NULL;
+ }
+
+ android::String8 string(" span -> size/num");
+ size_t oldLength;
+ short spaces = 2;
+
+ log_id_for_each(i) {
+ if (logMask & (1 << i)) {
+ oldLength = string.length();
+ string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
+ spaces += spaces_total + oldLength - string.length();
+ }
+ }
+
+ spaces = 1;
+ log_time t(CLOCK_MONOTONIC);
+ unsigned long long d = t.nsec() - start.nsec();
+ string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
+ d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
+ (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+
+ log_id_for_each(i) {
+ if (!(logMask & (1 << i))) {
+ continue;
+ }
+ oldLength = string.length();
+ string.appendFormat("%*s%zu/%zu", spaces, "",
+ sizesTotal(i), elementsTotal(i));
+ spaces += spaces_total + oldLength - string.length();
+ }
+
+ spaces = 1;
+ d = t.nsec() - oldest.nsec();
+ string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
+ d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
+ (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+
+ log_id_for_each(i) {
+ if (!(logMask & (1 << i))) {
+ continue;
+ }
+
+ size_t els = elements(i);
+ if (els) {
+ oldLength = string.length();
+ string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
+ spaces -= string.length() - oldLength;
+ }
+ spaces += spaces_total;
+ }
+
+ log_id_for_each(i) {
+ if (!(logMask & (1 << i))) {
+ continue;
+ }
+
+ bool header = false;
+ bool first = true;
+
+ UidStatisticsCollection::iterator ut;
+ for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
+ UidStatistics *up = *ut;
+ if ((uid != AID_ROOT) && (uid != up->getUid())) {
+ continue;
+ }
+
+ PidStatisticsCollection::iterator pt = up->begin();
+ if (pt == up->end()) {
+ continue;
+ }
+
+ android::String8 intermediate;
+
+ if (!header) {
+ // header below tuned to match spaces_total and spaces_current
+ spaces = 0;
+ intermediate = string.format("%s: UID/PID Total size/num",
+ android_log_id_to_name(i));
+ string.appendFormat("\n\n%-31sNow "
+ "UID/PID[?] Total Now",
+ intermediate.string());
+ intermediate.clear();
+ header = true;
+ }
+
+ bool oneline = ++pt == up->end();
+ --pt;
+
+ if (!oneline) {
+ first = true;
+ } else if (!first && spaces) {
+ string.appendFormat("%*s", spaces, "");
+ }
+ spaces = 0;
+
+ uid_t u = up->getUid();
+ pid_t p = (*pt)->getPid();
+
+ intermediate = string.format(oneline
+ ? ((p == PidStatistics::gone)
+ ? "%d/?"
+ : "%d/%d")
+ : "%d",
+ u, p);
+ string.appendFormat((first) ? "\n%-12s" : "%-12s",
+ intermediate.string());
+ intermediate.clear();
+
+ size_t elsTotal = up->elementsTotal();
+ oldLength = string.length();
+ string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
+ spaces += spaces_total + oldLength - string.length();
+
+ size_t els = up->elements();
+ if (els == elsTotal) {
+ string.appendFormat("%*s=", spaces, "");
+ spaces = -1;
+ } else if (els) {
+ oldLength = string.length();
+ string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
+ spaces -= string.length() - oldLength;
+ }
+ spaces += spaces_current;
+
+ first = !first;
+
+ if (oneline) {
+ continue;
+ }
+
+ size_t gone_szs = 0;
+ size_t gone_els = 0;
+
+ for(; pt != up->end(); ++pt) {
+ PidStatistics *pp = *pt;
+ pid_t p = pp->getPid();
+
+ // If a PID no longer has any current logs, and is not
+ // active anymore, skip & report totals for gone.
+ elsTotal = pp->elementsTotal();
+ size_t szsTotal = pp->sizesTotal();
+ if (p == pp->gone) {
+ gone_szs += szsTotal;
+ gone_els += elsTotal;
+ continue;
+ }
+ els = pp->elements();
+ bool gone = kill(p, 0);
+ if (gone && (els == 0)) {
+ // ToDo: garbage collection: move this statistical bucket
+ // from its current UID/PID to UID/? (races and
+ // wrap around are our achilles heel). Below is
+ // merely lipservice to catch PIDs that were still
+ // around when the stats were pruned to zero.
+ gone_szs += szsTotal;
+ gone_els += elsTotal;
+ continue;
+ }
+
+ if (!first && spaces) {
+ string.appendFormat("%*s", spaces, "");
+ }
+ spaces = 0;
+
+ intermediate = string.format((gone) ? "%d/%d?" : "%d/%d", u, p);
+ string.appendFormat((first) ? "\n%-12s" : "%-12s",
+ intermediate.string());
+ intermediate.clear();
+
+ oldLength = string.length();
+ string.appendFormat("%zu/%zu", szsTotal, elsTotal);
+ spaces += spaces_total + oldLength - string.length();
+
+ if (els == elsTotal) {
+ string.appendFormat("%*s=", spaces, "");
+ spaces = -1;
+ } else if (els) {
+ oldLength = string.length();
+ string.appendFormat("%*s%zu/%zu", spaces, "",
+ pp->sizes(), els);
+ spaces -= string.length() - oldLength;
+ }
+ spaces += spaces_current;
+
+ first = !first;
+ }
+
+ if (gone_els) {
+ if (!first && spaces) {
+ string.appendFormat("%*s", spaces, "");
+ }
+
+ intermediate = string.format("%d/?", u);
+ string.appendFormat((first) ? "\n%-12s" : "%-12s",
+ intermediate.string());
+ intermediate.clear();
+
+ spaces = spaces_total + spaces_current;
+
+ oldLength = string.length();
+ string.appendFormat("%zu/%zu", gone_szs, gone_els);
+ spaces -= string.length() - oldLength;
+
+ first = !first;
+ }
+ }
+ }
+
+ *buf = strdup(string.string());
+}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
new file mode 100644
index 0000000..d44afa2
--- /dev/null
+++ b/logd/LogStatistics.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_STATISTICS_H__
+#define _LOGD_LOG_STATISTICS_H__
+
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <log/log_read.h>
+#include <utils/List.h>
+
+#define log_id_for_each(i) \
+ for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
+
+class PidStatistics {
+ const pid_t pid;
+
+ // Total
+ size_t mSizesTotal;
+ size_t mElementsTotal;
+ // Current
+ size_t mSizes;
+ size_t mElements;
+
+public:
+ static const pid_t gone = (pid_t) -1;
+
+ PidStatistics(pid_t pid);
+
+ pid_t getPid() const { return pid; }
+
+ void add(unsigned short size);
+ bool subtract(unsigned short size); // returns true if stats and PID gone
+ void addTotal(size_t size, size_t element);
+
+ size_t sizes() const { return mSizes; }
+ size_t elements() const { return mElements; }
+
+ size_t sizesTotal() const { return mSizesTotal; }
+ size_t elementsTotal() const { return mElementsTotal; }
+};
+
+typedef android::List<PidStatistics *> PidStatisticsCollection;
+
+class UidStatistics {
+ const uid_t uid;
+
+ PidStatisticsCollection Pids;
+
+public:
+ UidStatistics(uid_t uid);
+ ~UidStatistics();
+
+ PidStatisticsCollection::iterator begin() { return Pids.begin(); }
+ PidStatisticsCollection::iterator end() { return Pids.end(); }
+
+ uid_t getUid() { return uid; }
+
+ void add(unsigned short size, pid_t pid);
+ void subtract(unsigned short size, pid_t pid);
+
+ static const pid_t pid_all = (pid_t) -1;
+
+ size_t sizes(pid_t pid = pid_all);
+ size_t elements(pid_t pid = pid_all);
+
+ size_t sizesTotal(pid_t pid = pid_all);
+ size_t elementsTotal(pid_t pid = pid_all);
+};
+
+typedef android::List<UidStatistics *> UidStatisticsCollection;
+
+class LidStatistics {
+ UidStatisticsCollection Uids;
+
+public:
+ LidStatistics();
+ ~LidStatistics();
+
+ UidStatisticsCollection::iterator begin() { return Uids.begin(); }
+ UidStatisticsCollection::iterator end() { return Uids.end(); }
+
+ void add(unsigned short size, uid_t uid, pid_t pid);
+ void subtract(unsigned short size, uid_t uid, pid_t pid);
+
+ static const pid_t pid_all = (pid_t) -1;
+ static const uid_t uid_all = (uid_t) -1;
+
+ size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all);
+ size_t elements(uid_t uid = uid_all, pid_t pid = pid_all);
+
+ size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+ size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+};
+
+// Log Statistics
+class LogStatistics {
+ LidStatistics LogIds[LOG_ID_MAX];
+
+ size_t mSizes[LOG_ID_MAX];
+ size_t mElements[LOG_ID_MAX];
+
+public:
+ const log_time start;
+
+ LogStatistics();
+
+ LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
+
+ void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
+ void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
+
+ // fast track current value by id only
+ size_t sizes(log_id_t id) const { return mSizes[id]; }
+ size_t elements(log_id_t id) const { return mElements[id]; }
+
+ // statistical track
+ static const log_id_t log_id_all = (log_id_t) -1;
+ static const uid_t uid_all = (uid_t) -1;
+ static const pid_t pid_all = (pid_t) -1;
+
+ size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all);
+ size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all);
+ size_t sizes() { return sizes(log_id_all, uid_all); }
+ size_t elements() { return elements(log_id_all, uid_all); }
+
+ size_t sizesTotal(log_id_t id = log_id_all,
+ uid_t uid = uid_all,
+ pid_t pid = pid_all);
+ size_t elementsTotal(log_id_t id = log_id_all,
+ uid_t uid = uid_all,
+ pid_t pid = pid_all);
+
+ // *strp = malloc, balance with free
+ void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
+};
+
+#endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
new file mode 100644
index 0000000..67cc65e
--- /dev/null
+++ b/logd/LogTimes.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FlushCommand.h"
+#include "LogBuffer.h"
+#include "LogTimes.h"
+#include "LogReader.h"
+
+pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER;
+
+const struct timespec LogTimeEntry::EPOCH = { 0, 1 };
+
+LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
+ bool nonBlock, unsigned long tail,
+ unsigned int logMask, pid_t pid)
+ : mRefCount(1)
+ , mRelease(false)
+ , mError(false)
+ , threadRunning(false)
+ , threadTriggered(true)
+ , mReader(reader)
+ , mLogMask(logMask)
+ , mPid(pid)
+ , skipAhead(0)
+ , mCount(0)
+ , mTail(tail)
+ , mIndex(0)
+ , mClient(client)
+ , mStart(EPOCH)
+ , mNonBlock(nonBlock)
+ , mEnd(CLOCK_MONOTONIC)
+{ }
+
+void LogTimeEntry::startReader_Locked(void) {
+ threadRunning = true;
+ if (pthread_create(&mThread, NULL, LogTimeEntry::threadStart, this)) {
+ threadRunning = false;
+ if (mClient) {
+ mClient->decRef();
+ }
+ decRef_Locked();
+ }
+}
+
+void LogTimeEntry::threadStop(void *obj) {
+ LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+ lock();
+
+ me->threadRunning = false;
+ if (me->mNonBlock) {
+ me->error_Locked();
+ }
+
+ SocketClient *client = me->mClient;
+
+ if (me->isError_Locked()) {
+ LogReader &reader = me->mReader;
+ LastLogTimes × = reader.logbuf().mTimes;
+
+ LastLogTimes::iterator it = times.begin();
+ while(it != times.end()) {
+ if (*it == me) {
+ times.erase(it);
+ me->release_Locked();
+ break;
+ }
+ it++;
+ }
+
+ me->mClient = NULL;
+ reader.release(client);
+ }
+
+ if (client) {
+ client->decRef();
+ }
+
+ me->decRef_Locked();
+
+ unlock();
+}
+
+void *LogTimeEntry::threadStart(void *obj) {
+ LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+ pthread_cleanup_push(threadStop, obj);
+
+ SocketClient *client = me->mClient;
+ if (!client) {
+ me->error();
+ pthread_exit(NULL);
+ }
+
+ LogBuffer &logbuf = me->mReader.logbuf();
+
+ bool privileged = FlushCommand::hasReadLogs(client);
+
+ lock();
+
+ me->threadTriggered = true;
+
+ while(me->threadTriggered && !me->isError_Locked()) {
+
+ me->threadTriggered = false;
+
+ log_time start = me->mStart;
+
+ unlock();
+
+ if (me->mTail) {
+ logbuf.flushTo(client, start, privileged, FilterFirstPass, me);
+ }
+ start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
+
+ if (start == LogBufferElement::FLUSH_ERROR) {
+ me->error();
+ }
+
+ if (me->mNonBlock) {
+ lock();
+ break;
+ }
+
+ sched_yield();
+
+ lock();
+ }
+
+ unlock();
+
+ pthread_exit(NULL);
+
+ pthread_cleanup_pop(true);
+
+ return NULL;
+}
+
+// A first pass to count the number of elements
+bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) {
+ LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+ LogTimeEntry::lock();
+
+ if (me->mCount == 0) {
+ me->mStart = element->getMonotonicTime();
+ }
+
+ if ((!me->mPid || (me->mPid == element->getPid()))
+ && (me->mLogMask & (1 << element->getLogId()))) {
+ ++me->mCount;
+ }
+
+ LogTimeEntry::unlock();
+
+ return false;
+}
+
+// A second pass to send the selected elements
+bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) {
+ LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
+
+ LogTimeEntry::lock();
+
+ if (me->skipAhead) {
+ me->skipAhead--;
+ }
+
+ me->mStart = element->getMonotonicTime();
+
+ // Truncate to close race between first and second pass
+ if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) {
+ goto skip;
+ }
+
+ if ((me->mLogMask & (1 << element->getLogId())) == 0) {
+ goto skip;
+ }
+
+ if (me->mPid && (me->mPid != element->getPid())) {
+ goto skip;
+ }
+
+ if (me->isError_Locked()) {
+ goto skip;
+ }
+
+ if (!me->mTail) {
+ goto ok;
+ }
+
+ ++me->mIndex;
+
+ if ((me->mCount > me->mTail) && (me->mIndex <= (me->mCount - me->mTail))) {
+ goto skip;
+ }
+
+ if (!me->mNonBlock) {
+ me->mTail = 0;
+ }
+
+ok:
+ if (!me->skipAhead) {
+ LogTimeEntry::unlock();
+ return true;
+ }
+ // FALLTHRU
+
+skip:
+ LogTimeEntry::unlock();
+ return false;
+}
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
new file mode 100644
index 0000000..cb6f566
--- /dev/null
+++ b/logd/LogTimes.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_TIMES_H__
+#define _LOGD_LOG_TIMES_H__
+
+#include <pthread.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sysutils/SocketClient.h>
+#include <utils/List.h>
+
+class LogReader;
+
+class LogTimeEntry {
+ static pthread_mutex_t timesLock;
+ unsigned int mRefCount;
+ bool mRelease;
+ bool mError;
+ bool threadRunning;
+ bool threadTriggered;
+ pthread_t mThread;
+ LogReader &mReader;
+ static void *threadStart(void *me);
+ static void threadStop(void *me);
+ const unsigned int mLogMask;
+ const pid_t mPid;
+ unsigned int skipAhead;
+ unsigned long mCount;
+ unsigned long mTail;
+ unsigned long mIndex;
+
+public:
+ LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock,
+ unsigned long tail, unsigned int logMask, pid_t pid);
+
+ SocketClient *mClient;
+ static const struct timespec EPOCH;
+ log_time mStart;
+ const bool mNonBlock;
+ const log_time mEnd; // only relevant if mNonBlock
+
+ // Protect List manipulations
+ static void lock(void) { pthread_mutex_lock(×Lock); }
+ static void unlock(void) { pthread_mutex_unlock(×Lock); }
+
+ void startReader_Locked(void);
+
+ bool runningReader_Locked(void) const {
+ return threadRunning || mRelease || mError || mNonBlock;
+ }
+ void triggerReader_Locked(void) { threadTriggered = true; }
+ void triggerSkip_Locked(unsigned int skip) { skipAhead = skip; }
+
+ // Called after LogTimeEntry removed from list, lock implicitly held
+ void release_Locked(void) {
+ mRelease = true;
+ if (mRefCount || threadRunning) {
+ return;
+ }
+ // No one else is holding a reference to this
+ delete this;
+ }
+
+ // Called to mark socket in jeopardy
+ void error_Locked(void) { mError = true; }
+ void error(void) { lock(); mError = true; unlock(); }
+
+ bool isError_Locked(void) const { return mRelease || mError; }
+
+ // Mark Used
+ // Locking implied, grabbed when protection around loop iteration
+ void incRef_Locked(void) { ++mRefCount; }
+
+ bool owned_Locked(void) const { return mRefCount != 0; }
+
+ void decRef_Locked(void) {
+ if ((mRefCount && --mRefCount) || !mRelease || threadRunning) {
+ return;
+ }
+ // No one else is holding a reference to this
+ delete this;
+ }
+
+ // flushTo filter callbacks
+ static bool FilterFirstPass(const LogBufferElement *element, void *me);
+ static bool FilterSecondPass(const LogBufferElement *element, void *me);
+};
+
+typedef android::List<LogTimeEntry *> LastLogTimes;
+
+#endif
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
new file mode 100644
index 0000000..d0ceb9f
--- /dev/null
+++ b/logd/LogWhiteBlackList.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef USERDEBUG_BUILD
+
+#include <ctype.h>
+
+#include <utils/String8.h>
+
+#include "LogWhiteBlackList.h"
+
+// White and Black list
+
+Prune::Prune(uid_t uid, pid_t pid)
+ : mUid(uid)
+ , mPid(pid)
+{ }
+
+int Prune::cmp(uid_t uid, pid_t pid) const {
+ if ((mUid == uid_all) || (mUid == uid)) {
+ if (mPid == pid_all) {
+ return 0;
+ }
+ return pid - mPid;
+ }
+ return uid - mUid;
+}
+
+void Prune::format(char **strp) {
+ if (mUid != uid_all) {
+ asprintf(strp, (mPid != pid_all) ? "%u/%u" : "%u", mUid, mPid);
+ } else {
+ // NB: mPid == pid_all can not happen if mUid == uid_all
+ asprintf(strp, (mPid != pid_all) ? "/%u" : "/", mPid);
+ }
+}
+
+PruneList::PruneList()
+ : mWorstUidEnabled(true) {
+ mNaughty.clear();
+ mNice.clear();
+}
+
+PruneList::~PruneList() {
+ PruneCollection::iterator it;
+ for (it = mNice.begin(); it != mNice.end();) {
+ delete (*it);
+ it = mNice.erase(it);
+ }
+ for (it = mNaughty.begin(); it != mNaughty.end();) {
+ delete (*it);
+ it = mNaughty.erase(it);
+ }
+}
+
+int PruneList::init(char *str) {
+ mWorstUidEnabled = true;
+ PruneCollection::iterator it;
+ for (it = mNice.begin(); it != mNice.end();) {
+ delete (*it);
+ it = mNice.erase(it);
+ }
+ for (it = mNaughty.begin(); it != mNaughty.end();) {
+ delete (*it);
+ it = mNaughty.erase(it);
+ }
+
+ if (!str) {
+ return 0;
+ }
+
+ mWorstUidEnabled = false;
+
+ for(; *str; ++str) {
+ if (isspace(*str)) {
+ continue;
+ }
+
+ PruneCollection *list;
+ if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
+ ++str;
+ // special case, translates to worst UID at priority in blacklist
+ if (*str == '!') {
+ mWorstUidEnabled = true;
+ ++str;
+ if (!*str) {
+ break;
+ }
+ if (!isspace(*str)) {
+ return 1;
+ }
+ continue;
+ }
+ if (!*str) {
+ return 1;
+ }
+ list = &mNaughty;
+ } else {
+ list = &mNice;
+ }
+
+ uid_t uid = Prune::uid_all;
+ if (isdigit(*str)) {
+ uid = 0;
+ do {
+ uid = uid * 10 + *str++ - '0';
+ } while (isdigit(*str));
+ }
+
+ pid_t pid = Prune::pid_all;
+ if (*str == '/') {
+ ++str;
+ if (isdigit(*str)) {
+ pid = 0;
+ do {
+ pid = pid * 10 + *str++ - '0';
+ } while (isdigit(*str));
+ }
+ }
+
+ if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) {
+ return 1;
+ }
+
+ if (*str && !isspace(*str)) {
+ return 1;
+ }
+
+ // insert sequentially into list
+ PruneCollection::iterator it = list->begin();
+ while (it != list->end()) {
+ Prune *p = *it;
+ int m = uid - p->mUid;
+ if (m == 0) {
+ if (p->mPid == p->pid_all) {
+ break;
+ }
+ if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
+ it = list->erase(it);
+ continue;
+ }
+ m = pid - p->mPid;
+ }
+ if (m >= 0) {
+ if (m > 0) {
+ list->insert(it, new Prune(uid,pid));
+ }
+ break;
+ }
+ ++it;
+ }
+ if (it == list->end()) {
+ list->push_back(new Prune(uid,pid));
+ }
+ if (!*str) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void PruneList::format(char **strp) {
+ if (*strp) {
+ free(*strp);
+ *strp = NULL;
+ }
+
+ static const char nice_format[] = " %s";
+ const char *fmt = nice_format + 1;
+
+ android::String8 string;
+
+ if (mWorstUidEnabled) {
+ string.setTo("~!");
+ fmt = nice_format;
+ }
+
+ PruneCollection::iterator it;
+
+ for (it = mNice.begin(); it != mNice.end(); ++it) {
+ char *a = NULL;
+ (*it)->format(&a);
+
+ string.appendFormat(fmt, a);
+ fmt = nice_format;
+
+ free(a);
+ }
+
+ static const char naughty_format[] = " ~%s";
+ fmt = naughty_format + (*fmt != ' ');
+ for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
+ char *a = NULL;
+ (*it)->format(&a);
+
+ string.appendFormat(fmt, a);
+ fmt = naughty_format;
+
+ free(a);
+ }
+
+ *strp = strdup(string.string());
+}
+
+// ToDo: Lists are in sorted order, Prune->cmp() returns + or -
+// If there is scaling issues, resort to a better algorithm than linear
+// based on these assumptions.
+
+bool PruneList::naughty(LogBufferElement *element) {
+ PruneCollection::iterator it;
+ for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
+ if (!(*it)->cmp(element)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PruneList::nice(LogBufferElement *element) {
+ PruneCollection::iterator it;
+ for (it = mNice.begin(); it != mNice.end(); ++it) {
+ if (!(*it)->cmp(element)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif // USERDEBUG_BUILD
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
new file mode 100644
index 0000000..769d651
--- /dev/null
+++ b/logd/LogWhiteBlackList.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LOGD_LOG_WHITE_BLACK_LIST_H__
+#define _LOGD_LOG_WHITE_BLACK_LIST_H__
+
+#include <sys/types.h>
+
+#include <utils/List.h>
+
+#include <LogBufferElement.h>
+
+// White and Blacklist
+
+class Prune {
+ friend class PruneList;
+
+ const uid_t mUid;
+ const pid_t mPid;
+ int cmp(uid_t uid, pid_t pid) const;
+
+public:
+ static const uid_t uid_all = (uid_t) -1;
+ static const pid_t pid_all = (pid_t) -1;
+
+ Prune(uid_t uid, pid_t pid);
+
+ uid_t getUid() const { return mUid; }
+ pid_t getPid() const { return mPid; }
+
+ int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
+
+ // *strp is malloc'd, use free to release
+ void format(char **strp);
+};
+
+typedef android::List<Prune *> PruneCollection;
+
+class PruneList {
+ PruneCollection mNaughty;
+ PruneCollection mNice;
+ bool mWorstUidEnabled;
+
+public:
+ PruneList();
+ ~PruneList();
+
+ int init(char *str);
+
+ bool naughty(LogBufferElement *element);
+ bool nice(LogBufferElement *element);
+ bool worstUidEnabled() const { return mWorstUidEnabled; }
+
+ // *strp is malloc'd, use free to release
+ void format(char **strp);
+};
+
+#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
diff --git a/logd/main.cpp b/logd/main.cpp
new file mode 100644
index 0000000..6216b95
--- /dev/null
+++ b/logd/main.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012-2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/prctl.h>
+
+#include "private/android_filesystem_config.h"
+#include "CommandListener.h"
+#include "LogBuffer.h"
+#include "LogListener.h"
+
+static int drop_privs() {
+ struct sched_param param;
+ memset(¶m, 0, sizeof(param));
+
+ if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
+ return -1;
+ }
+
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
+ return -1;
+ }
+
+ if (setgid(AID_LOGD) != 0) {
+ return -1;
+ }
+
+ if (setuid(AID_LOGD) != 0) {
+ return -1;
+ }
+
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
+ capdata[0].inheritable = 0;
+ capdata[1].inheritable = 0;
+
+ if (capset(&capheader, &capdata[0]) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+// Foreground waits for exit of the three main persistent threads that
+// are started here. The three threads are created to manage UNIX
+// domain client sockets for writing, reading and controlling the user
+// space logger. Additional transitory per-client threads are created
+// for each reader once they register.
+int main() {
+ if (drop_privs() != 0) {
+ return -1;
+ }
+
+ // Serves the purpose of managing the last logs times read on a
+ // socket connection, and as a reader lock on a range of log
+ // entries.
+
+ LastLogTimes *times = new LastLogTimes();
+
+ // LogBuffer is the object which is responsible for holding all
+ // log entries.
+
+ LogBuffer *logBuf = new LogBuffer(times);
+
+ // LogReader listens on /dev/socket/logdr. When a client
+ // connects, log entries in the LogBuffer are written to the client.
+
+ LogReader *reader = new LogReader(logBuf);
+ if (reader->startListener()) {
+ exit(1);
+ }
+
+ // LogListener listens on /dev/socket/logdw for client
+ // initiated log messages. New log entries are added to LogBuffer
+ // and LogReader is notified to send updates to connected clients.
+
+ LogListener *swl = new LogListener(logBuf, reader);
+ // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
+ if (swl->startListener(300)) {
+ exit(1);
+ }
+
+ // Command listener listens on /dev/socket/logd for incoming logd
+ // administrative commands.
+
+ CommandListener *cl = new CommandListener(logBuf, reader, swl);
+ if (cl->startListener()) {
+ exit(1);
+ }
+
+ pause();
+ exit(0);
+}
+
diff --git a/reboot/reboot.c b/reboot/reboot.c
index d9a4227..007dfba 100644
--- a/reboot/reboot.c
+++ b/reboot/reboot.c
@@ -35,7 +35,7 @@
c = getopt(argc, argv, "p");
- if (c == EOF) {
+ if (c == -1) {
break;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8a1cb26..1619100 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -104,6 +104,7 @@
write /proc/sys/kernel/dmesg_restrict 1
write /proc/sys/vm/mmap_min_addr 32768
write /proc/sys/net/ipv4/ping_group_range "0 2147483647"
+ write /proc/sys/net/unix/max_dgram_qlen 300
write /proc/sys/kernel/sched_rt_runtime_us 950000
write /proc/sys/kernel/sched_rt_period_us 1000000
@@ -223,23 +224,16 @@
mkdir /data/misc/radio 0770 system radio
mkdir /data/misc/sms 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
- restorecon_recursive /data/misc/zoneinfo
mkdir /data/misc/vpn 0770 system vpn
mkdir /data/misc/systemkeys 0700 system system
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
- restorecon_recursive /data/misc/wifi/sockets
mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
mkdir /data/misc/dhcp 0770 dhcp dhcp
# give system access to wpa_supplicant.conf for backup and restore
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
mkdir /data/misc/media 0700 media media
- restorecon_recursive /data/misc/media
-
- # Set security context of any pre-existing /data/misc/adb/adb_keys file.
- restorecon /data/misc/adb
- restorecon /data/misc/adb/adb_keys
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
@@ -271,7 +265,6 @@
# create directory for MediaDrm plug-ins - give drm the read/write access to
# the following directory.
mkdir /data/mediadrm 0770 mediadrm mediadrm
- restorecon_recursive /data/mediadrm
# symlink to bugreport storage location
symlink /data/data/com.android.shell/files/bugreports /data/bugreports
@@ -282,6 +275,9 @@
# Reload policy from /data/security if present.
setprop selinux.reload_policy 1
+ # Set SELinux security contexts on upgrade or policy update.
+ restorecon_recursive /data
+
# If there is no fs-post-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
# won't work.
@@ -470,6 +466,12 @@
critical
socket lmkd seqpacket 0660 system system
+service logd /system/bin/logd
+ class main
+ socket logd stream 0666 logd logd
+ socket logdr seqpacket 0666 logd logd
+ socket logdw dgram 0222 logd logd
+
service servicemanager /system/bin/servicemanager
class core
user system
@@ -495,6 +497,9 @@
service debuggerd /system/bin/debuggerd
class main
+service debuggerd64 /system/bin/debuggerd64
+ class main
+
service ril-daemon /system/bin/rild
class main
socket rild stream 660 root radio
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 05fbfba..6a9c2eb 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -200,7 +200,7 @@
}
static int int_hash(void *key) {
- return (int) key;
+ return (int) (uintptr_t) key;
}
static bool int_equals(void *keyA, void *keyB) {
@@ -232,7 +232,7 @@
* buffer at the same time. This allows us to share the underlying storage. */
union {
__u8 request_buffer[MAX_REQUEST_SIZE];
- __u8 read_buffer[MAX_READ];
+ __u8 read_buffer[MAX_READ + PAGESIZE];
};
};
@@ -487,7 +487,7 @@
break;
case PERM_ANDROID_DATA:
case PERM_ANDROID_OBB:
- appid = (appid_t) hashmapGet(fuse->package_to_appid, node->name);
+ appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
if (appid != 0) {
node->uid = multiuser_get_uid(parent->userid, appid);
}
@@ -511,7 +511,7 @@
}
appid_t appid = multiuser_get_app_id(hdr->uid);
- return hashmapContainsKey(fuse->appid_with_rw, (void*) appid);
+ return hashmapContainsKey(fuse->appid_with_rw, (void*) (uintptr_t) appid);
}
/* Kernel has already enforced everything we returned through
@@ -1218,6 +1218,7 @@
__u32 size = req->size;
__u64 offset = req->offset;
int res;
+ __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGESIZE) & ~((uintptr_t)PAGESIZE-1));
/* Don't access any other fields of hdr or req beyond this point, the read buffer
* overlaps the request buffer and will clobber data in the request. This
@@ -1225,14 +1226,14 @@
TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
h, h->fd, size, offset);
- if (size > sizeof(handler->read_buffer)) {
+ if (size > MAX_READ) {
return -EINVAL;
}
- res = pread64(h->fd, handler->read_buffer, size, offset);
+ res = pread64(h->fd, read_buffer, size, offset);
if (res < 0) {
return -errno;
}
- fuse_reply(fuse, unique, handler->read_buffer, res);
+ fuse_reply(fuse, unique, read_buffer, res);
return NO_STATUS;
}
@@ -1243,6 +1244,12 @@
struct fuse_write_out out;
struct handle *h = id_to_ptr(req->fh);
int res;
+ __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGESIZE)));
+
+ if (req->flags & O_DIRECT) {
+ memcpy(aligned_buffer, buffer, req->size);
+ buffer = (const __u8*) aligned_buffer;
+ }
TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
h, h->fd, req->size, req->offset);
@@ -1496,7 +1503,8 @@
return handle_release(fuse, handler, hdr, req);
}
- case FUSE_FSYNC: {
+ case FUSE_FSYNC:
+ case FUSE_FSYNCDIR: {
const struct fuse_fsync_in *req = data;
return handle_fsync(fuse, handler, hdr, req);
}
@@ -1524,7 +1532,6 @@
return handle_releasedir(fuse, handler, hdr, req);
}
-// case FUSE_FSYNCDIR:
case FUSE_INIT: { /* init_in -> init_out */
const struct fuse_init_in *req = data;
return handle_init(fuse, handler, hdr, req);
@@ -1621,12 +1628,12 @@
if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
char* package_name_dup = strdup(package_name);
- hashmapPut(fuse->package_to_appid, package_name_dup, (void*) appid);
+ hashmapPut(fuse->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
char* token = strtok(gids, ",");
while (token != NULL) {
if (strtoul(token, NULL, 10) == fuse->write_gid) {
- hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 1);
+ hashmapPut(fuse->appid_with_rw, (void*) (uintptr_t) appid, (void*) (uintptr_t) 1);
break;
}
token = strtok(NULL, ",");
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 4fff9f5..3deb3e7 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -80,15 +80,23 @@
grep
LOCAL_SRC_FILES := \
+ cp/cp.c \
+ cp/utils.c \
dynarray.c \
- toolbox.c \
+ grep/fastgrep.c \
+ grep/file.c \
+ grep/grep.c \
+ grep/queue.c \
+ grep/util.c \
$(patsubst %,%.c,$(TOOLS)) \
- cp/cp.c cp/utils.c \
- grep/grep.c grep/fastgrep.c grep/file.c grep/queue.c grep/util.c
+ toolbox.c \
+ uid_from_user.c \
LOCAL_C_INCLUDES := bionic/libc/bionic
-LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += \
+ -Wno-unused-parameter \
+ -include bsd-compatibility.h \
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
new file mode 100644
index 0000000..a304631
--- /dev/null
+++ b/toolbox/bsd-compatibility.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014, 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.
+ */
+
+#include <sys/types.h>
+
+/* We want chown to support user.group as well as user:group. */
+#define SUPPORT_DOT
+
+__BEGIN_DECLS
+
+extern int uid_from_user(const char* name, uid_t* uid);
+
+__END_DECLS
diff --git a/toolbox/chown.c b/toolbox/chown.c
index 92efee6..6ac2233 100644
--- a/toolbox/chown.c
+++ b/toolbox/chown.c
@@ -1,73 +1,302 @@
+/* $NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993, 1994, 2003
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994, 2003\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94";
+#else
+__RCSID("$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <errno.h>
-#include <pwd.h>
-#include <grp.h>
-
#include <unistd.h>
-#include <time.h>
+#include <getopt.h>
-int chown_main(int argc, char **argv)
+static void a_gid(const char *);
+static void a_uid(const char *);
+static id_t id(const char *, const char *);
+__dead static void usage(void);
+
+static uid_t uid;
+static gid_t gid;
+static int ischown;
+static const char *myname;
+
+struct option chown_longopts[] = {
+ { "reference", required_argument, 0,
+ 1 },
+ { NULL, 0, 0,
+ 0 },
+};
+
+int
+chown_main(int argc, char **argv)
{
- int i;
+ FTS *ftsp;
+ FTSENT *p;
+ int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag;
+ char *cp, *reference;
+ int (*change_owner)(const char *, uid_t, gid_t);
- if (argc < 3) {
- fprintf(stderr, "Usage: chown <USER>[:GROUP] <FILE1> [FILE2] ...\n");
- return 10;
- }
+ setprogname(*argv);
- // Copy argv[1] to 'user' so we can truncate it at the period
- // if a group id specified.
- char user[32];
- char *group = NULL;
- strncpy(user, argv[1], sizeof(user));
- if ((group = strchr(user, ':')) != NULL) {
- *group++ = '\0';
- } else if ((group = strchr(user, '.')) != NULL) {
- *group++ = '\0';
- }
+ (void)setlocale(LC_ALL, "");
- // Lookup uid (and gid if specified)
- struct passwd *pw;
- struct group *grp = NULL;
- uid_t uid;
- gid_t gid = -1; // passing -1 to chown preserves current group
+ myname = getprogname();
+ ischown = (myname[2] == 'o');
+ reference = NULL;
- pw = getpwnam(user);
- if (pw != NULL) {
- uid = pw->pw_uid;
- } else {
- char* endptr;
- uid = (int) strtoul(user, &endptr, 0);
- if (endptr == user) { // no conversion
- fprintf(stderr, "No such user '%s'\n", user);
- return 10;
- }
- }
+ Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
+ while ((ch = getopt_long(argc, argv, "HLPRfhv",
+ chown_longopts, NULL)) != -1)
+ switch (ch) {
+ case 1:
+ reference = optarg;
+ break;
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ /*
+ * In System V the -h option causes chown/chgrp to
+ * change the owner/group of the symbolic link.
+ * 4.4BSD's symbolic links didn't have owners/groups,
+ * so it was an undocumented noop.
+ * In NetBSD 1.3, lchown(2) is introduced.
+ */
+ hflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
- if (group != NULL) {
- grp = getgrnam(group);
- if (grp != NULL) {
- gid = grp->gr_gid;
- } else {
- char* endptr;
- gid = (int) strtoul(group, &endptr, 0);
- if (endptr == group) { // no conversion
- fprintf(stderr, "No such group '%s'\n", group);
- return 10;
- }
- }
- }
+ if (argc == 0 || (argc == 1 && reference == NULL))
+ usage();
- for (i = 2; i < argc; i++) {
- if (chown(argv[i], uid, gid) < 0) {
- fprintf(stderr, "Unable to chown %s: %s\n", argv[i], strerror(errno));
- return 10;
- }
- }
+ fts_options = FTS_PHYSICAL;
+ if (Rflag) {
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ if (hflag)
+ errx(EXIT_FAILURE,
+ "the -L and -h options "
+ "may not be specified together.");
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ } else if (!hflag)
+ fts_options |= FTS_COMFOLLOW;
- return 0;
+ uid = (uid_t)-1;
+ gid = (gid_t)-1;
+ if (reference == NULL) {
+ if (ischown) {
+ if ((cp = strchr(*argv, ':')) != NULL) {
+ *cp++ = '\0';
+ a_gid(cp);
+ }
+#ifdef SUPPORT_DOT
+ else if ((cp = strrchr(*argv, '.')) != NULL) {
+ if (uid_from_user(*argv, &uid) == -1) {
+ *cp++ = '\0';
+ a_gid(cp);
+ }
+ }
+#endif
+ a_uid(*argv);
+ } else
+ a_gid(*argv);
+ argv++;
+ } else {
+ struct stat st;
+
+ if (stat(reference, &st) == -1)
+ err(EXIT_FAILURE, "Cannot stat `%s'", reference);
+ if (ischown)
+ uid = st.st_uid;
+ gid = st.st_gid;
+ }
+
+ if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
+ err(EXIT_FAILURE, "fts_open");
+
+ for (rval = EXIT_SUCCESS; (p = fts_read(ftsp)) != NULL;) {
+ change_owner = chown;
+ switch (p->fts_info) {
+ case FTS_D:
+ if (!Rflag) /* Change it at FTS_DP. */
+ fts_set(ftsp, p, FTS_SKIP);
+ continue;
+ case FTS_DNR: /* Warn, chown, continue. */
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = EXIT_FAILURE;
+ break;
+ case FTS_ERR: /* Warn, continue. */
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = EXIT_FAILURE;
+ continue;
+ case FTS_SL: /* Ignore unless -h. */
+ /*
+ * All symlinks we found while doing a physical
+ * walk end up here.
+ */
+ if (!hflag)
+ continue;
+ /*
+ * Note that if we follow a symlink, fts_info is
+ * not FTS_SL but FTS_F or whatever. And we should
+ * use lchown only for FTS_SL and should use chown
+ * for others.
+ */
+ change_owner = lchown;
+ break;
+ case FTS_SLNONE: /* Ignore. */
+ /*
+ * The only symlinks that end up here are ones that
+ * don't point to anything. Note that if we are
+ * doing a phisycal walk, we never reach here unless
+ * we asked to follow explicitly.
+ */
+ continue;
+ default:
+ break;
+ }
+
+ if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) {
+ warn("%s", p->fts_path);
+ rval = EXIT_FAILURE;
+ } else {
+ if (vflag)
+ printf("%s\n", p->fts_path);
+ }
+ }
+ if (errno)
+ err(EXIT_FAILURE, "fts_read");
+ exit(rval);
+ /* NOTREACHED */
+}
+
+static void
+a_gid(const char *s)
+{
+ struct group *gr;
+
+ if (*s == '\0') /* Argument was "uid[:.]". */
+ return;
+ gr = *s == '#' ? NULL : getgrnam(s);
+ if (gr == NULL)
+ gid = id(s, "group");
+ else
+ gid = gr->gr_gid;
+ return;
+}
+
+static void
+a_uid(const char *s)
+{
+ if (*s == '\0') /* Argument was "[:.]gid". */
+ return;
+ if (*s == '#' || uid_from_user(s, &uid) == -1) {
+ uid = id(s, "user");
+ }
+ return;
+}
+
+static id_t
+id(const char *name, const char *type)
+{
+ id_t val;
+ char *ep;
+
+ errno = 0;
+ if (*name == '#')
+ name++;
+ val = (id_t)strtoul(name, &ep, 10);
+ if (errno)
+ err(EXIT_FAILURE, "%s", name);
+ if (*ep != '\0')
+ errx(EXIT_FAILURE, "%s: invalid %s name", name, type);
+ return (val);
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "Usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n"
+ "\t%s [-R [-H | -L | -P]] [-fhv] --reference=rfile file ...\n",
+ myname, ischown ? "owner:group|owner|:group" : "group",
+ myname);
+ exit(EXIT_FAILURE);
}
diff --git a/toolbox/grep/grep.c b/toolbox/grep/grep.c
index b5bb2ef..5a4fa0c 100644
--- a/toolbox/grep/grep.c
+++ b/toolbox/grep/grep.c
@@ -294,10 +294,8 @@
err(2, "%s", fn);
line = NULL;
len = 0;
-#ifndef ANDROID
while ((rlen = getline(&line, &len, f)) != -1)
add_pattern(line, *line == '\n' ? 0 : (size_t)rlen);
-#endif
free(line);
if (ferror(f))
err(2, "%s", fn);
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index 113c120..af321af 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -113,7 +113,7 @@
if (!maps)
goto out;
- while (fscanf(maps, "%*x-%*x %*s %zx %5s %ld %s\n", &offset, device, &inode,
+ while (fscanf(maps, "%*x-%*x %*s %zx %s %ld %s\n", &offset, device, &inode,
file) == 4) {
// We don't care about non-file maps
if (inode == 0 || !strcmp(device, "00:00"))
diff --git a/toolbox/mkswap.c b/toolbox/mkswap.c
index 1710ef6..0904152 100644
--- a/toolbox/mkswap.c
+++ b/toolbox/mkswap.c
@@ -1,6 +1,5 @@
#include <stdio.h>
#include <unistd.h>
-#include <asm/page.h>
#include <sys/swap.h>
#include <sys/types.h>
#include <sys/stat.h>
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
index d43b2fe..971c232 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -177,11 +177,7 @@
if (rawmode) {
rawmode = mtdinfo.oobsize;
-#if !defined(MTD_STUPID_LOCK) /* using uapi kernel headers */
ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
-#else /* still using old kernel headers */
- ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
-#endif
if (ret) {
fprintf(stderr, "failed set raw mode for %s, %s\n",
devname, strerror(errno));
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
index f9f604f..3568625 100644
--- a/toolbox/restorecon.c
+++ b/toolbox/restorecon.c
@@ -2,76 +2,44 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fts.h>
#include <selinux/selinux.h>
-#include <selinux/label.h>
#include <selinux/android.h>
-static struct selabel_handle *sehandle;
static const char *progname;
-static int nochange;
-static int verbose;
static void usage(void)
{
- fprintf(stderr, "usage: %s [-nrRv] pathname...\n", progname);
+ fprintf(stderr, "usage: %s [-DFnrRv] pathname...\n", progname);
exit(1);
}
-static int restore(const char *pathname, const struct stat *sb)
-{
- char *oldcontext, *newcontext;
-
- if (lgetfilecon(pathname, &oldcontext) < 0) {
- fprintf(stderr, "Could not get context of %s: %s\n",
- pathname, strerror(errno));
- return -1;
- }
- if (selabel_lookup(sehandle, &newcontext, pathname, sb->st_mode) < 0) {
- fprintf(stderr, "Could not lookup context for %s: %s\n", pathname,
- strerror(errno));
- return -1;
- }
- if (strcmp(newcontext, "<<none>>") &&
- strcmp(oldcontext, newcontext)) {
- if (verbose)
- printf("Relabeling %s from %s to %s.\n", pathname, oldcontext, newcontext);
- if (!nochange) {
- if (lsetfilecon(pathname, newcontext) < 0) {
- fprintf(stderr, "Could not label %s with %s: %s\n",
- pathname, newcontext, strerror(errno));
- return -1;
- }
- }
- }
- freecon(oldcontext);
- freecon(newcontext);
- return 0;
-}
-
int restorecon_main(int argc, char **argv)
{
- int ch, recurse = 0, ftsflags = FTS_PHYSICAL;
- int i = 0;
+ int ch, i, rc;
+ unsigned int flags = 0;
progname = argv[0];
do {
- ch = getopt(argc, argv, "nrRv");
+ ch = getopt(argc, argv, "DFnrRv");
if (ch == EOF)
break;
switch (ch) {
+ case 'D':
+ flags |= SELINUX_ANDROID_RESTORECON_DATADATA;
+ break;
+ case 'F':
+ flags |= SELINUX_ANDROID_RESTORECON_FORCE;
+ break;
case 'n':
- nochange = 1;
+ flags |= SELINUX_ANDROID_RESTORECON_NOCHANGE;
break;
case 'r':
case 'R':
- recurse = 1;
+ flags |= SELINUX_ANDROID_RESTORECON_RECURSE;
break;
case 'v':
- verbose = 1;
+ flags |= SELINUX_ANDROID_RESTORECON_VERBOSE;
break;
default:
usage();
@@ -83,53 +51,11 @@
if (!argc)
usage();
- sehandle = selinux_android_file_context_handle();
-
- if (!sehandle) {
- fprintf(stderr, "Could not load file_contexts: %s\n",
- strerror(errno));
- return -1;
- }
-
- if (recurse) {
- FTS *fts;
- FTSENT *ftsent;
- fts = fts_open(argv, ftsflags, NULL);
- if (!fts) {
- fprintf(stderr, "Could not traverse filesystems (first was %s): %s\n",
- argv[0], strerror(errno));
- return -1;
- }
- while ((ftsent = fts_read(fts))) {
- switch (ftsent->fts_info) {
- case FTS_DP:
- break;
- case FTS_DNR:
- case FTS_ERR:
- case FTS_NS:
- fprintf(stderr, "Could not access %s: %s\n", ftsent->fts_path,
- strerror(errno));
- fts_set(fts, ftsent, FTS_SKIP);
- break;
- default:
- if (restore(ftsent->fts_path, ftsent->fts_statp) < 0)
- fts_set(fts, ftsent, FTS_SKIP);
- break;
- }
- }
- } else {
- int i, rc;
- struct stat sb;
-
- for (i = 0; i < argc; i++) {
- rc = lstat(argv[i], &sb);
- if (rc < 0) {
- fprintf(stderr, "Could not stat %s: %s\n", argv[i],
- strerror(errno));
- continue;
- }
- restore(argv[i], &sb);
- }
+ for (i = 0; i < argc; i++) {
+ rc = selinux_android_restorecon(argv[i], flags);
+ if (rc < 0)
+ fprintf(stderr, "Could not restorecon %s: %s\n", argv[i],
+ strerror(errno));
}
return 0;
diff --git a/toolbox/swapoff.c b/toolbox/swapoff.c
index 8f14158..d8f6a00 100644
--- a/toolbox/swapoff.c
+++ b/toolbox/swapoff.c
@@ -1,6 +1,5 @@
#include <stdio.h>
#include <unistd.h>
-#include <asm/page.h>
#include <sys/swap.h>
int swapoff_main(int argc, char **argv)
diff --git a/toolbox/swapon.c b/toolbox/swapon.c
index a810b3d..21d2287 100644
--- a/toolbox/swapon.c
+++ b/toolbox/swapon.c
@@ -2,7 +2,6 @@
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
-#include <asm/page.h>
#include <sys/swap.h>
void usage(char *name)
diff --git a/toolbox/uid_from_user.c b/toolbox/uid_from_user.c
new file mode 100644
index 0000000..fd48d3c
--- /dev/null
+++ b/toolbox/uid_from_user.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014, 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.
+ */
+
+#include <pwd.h>
+#include <sys/types.h>
+
+int uid_from_user(const char* name, uid_t* uid) {
+ struct passwd* pw = getpwnam(name);
+ if (pw == NULL) {
+ return -1;
+ }
+ *uid = pw->pw_uid;
+ return 0;
+}