Merge "adb: do not mix printf() with write() when writing to stdout."
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 866e3af..fd34052 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -61,6 +61,8 @@
#define VENDOR_ID_GARMIN_ASUS 0x091E
// Sharp's USB Vendor ID
#define VENDOR_ID_SHARP 0x04dd
+// ZTE's USB Vendor ID
+#define VENDOR_ID_ZTE 0x19D2
/** built-in vendor list */
int builtInVendorIds[] = {
@@ -77,6 +79,7 @@
VENDOR_ID_NVIDIA,
VENDOR_ID_GARMIN_ASUS,
VENDOR_ID_SHARP,
+ VENDOR_ID_ZTE,
};
#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/include/cutils/iosched_policy.h b/include/cutils/iosched_policy.h
new file mode 100644
index 0000000..07c5d1f
--- /dev/null
+++ b/include/cutils/iosched_policy.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CUTILS_IOSCHED_POLICY_H
+#define __CUTILS_IOSCHED_POLICY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ IoSchedClass_NONE,
+ IoSchedClass_RT,
+ IoSchedClass_BE,
+ IoSchedClass_IDLE,
+} IoSchedClass;
+
+extern int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio);
+extern int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CUTILS_IOSCHED_POLICY_H */
diff --git a/init/init.c b/init/init.c
index 16a3530..4d98cc2 100755
--- a/init/init.c
+++ b/init/init.c
@@ -35,6 +35,7 @@
#include <sys/reboot.h>
#include <cutils/sockets.h>
+#include <cutils/iosched_policy.h>
#include <termios.h>
#include <linux/kd.h>
#include <linux/keychord.h>
@@ -224,6 +225,13 @@
}
}
+ if (svc->ioprio_class != IoSchedClass_NONE) {
+ if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
+ ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
+ getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
+ }
+ }
+
if (needs_console) {
setsid();
open_console();
diff --git a/init/init.h b/init/init.h
index 60c3055..8c0571c 100644
--- a/init/init.h
+++ b/init/init.h
@@ -146,6 +146,9 @@
int nkeycodes;
int keychord_id;
+ int ioprio_class;
+ int ioprio_pri;
+
int nargs;
/* "MUST BE AT THE END OF THE STRUCT" */
char *args[1];
diff --git a/init/keywords.h b/init/keywords.h
index 308118e..254c785 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -75,6 +75,7 @@
KEYWORD(chmod, COMMAND, 2, do_chmod)
KEYWORD(loglevel, COMMAND, 1, do_loglevel)
KEYWORD(device, COMMAND, 4, do_device)
+ KEYWORD(ioprio, OPTION, 0, 0)
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
};
diff --git a/init/parser.c b/init/parser.c
index 54622cc..7da0d19 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -10,6 +10,8 @@
#include "init.h"
#include "property_service.h"
+#include <cutils/iosched_policy.h>
+
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -155,6 +157,7 @@
if (!strcmp(s, "ostname")) return K_hostname;
break;
case 'i':
+ if (!strcmp(s, "oprio")) return K_ioprio;
if (!strcmp(s, "fup")) return K_ifup;
if (!strcmp(s, "nsmod")) return K_insmod;
if (!strcmp(s, "mport")) return K_import;
@@ -619,6 +622,8 @@
return;
}
+ svc->ioprio_class = IoSchedClass_NONE;
+
kw = lookup_keyword(args[0]);
switch (kw) {
case K_capability:
@@ -636,6 +641,28 @@
case K_disabled:
svc->flags |= SVC_DISABLED;
break;
+ case K_ioprio:
+ if (nargs != 3) {
+ parse_error(state, "ioprio optin usage: ioprio <rt|be|idle> <ioprio 0-7>\n");
+ } else {
+ svc->ioprio_pri = strtoul(args[2], 0, 8);
+
+ if (svc->ioprio_pri < 0 || svc->ioprio_pri > 7) {
+ parse_error(state, "priority value must be range 0 - 7\n");
+ break;
+ }
+
+ if (!strcmp(args[1], "rt")) {
+ svc->ioprio_class = IoSchedClass_RT;
+ } else if (!strcmp(args[1], "be")) {
+ svc->ioprio_class = IoSchedClass_BE;
+ } else if (!strcmp(args[1], "idle")) {
+ svc->ioprio_class = IoSchedClass_IDLE;
+ } else {
+ parse_error(state, "ioprio option usage: ioprio <rt|be|idle> <0-7>\n");
+ }
+ }
+ break;
case K_group:
if (nargs < 2) {
parse_error(state, "group option requires a group id\n");
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 93933e2..4c45cc9 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -38,7 +38,8 @@
process_name.c \
properties.c \
threads.c \
- sched_policy.c
+ sched_policy.c \
+ iosched_policy.c
commonHostSources := \
ashmem-host.c
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
new file mode 100644
index 0000000..f350f58
--- /dev/null
+++ b/libcutils/iosched_policy.c
@@ -0,0 +1,67 @@
+
+/* libs/cutils/iosched_policy.c
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SCHED_H
+
+#include <cutils/iosched_policy.h>
+
+extern int ioprio_set(int which, int who, int ioprio);
+
+enum {
+ WHO_PROCESS = 1,
+ WHO_PGRP,
+ WHO_USER,
+};
+
+#define CLASS_SHIFT 13
+#define IOPRIO_NORM 4
+
+int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio) {
+#ifdef HAVE_ANDROID_OS
+ if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio) {
+#ifdef HAVE_ANDROID_OS
+ int rc;
+
+ if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) {
+ return -1;
+ }
+
+ *clazz = (rc >> CLASS_SHIFT);
+ *ioprio = (rc & 0xff);
+#else
+ *clazz = IoSchedClass_NONE;
+ *ioprio = 0;
+#endif
+ return 0;
+}
+
+#endif /* HAVE_SCHED_H */
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 3130a1c..43c9ccd 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -30,6 +30,57 @@
#define LOG_FILE_DIR "/dev/log/"
+struct queued_entry_t {
+ union {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
+ struct logger_entry entry __attribute__((aligned(4)));
+ };
+ queued_entry_t* next;
+
+ queued_entry_t() {
+ next = NULL;
+ }
+};
+
+static int cmp(queued_entry_t* a, queued_entry_t* b) {
+ int n = a->entry.sec - b->entry.sec;
+ if (n != 0) {
+ return n;
+ }
+ return a->entry.nsec - b->entry.nsec;
+}
+
+struct log_device_t {
+ char* device;
+ bool binary;
+ int fd;
+ bool printed;
+ char label;
+
+ queued_entry_t* queue;
+ log_device_t* next;
+
+ log_device_t(char* d, bool b, char l) {
+ device = d;
+ binary = b;
+ label = l;
+ next = NULL;
+ printed = false;
+ }
+
+ void enqueue(queued_entry_t* entry) {
+ if (this->queue == NULL) {
+ this->queue = entry;
+ } else {
+ queued_entry_t** e = &this->queue;
+ while (*e && cmp(entry, *e) >= 0) {
+ e = &((*e)->next);
+ }
+ entry->next = *e;
+ *e = entry;
+ }
+ }
+};
namespace android {
@@ -40,8 +91,8 @@
static int g_maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
static int g_outFD = -1;
static off_t g_outByteCount = 0;
-static int g_isBinary = 0;
static int g_printBinary = 0;
+static int g_devCount = 0;
static EventTagMap* g_eventTagMap = NULL;
@@ -103,14 +154,37 @@
} while (ret < 0 && errno == EINTR);
}
-static void processBuffer(struct logger_entry *buf)
+static void processBuffer(log_device_t* dev, struct logger_entry *buf)
{
int bytesWritten;
int err;
AndroidLogEntry entry;
char binaryMsgBuf[1024];
- if (g_isBinary) {
+ if (!dev->printed) {
+ dev->printed = true;
+ if (g_devCount > 1) {
+ snprintf(binaryMsgBuf, sizeof(binaryMsgBuf), "--------- beginning of %s\n",
+ dev->device);
+ bytesWritten = write(g_outFD, binaryMsgBuf, strlen(binaryMsgBuf));
+ if (bytesWritten < 0) {
+ perror("output error");
+ exit(-1);
+ }
+ }
+ }
+
+ if (g_devCount > 1) {
+ binaryMsgBuf[0] = dev->label;
+ binaryMsgBuf[1] = ' ';
+ bytesWritten = write(g_outFD, binaryMsgBuf, 2);
+ if (bytesWritten < 0) {
+ perror("output error");
+ exit(-1);
+ }
+ }
+
+ if (dev->binary) {
err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
binaryMsgBuf, sizeof(binaryMsgBuf));
//printf(">>> pri=%d len=%d msg='%s'\n",
@@ -142,36 +216,125 @@
return;
}
-static void readLogLines(int logfd)
+static void chooseFirst(log_device_t* dev, log_device_t** firstdev, queued_entry_t** firstentry) {
+ *firstdev = NULL;
+ *firstentry = NULL;
+ int i=0;
+ for (; dev; dev=dev->next) {
+ i++;
+ if (dev->queue) {
+ if ((*firstentry) == NULL || cmp(dev->queue, *firstentry) < 0) {
+ (*firstentry) = dev->queue;
+ *firstdev = dev;
+ }
+ }
+ }
+}
+
+static void printEntry(log_device_t* dev, queued_entry_t* entry) {
+ if (g_printBinary) {
+ printBinary(&entry->entry);
+ } else {
+ processBuffer(dev, &entry->entry);
+ }
+}
+
+static void eatEntry(log_device_t* dev, queued_entry_t* entry) {
+ if (dev->queue != entry) {
+ perror("assertion failed: entry isn't first in queue");
+ exit(1);
+ }
+ printEntry(dev, entry);
+ dev->queue = entry->next;
+ delete entry;
+}
+
+static void readLogLines(log_device_t* devices)
{
+ log_device_t* dev;
+ int max = 0;
+ queued_entry_t* entry;
+ queued_entry_t* old;
+ int ret;
+ bool somethingForEveryone;
+ bool sleep = true;
+
+ int result;
+ fd_set readset;
+
+ for (dev=devices; dev; dev = dev->next) {
+ if (dev->fd > max) {
+ max = dev->fd;
+ }
+ }
+
while (1) {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
- struct logger_entry *entry = (struct logger_entry *) buf;
- int ret;
+ do {
+ timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.
+ FD_ZERO(&readset);
+ for (dev=devices; dev; dev = dev->next) {
+ FD_SET(dev->fd, &readset);
+ }
+ result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
+ } while (result == -1 && errno == EINTR);
- ret = read(logfd, entry, LOGGER_ENTRY_MAX_LEN);
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- if (errno == EAGAIN)
- break;
- perror("logcat read");
- exit(EXIT_FAILURE);
+ if (result >= 0) {
+ for (dev=devices; dev; dev = dev->next) {
+ if (FD_ISSET(dev->fd, &readset)) {
+ entry = new queued_entry_t;
+ /* NOTE: driver guarantees we read exactly one full entry */
+ ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ delete entry;
+ goto next;
+ }
+ if (errno == EAGAIN) {
+ delete entry;
+ break;
+ }
+ perror("logcat read");
+ exit(EXIT_FAILURE);
+ }
+ else if (!ret) {
+ fprintf(stderr, "read: Unexpected EOF!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ entry->entry.msg[entry->entry.len] = '\0';
+
+ dev->enqueue(entry);
+ }
+ }
+
+ if (result == 0) {
+ // we did our short timeout trick and there's nothing new
+ // print all that aren't the last in their list
+ sleep = true;
+ while (true) {
+ chooseFirst(devices, &dev, &entry);
+ if (!entry) {
+ break;
+ }
+ eatEntry(dev, entry);
+ }
+ } else {
+ // print all that aren't the last in their list
+ while (true) {
+ chooseFirst(devices, &dev, &entry);
+ if (!entry) {
+ sleep = false;
+ break;
+ } else if (entry->next == NULL) {
+ sleep = false;
+ break;
+ }
+ eatEntry(dev, entry);
+ }
+ }
}
- else if (!ret) {
- fprintf(stderr, "read: Unexpected EOF!\n");
- exit(EXIT_FAILURE);
- }
-
- /* NOTE: driver guarantees we read exactly one full entry */
-
- entry->msg[entry->len] = '\0';
-
- if (g_printBinary) {
- printBinary(entry);
- } else {
- (void) processBuffer(entry);
- }
+next:
+ ;
}
}
@@ -275,16 +438,17 @@
extern "C" void logprint_run_tests(void);
-int main (int argc, char **argv)
+int main(int argc, char **argv)
{
- int logfd;
int err;
int hasSetLogFormat = 0;
int clearLog = 0;
int getLogSize = 0;
int mode = O_RDONLY;
- char *log_device = strdup("/dev/"LOGGER_LOG_MAIN);
const char *forceFilters = NULL;
+ log_device_t* devices = NULL;
+ log_device_t* dev;
+ bool needBinary = false;
g_logformat = android_log_format_new();
@@ -326,14 +490,27 @@
getLogSize = 1;
break;
- case 'b':
- free(log_device);
- log_device =
- (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
- strcpy(log_device, LOG_FILE_DIR);
- strcat(log_device, optarg);
+ case 'b': {
+ char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
+ strcpy(buf, LOG_FILE_DIR);
+ strcat(buf, optarg);
- android::g_isBinary = (strcmp(optarg, "events") == 0);
+ bool binary = strcmp(optarg, "events") == 0;
+ if (binary) {
+ needBinary = true;
+ }
+
+ if (devices) {
+ dev = devices;
+ while (dev->next) {
+ dev = dev->next;
+ }
+ dev->next = new log_device_t(buf, binary, optarg[0]);
+ } else {
+ devices = new log_device_t(buf, binary, optarg[0]);
+ }
+ android::g_devCount++;
+ }
break;
case 'B':
@@ -460,6 +637,11 @@
}
}
+ if (!devices) {
+ devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, LOGGER_LOG_MAIN[0]);
+ android::g_devCount = 1;
+ }
+
if (android::g_logRotateSizeKBytes != 0
&& android::g_outputFileName == NULL
) {
@@ -516,42 +698,50 @@
}
}
- logfd = open(log_device, mode);
- if (logfd < 0) {
- fprintf(stderr, "Unable to open log device '%s': %s\n",
- log_device, strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (clearLog) {
- int ret;
- ret = android::clearLog(logfd);
- if (ret) {
- perror("ioctl");
+ dev = devices;
+ while (dev) {
+ dev->fd = open(dev->device, mode);
+ if (dev->fd < 0) {
+ fprintf(stderr, "Unable to open log device '%s': %s\n",
+ dev->device, strerror(errno));
exit(EXIT_FAILURE);
}
- return 0;
+
+ if (clearLog) {
+ int ret;
+ ret = android::clearLog(dev->fd);
+ if (ret) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+ return 0;
+ }
+
+ if (getLogSize) {
+ int size, readable;
+
+ size = android::getLogSize(dev->fd);
+ if (size < 0) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+
+ readable = android::getLogReadableSize(dev->fd);
+ if (readable < 0) {
+ perror("ioctl");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%s: ring buffer is %dKb (%dKb 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);
+ }
+
+ dev = dev->next;
}
if (getLogSize) {
- int size, readable;
-
- size = android::getLogSize(logfd);
- if (size < 0) {
- perror("ioctl");
- exit(EXIT_FAILURE);
- }
-
- readable = android::getLogReadableSize(logfd);
- if (readable < 0) {
- perror("ioctl");
- exit(EXIT_FAILURE);
- }
-
- printf("ring buffer is %dKb (%dKb consumed), "
- "max entry is %db, max payload is %db\n",
- size / 1024, readable / 1024,
- (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
return 0;
}
@@ -559,10 +749,10 @@
//LOG_EVENT_LONG(11, 0x1122334455667788LL);
//LOG_EVENT_STRING(0, "whassup, doc?");
- if (android::g_isBinary)
+ if (needBinary)
android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
- android::readLogLines(logfd);
+ android::readLogLines(devices);
return 0;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 059ac0a..97a3b38 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -58,7 +58,9 @@
# Create cgroup mount points for process groups
mkdir /dev/cpuctl
- mount cgroup none /dev/cpuctl cpu
+ mount cgroup none /dev/cpuctl cpu,cpuacct
+ mkdir /dev/cpuctl/uid
+ chmod 0775 /dev/cpuctl/uid
chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
chmod 0777 /dev/cpuctl/tasks
@@ -281,6 +283,7 @@
service vold /system/bin/vold
socket vold stream 0660 root mount
+ ioprio be 2
service netd /system/bin/netd
socket netd stream 0660 root system
@@ -302,6 +305,7 @@
service media /system/bin/mediaserver
user media
group system audio camera graphics inet net_bt net_bt_admin
+ ioprio rt 4
service bootanim /system/bin/bootanimation
user graphics
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 122a544..a6114ac 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -51,7 +51,8 @@
iftop \
id \
vmstat \
- nandread
+ nandread \
+ ionice
LOCAL_SRC_FILES:= \
toolbox.c \
diff --git a/toolbox/ionice.c b/toolbox/ionice.c
new file mode 100644
index 0000000..4a182f2
--- /dev/null
+++ b/toolbox/ionice.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <cutils/iosched_policy.h>
+
+static char *classes[] = {"none", "rt", "be", "idle", NULL};
+
+int ionice_main(int argc, char *argv[])
+{
+ IoSchedClass clazz = IoSchedClass_NONE;
+ int ioprio = 0;
+ int pid;
+
+ if(argc != 2 && argc != 4) {
+ fprintf(stderr, "usage: ionice <pid> [none|rt|be|idle] [prio]\n");
+ return 1;
+ }
+
+ if (!(pid = atoi(argv[1]))) {
+ fprintf(stderr, "Invalid pid specified\n");
+ return 1;
+ }
+
+ if (argc == 2) {
+ if (android_get_ioprio(pid, &clazz, &ioprio)) {
+ fprintf(stderr, "Failed to read priority (%s)\n", strerror(errno));
+ return 1;
+ }
+ fprintf(stdout, "Pid %d, class %s (%d), prio %d\n", pid, classes[clazz], clazz, ioprio);
+ return 0;
+ }
+
+ if (!strcmp(argv[2], "none")) {
+ clazz = IoSchedClass_NONE;
+ } else if (!strcmp(argv[2], "rt")) {
+ clazz = IoSchedClass_RT;
+ } else if (!strcmp(argv[2], "be")) {
+ clazz = IoSchedClass_BE;
+ } else if (!strcmp(argv[2], "idle")) {
+ clazz = IoSchedClass_IDLE;
+ } else {
+ fprintf(stderr, "Unsupported class '%s'\n", argv[2]);
+ return 1;
+ }
+
+ ioprio = atoi(argv[3]);
+
+ printf("Setting pid %d i/o class to %d, prio %d\n", pid, clazz, ioprio);
+ if (android_set_ioprio(pid, clazz, ioprio)) {
+ fprintf(stderr, "Failed to set priority (%s)\n", strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}