Merge "crash_reporter: Support crashes from arbitrary users"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 1c1683e..1eb3a3c 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -245,7 +245,7 @@
if (pieces.size() > 2) {
const std::string& props = pieces[2];
- for (auto& prop : android::base::Split(props, ";")) {
+ for (const auto& prop : android::base::Split(props, ";")) {
// The list of properties was traditionally ;-terminated rather than ;-separated.
if (prop.empty()) continue;
@@ -904,7 +904,7 @@
}
std::string error_msg;
- atransport* transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
+ atransport* transport = acquire_one_transport(type, serial, nullptr, &error_msg);
if (!transport) {
SendFail(reply_fd, error_msg);
return 1;
@@ -990,13 +990,13 @@
serial = service;
}
- std::string error_msg;
- atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg);
+ std::string error;
+ atransport* t = acquire_one_transport(type, serial, nullptr, &error);
if (t != nullptr) {
s->transport = t;
SendOkay(reply_fd);
} else {
- SendFail(reply_fd, error_msg);
+ SendFail(reply_fd, error);
}
return 1;
}
@@ -1014,12 +1014,12 @@
}
if (!strcmp(service, "features")) {
- std::string error_msg;
- atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg);
+ std::string error;
+ atransport* t = acquire_one_transport(type, serial, nullptr, &error);
if (t != nullptr) {
SendOkay(reply_fd, FeatureSetToString(t->features()));
} else {
- SendFail(reply_fd, error_msg);
+ SendFail(reply_fd, error);
}
return 0;
}
@@ -1049,29 +1049,41 @@
return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
}
- // returns our value for ADB_SERVER_VERSION
+ // Returns our value for ADB_SERVER_VERSION.
if (!strcmp(service, "version")) {
return SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
}
// These always report "unknown" rather than the actual error, for scripts.
if (!strcmp(service, "get-serialno")) {
- std::string ignored;
- atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
- return SendOkay(reply_fd, (t && t->serial) ? t->serial : "unknown");
+ std::string error;
+ atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+ if (t) {
+ return SendOkay(reply_fd, t->serial ? t->serial : "unknown");
+ } else {
+ return SendFail(reply_fd, error);
+ }
}
if (!strcmp(service, "get-devpath")) {
- std::string ignored;
- atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
- return SendOkay(reply_fd, (t && t->devpath) ? t->devpath : "unknown");
+ std::string error;
+ atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+ if (t) {
+ return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown");
+ } else {
+ return SendFail(reply_fd, error);
+ }
}
if (!strcmp(service, "get-state")) {
- std::string ignored;
- atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
- return SendOkay(reply_fd, t ? t->connection_state_name() : "unknown");
+ std::string error;
+ atransport* t = acquire_one_transport(type, serial, nullptr, &error);
+ if (t) {
+ return SendOkay(reply_fd, t->connection_state_name());
+ } else {
+ return SendFail(reply_fd, error);
+ }
}
- // indicates a new emulator instance has started
+ // Indicates a new emulator instance has started.
if (!strncmp(service, "emulator:", 9)) {
int port = atoi(service+9);
local_connect(port);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 7b314c3..5309519 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -368,7 +368,7 @@
return;
}
- for (auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
+ for (const auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
if (!read_key(path.c_str(), key_list)) {
D("Failed to read '%s'", path.c_str());
}
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 984910d..fa8ce9e 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -209,9 +209,8 @@
adb_close(fd);
if (sscanf(&version_string[0], "%04x", &version) != 1) {
- *error = android::base::StringPrintf(
- "cannot parse version string: %s",
- version_string.c_str());
+ *error = android::base::StringPrintf("cannot parse version string: %s",
+ version_string.c_str());
return -1;
}
} else {
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 5e5ca7f..0531cf9 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -1093,8 +1093,6 @@
}
// TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
- const char* serial = getenv("ANDROID_SERIAL");
-
/* Validate and assign the server port */
const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
int server_port = DEFAULT_ADB_PORT;
@@ -1108,7 +1106,9 @@
}
}
- /* modifiers and flags */
+ // We need to check for -d and -e before we look at $ANDROID_SERIAL.
+ const char* serial = nullptr;
+
while (argc > 0) {
if (!strcmp(argv[0],"server")) {
is_server = 1;
@@ -1199,6 +1199,11 @@
argv++;
}
+ // If none of -d, -e, or -s were specified, try $ANDROID_SERIAL.
+ if (transport_type == kTransportAny && serial == nullptr) {
+ serial = getenv("ANDROID_SERIAL");
+ }
+
adb_set_transport(transport_type, serial);
adb_set_tcp_specifics(server_port);
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 18b64f6..ddd15a2 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -199,7 +199,7 @@
static std::string dump_pollfds(const std::vector<pollfd>& pollfds) {
std::string result;
- for (auto& pollfd : pollfds) {
+ for (const auto& pollfd : pollfds) {
std::string op;
if (pollfd.events & POLLIN) {
op += "R";
@@ -214,8 +214,8 @@
static void fdevent_process() {
std::vector<pollfd> pollfds;
- for (auto it = g_poll_node_map.begin(); it != g_poll_node_map.end(); ++it) {
- pollfds.push_back(it->second.pollfd);
+ for (const auto& pair : g_poll_node_map) {
+ pollfds.push_back(pair.second.pollfd);
}
CHECK_GT(pollfds.size(), 0u);
D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
@@ -224,7 +224,7 @@
PLOG(ERROR) << "poll(), ret = " << ret;
return;
}
- for (auto& pollfd : pollfds) {
+ for (const auto& pollfd : pollfds) {
if (pollfd.revents != 0) {
D("for fd %d, revents = %x", pollfd.fd, pollfd.revents);
}
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 9b56392..298ed82 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -56,7 +56,7 @@
path_components.pop_back(); // For "/system/bin/sh", only create "/system/bin".
std::string partial_path;
- for (auto& path_component : path_components) {
+ for (const auto& path_component : path_components) {
if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
partial_path += path_component;
diff --git a/adb/services.cpp b/adb/services.cpp
index e832b1e..e24b470 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -363,23 +363,31 @@
ConnectionState state;
};
-static void wait_for_state(int fd, void* cookie)
-{
+static void wait_for_state(int fd, void* cookie) {
state_info* sinfo = reinterpret_cast<state_info*>(cookie);
D("wait_for_state %d", sinfo->state);
- std::string error_msg = "unknown error";
- atransport* t = acquire_one_transport(sinfo->state, sinfo->transport_type, sinfo->serial,
- &error_msg);
- if (t != nullptr) {
- SendOkay(fd);
- } else {
- SendFail(fd, error_msg);
+ while (true) {
+ bool is_ambiguous = false;
+ std::string error = "unknown error";
+ atransport* t = acquire_one_transport(sinfo->transport_type, sinfo->serial,
+ &is_ambiguous, &error);
+ if (t != nullptr && t->connection_state == sinfo->state) {
+ SendOkay(fd);
+ break;
+ } else if (!is_ambiguous) {
+ adb_sleep_ms(1000);
+ // Try again...
+ } else {
+ SendFail(fd, error);
+ break;
+ }
}
- if (sinfo->serial)
+ if (sinfo->serial) {
free(sinfo->serial);
+ }
free(sinfo);
adb_close(fd);
D("wait_for_state is done");
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 8562496..f8c2f64 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -671,8 +671,8 @@
{
unsigned len;
#if ADB_HOST
- char *service = NULL;
- char* serial = NULL;
+ char *service = nullptr;
+ char* serial = nullptr;
TransportType type = kTransportAny;
#endif
@@ -739,7 +739,7 @@
type = kTransportAny;
service += strlen("host:");
} else {
- service = NULL;
+ service = nullptr;
}
if (service) {
@@ -782,7 +782,7 @@
SendOkay(s->peer->fd);
s->peer->ready = local_socket_ready;
- s->peer->shutdown = NULL;
+ s->peer->shutdown = nullptr;
s->peer->close = local_socket_close;
s->peer->peer = s2;
s2->peer = s->peer;
@@ -795,12 +795,10 @@
return 0;
}
#else /* !ADB_HOST */
- if (s->transport == NULL) {
+ if (s->transport == nullptr) {
std::string error_msg = "unknown failure";
- s->transport =
- acquire_one_transport(kCsAny, kTransportAny, NULL, &error_msg);
-
- if (s->transport == NULL) {
+ s->transport = acquire_one_transport(kTransportAny, nullptr, nullptr, &error_msg);
+ if (s->transport == nullptr) {
SendFail(s->peer->fd, error_msg);
goto fail;
}
@@ -822,7 +820,7 @@
** tear down
*/
s->peer->ready = local_socket_ready_notify;
- s->peer->shutdown = NULL;
+ s->peer->shutdown = nullptr;
s->peer->close = local_socket_close_notify;
s->peer->peer = 0;
/* give him our transport and upref it */
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 501a39a..e9e774f 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -653,22 +653,28 @@
return !*to_test;
}
-atransport* acquire_one_transport(ConnectionState state, TransportType type,
- const char* serial, std::string* error_out) {
- atransport *result = NULL;
- int ambiguous = 0;
+atransport* acquire_one_transport(TransportType type, const char* serial,
+ bool* is_ambiguous, std::string* error_out) {
+ atransport* result = nullptr;
-retry:
- *error_out = serial ? android::base::StringPrintf("device '%s' not found", serial) : "no devices found";
+ if (serial) {
+ *error_out = android::base::StringPrintf("device '%s' not found", serial);
+ } else if (type == kTransportLocal) {
+ *error_out = "no emulators found";
+ } else if (type == kTransportAny) {
+ *error_out = "no devices/emulators found";
+ } else {
+ *error_out = "no devices found";
+ }
adb_mutex_lock(&transport_lock);
- for (auto t : transport_list) {
+ for (const auto& t : transport_list) {
if (t->connection_state == kCsNoPerm) {
*error_out = "insufficient permissions for device";
continue;
}
- /* check for matching serial number */
+ // Check for matching serial number.
if (serial) {
if ((t->serial && !strcmp(serial, t->serial)) ||
(t->devpath && !strcmp(serial, t->devpath)) ||
@@ -677,8 +683,8 @@
qual_match(serial, "device:", t->device, false)) {
if (result) {
*error_out = "more than one device";
- ambiguous = 1;
- result = NULL;
+ if (is_ambiguous) *is_ambiguous = true;
+ result = nullptr;
break;
}
result = t;
@@ -687,24 +693,24 @@
if (type == kTransportUsb && t->type == kTransportUsb) {
if (result) {
*error_out = "more than one device";
- ambiguous = 1;
- result = NULL;
+ if (is_ambiguous) *is_ambiguous = true;
+ result = nullptr;
break;
}
result = t;
} else if (type == kTransportLocal && t->type == kTransportLocal) {
if (result) {
*error_out = "more than one emulator";
- ambiguous = 1;
- result = NULL;
+ if (is_ambiguous) *is_ambiguous = true;
+ result = nullptr;
break;
}
result = t;
} else if (type == kTransportAny) {
if (result) {
*error_out = "more than one device/emulator";
- ambiguous = 1;
- result = NULL;
+ if (is_ambiguous) *is_ambiguous = true;
+ result = nullptr;
break;
}
result = t;
@@ -713,37 +719,26 @@
}
adb_mutex_unlock(&transport_lock);
- if (result) {
- if (result->connection_state == kCsUnauthorized) {
- *error_out = "device unauthorized.\n";
- char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
- *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
- *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
- *error_out += "\n";
- *error_out += "Try 'adb kill-server' if that seems wrong.\n";
- *error_out += "Otherwise check for a confirmation dialog on your device.";
- result = NULL;
- }
+ // Don't return unauthorized devices; the caller can't do anything with them.
+ if (result && result->connection_state == kCsUnauthorized) {
+ *error_out = "device unauthorized.\n";
+ char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+ *error_out += "This adb server's $ADB_VENDOR_KEYS is ";
+ *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+ *error_out += "\n";
+ *error_out += "Try 'adb kill-server' if that seems wrong.\n";
+ *error_out += "Otherwise check for a confirmation dialog on your device.";
+ result = nullptr;
+ }
- /* offline devices are ignored -- they are either being born or dying */
- if (result && result->connection_state == kCsOffline) {
- *error_out = "device offline";
- result = NULL;
- }
-
- /* check for required connection state */
- if (result && state != kCsAny && result->connection_state != state) {
- *error_out = "invalid device state";
- result = NULL;
- }
+ // Don't return offline devices; the caller can't do anything with them.
+ if (result && result->connection_state == kCsOffline) {
+ *error_out = "device offline";
+ result = nullptr;
}
if (result) {
- /* found one that we can take */
*error_out = "success";
- } else if (state != kCsAny && (serial || !ambiguous)) {
- adb_sleep_ms(1000);
- goto retry;
}
return result;
@@ -830,7 +825,7 @@
}
void atransport::RunDisconnects() {
- for (auto& disconnect : disconnects_) {
+ for (const auto& disconnect : disconnects_) {
disconnect->func(disconnect->opaque, this);
}
disconnects_.clear();
@@ -877,7 +872,7 @@
std::string list_transports(bool long_listing) {
std::string result;
adb_mutex_lock(&transport_lock);
- for (const auto t : transport_list) {
+ for (const auto& t : transport_list) {
append_transport(t, &result, long_listing);
}
adb_mutex_unlock(&transport_lock);
@@ -887,7 +882,7 @@
/* hack for osx */
void close_usb_devices() {
adb_mutex_lock(&transport_lock);
- for (auto t : transport_list) {
+ for (const auto& t : transport_list) {
if (!t->kicked) {
t->kicked = 1;
t->kick(t);
@@ -913,7 +908,7 @@
}
adb_mutex_lock(&transport_lock);
- for (auto transport : pending_list) {
+ for (const auto& transport : pending_list) {
if (transport->serial && strcmp(serial, transport->serial) == 0) {
adb_mutex_unlock(&transport_lock);
delete t;
@@ -921,7 +916,7 @@
}
}
- for (auto transport : transport_list) {
+ for (const auto& transport : transport_list) {
if (transport->serial && strcmp(serial, transport->serial) == 0) {
adb_mutex_unlock(&transport_lock);
delete t;
diff --git a/adb/transport.h b/adb/transport.h
index dfe8875..f41a8d4 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -122,12 +122,13 @@
/*
* Obtain a transport from the available transports.
- * If state is != kCsAny, only transports in that state are considered.
- * If serial is non-NULL then only the device with that serial will be chosen.
- * If no suitable transport is found, error is set.
+ * If serial is non-null then only the device with that serial will be chosen.
+ * If multiple devices/emulators would match, *is_ambiguous (if non-null)
+ * is set to true and nullptr returned.
+ * If no suitable transport is found, error is set and nullptr returned.
*/
-atransport* acquire_one_transport(ConnectionState state, TransportType type,
- const char* serial, std::string* error_out);
+atransport* acquire_one_transport(TransportType type, const char* serial,
+ bool* is_ambiguous, std::string* error_out);
void kick_transport(atransport* t);
void update_transports(void);
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 681c57f..970b386 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -126,11 +126,10 @@
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
{ 00644, AID_APP, AID_APP, 0, "data/data/*" },
- /* the following five files are INTENTIONALLY set-uid, but they
+ /* the following four files are INTENTIONALLY set-uid, but they
* are NOT included on user builds. */
{ 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" },
- { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
{ 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" },
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 9440b68..ddbfb3e 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -656,7 +656,7 @@
break;
case 'f':
- if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
+ if ((tail_time == log_time::EPOCH) && (tail_lines == 0)) {
tail_time = lastLogTime(optarg);
}
// redirect output to a file
@@ -832,49 +832,66 @@
} else {
logger_list = android_logger_list_alloc(mode, tail_lines, 0);
}
+ const char *openDeviceFail = NULL;
+ const char *clearFail = NULL;
+ const char *setSizeFail = NULL;
+ const char *getSizeFail = NULL;
+ // We have three orthogonal actions below to clear, set log size and
+ // get log size. All sharing the same iteration loop.
while (dev) {
dev->logger_list = logger_list;
dev->logger = android_logger_open(logger_list,
android_name_to_log_id(dev->device));
if (!dev->logger) {
- logcat_panic(false, "Unable to open log device '%s'\n",
- dev->device);
+ openDeviceFail = openDeviceFail ?: dev->device;
+ dev = dev->next;
+ continue;
}
if (clearLog) {
- int ret;
- ret = android_logger_clear(dev->logger);
- if (ret) {
- logcat_panic(false, "failed to clear the log");
+ if (android_logger_clear(dev->logger)) {
+ clearFail = clearFail ?: dev->device;
}
}
- if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
- logcat_panic(false, "failed to set the log size");
+ if (setLogSize) {
+ if (android_logger_set_log_size(dev->logger, setLogSize)) {
+ setSizeFail = setSizeFail ?: dev->device;
+ }
}
if (getLogSize) {
- long size, readable;
+ long size = android_logger_get_log_size(dev->logger);
+ long readable = android_logger_get_log_readable_size(dev->logger);
- size = android_logger_get_log_size(dev->logger);
- if (size < 0) {
- logcat_panic(false, "failed to get the log size");
+ if ((size < 0) || (readable < 0)) {
+ getSizeFail = getSizeFail ?: dev->device;
+ } else {
+ printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
+ "max entry is %db, max payload is %db\n", dev->device,
+ value_of_size(size), multiplier_of_size(size),
+ value_of_size(readable), multiplier_of_size(readable),
+ (int) LOGGER_ENTRY_MAX_LEN,
+ (int) LOGGER_ENTRY_MAX_PAYLOAD);
}
-
- readable = android_logger_get_log_readable_size(dev->logger);
- if (readable < 0) {
- logcat_panic(false, "failed to get the readable log size");
- }
-
- printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
- "max entry is %db, max payload is %db\n", dev->device,
- value_of_size(size), multiplier_of_size(size),
- value_of_size(readable), multiplier_of_size(readable),
- (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
}
dev = dev->next;
}
+ // report any errors in the above loop and exit
+ if (openDeviceFail) {
+ logcat_panic(false, "Unable to open log device '%s'\n", openDeviceFail);
+ }
+ if (clearFail) {
+ logcat_panic(false, "failed to clear the '%s' log\n", clearFail);
+ }
+ if (setSizeFail) {
+ logcat_panic(false, "failed to set the '%s' log size\n", setSizeFail);
+ }
+ if (getSizeFail) {
+ logcat_panic(false, "failed to get the readable '%s' log size",
+ getSizeFail);
+ }
if (setPruneList) {
size_t len = strlen(setPruneList);
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index bcf8d82..610a6ec 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -15,10 +15,12 @@
*/
#include <ctype.h>
+#include <dirent.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -368,7 +370,7 @@
while (fgets(buffer, sizeof(buffer), fp)) {
int size, consumed, max, payload;
- char size_mult[2], consumed_mult[2];
+ char size_mult[3], consumed_mult[3];
long full_size, full_consumed;
size = consumed = max = payload = 0;
@@ -573,12 +575,12 @@
static const char comm[] = "logcat -b radio -b events -b system -b main"
" -d -f %s/log.txt -n 7 -r 1";
char command[sizeof(buf) + sizeof(comm)];
- sprintf(command, comm, buf);
+ snprintf(command, sizeof(command), comm, buf);
int ret;
EXPECT_FALSE((ret = system(command)));
if (!ret) {
- sprintf(command, "ls -s %s 2>/dev/null", buf);
+ snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
FILE *fp;
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
@@ -587,16 +589,12 @@
int count = 0;
while (fgets(buffer, sizeof(buffer), fp)) {
- static const char match_1[] = "4 log.txt";
- static const char match_2[] = "8 log.txt";
- static const char match_3[] = "12 log.txt";
- static const char match_4[] = "16 log.txt";
static const char total[] = "total ";
+ int num;
+ char c;
- if (!strncmp(buffer, match_1, sizeof(match_1) - 1)
- || !strncmp(buffer, match_2, sizeof(match_2) - 1)
- || !strncmp(buffer, match_3, sizeof(match_3) - 1)
- || !strncmp(buffer, match_4, sizeof(match_4) - 1)) {
+ if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) &&
+ (num <= 24)) {
++count;
} else if (strncmp(buffer, total, sizeof(total) - 1)) {
fprintf(stderr, "WARNING: Parse error: %s", buffer);
@@ -606,7 +604,7 @@
EXPECT_TRUE(count == 7 || count == 8);
}
}
- sprintf(command, "rm -rf %s", buf);
+ snprintf(command, sizeof(command), "rm -rf %s", buf);
EXPECT_FALSE(system(command));
}
@@ -618,12 +616,12 @@
static const char logcat_cmd[] = "logcat -b radio -b events -b system -b main"
" -d -f %s/log.txt -n 10 -r 1";
char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)];
- sprintf(command, logcat_cmd, tmp_out_dir);
+ snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
int ret;
EXPECT_FALSE((ret = system(command)));
if (!ret) {
- sprintf(command, "ls %s 2>/dev/null", tmp_out_dir);
+ snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
FILE *fp;
EXPECT_TRUE(NULL != (fp = popen(command, "r")));
@@ -659,7 +657,113 @@
pclose(fp);
EXPECT_EQ(11, log_file_count);
}
- sprintf(command, "rm -rf %s", tmp_out_dir);
+ snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
+ EXPECT_FALSE(system(command));
+}
+
+TEST(logcat, logrotate_continue) {
+ static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ char tmp_out_dir[sizeof(tmp_out_dir_form)];
+ ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
+
+ static const char log_filename[] = "log.txt";
+ static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n 256 -r 1024";
+ static const char cleanup_cmd[] = "rm -rf %s";
+ char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename)];
+ snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
+
+ int ret;
+ EXPECT_FALSE((ret = system(command)));
+ if (ret) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ FILE *fp;
+ snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, log_filename);
+ EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
+ if (!fp) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ char *line = NULL;
+ char *last_line = NULL; // this line is allowed to stutter, one-line overlap
+ char *second_last_line = NULL;
+ size_t len = 0;
+ while (getline(&line, &len, fp) != -1) {
+ free(second_last_line);
+ second_last_line = last_line;
+ last_line = line;
+ line = NULL;
+ }
+ fclose(fp);
+ free(line);
+ if (second_last_line == NULL) {
+ fprintf(stderr, "No second to last line, using last, test may fail\n");
+ second_last_line = last_line;
+ last_line = NULL;
+ }
+ free(last_line);
+ EXPECT_TRUE(NULL != second_last_line);
+ if (!second_last_line) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ // re-run the command, it should only add a few lines more content if it
+ // continues where it left off.
+ snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
+ EXPECT_FALSE((ret = system(command)));
+ if (ret) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ DIR *dir;
+ EXPECT_TRUE(NULL != (dir = opendir(tmp_out_dir)));
+ if (!dir) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ struct dirent *entry;
+ unsigned count = 0;
+ while ((entry = readdir(dir))) {
+ if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
+ continue;
+ }
+ snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, entry->d_name);
+ EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
+ if (!fp) {
+ fprintf(stderr, "%s ?\n", command);
+ continue;
+ }
+ line = NULL;
+ size_t number = 0;
+ while (getline(&line, &len, fp) != -1) {
+ ++number;
+ if (!strcmp(line, second_last_line)) {
+ EXPECT_TRUE(++count <= 1);
+ fprintf(stderr, "%s(%zu):\n", entry->d_name, number);
+ }
+ }
+ fclose(fp);
+ free(line);
+ unlink(command);
+ }
+ closedir(dir);
+ if (count > 1) {
+ char *brk = strpbrk(second_last_line, "\r\n");
+ if (!brk) {
+ brk = second_last_line + strlen(second_last_line);
+ }
+ fprintf(stderr, "\"%.*s\" occured %u times\n",
+ (int)(brk - second_last_line), second_last_line, count);
+ }
+ free(second_last_line);
+
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(system(command));
}
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 031c740..eafa28f 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -96,8 +96,7 @@
return 0;
}
- mBuf.clear((log_id_t) id, uid);
- cli->sendMsg("success");
+ cli->sendMsg(mBuf.clear((log_id_t) id, uid) ? "busy" : "success");
return 0;
}
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index c2f846e..5cfc02f 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -374,8 +374,10 @@
//
// mLogElementsLock must be held when this function is called.
//
-void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
+bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
LogTimeEntry *oldest = NULL;
+ bool busy = false;
+ bool clearAll = pruneRows == ULONG_MAX;
LogTimeEntry::lock();
@@ -393,35 +395,31 @@
LogBufferElementCollection::iterator it;
if (caller_uid != AID_ROOT) {
+ // Only here if clearAll condition (pruneRows == ULONG_MAX)
for(it = mLogElements.begin(); it != mLogElements.end();) {
LogBufferElement *e = *it;
- if (oldest && (oldest->mStart <= e->getSequence())) {
- break;
- }
-
- if (e->getLogId() != id) {
+ if ((e->getLogId() != id) || (e->getUid() != caller_uid)) {
++it;
continue;
}
- if (e->getUid() == caller_uid) {
- it = erase(it);
- pruneRows--;
- if (pruneRows == 0) {
- break;
- }
- } else {
- ++it;
+ if (oldest && (oldest->mStart <= e->getSequence())) {
+ oldest->triggerSkip_Locked(id, pruneRows);
+ busy = true;
+ break;
}
+
+ it = erase(it);
+ pruneRows--;
}
LogTimeEntry::unlock();
- return;
+ return busy;
}
// prune by worst offender by uid
bool hasBlacklist = mPrune.naughty();
- while (pruneRows > 0) {
+ while (!clearAll && (pruneRows > 0)) {
// recalculate the worst offender on every batched pass
uid_t worst = (uid_t) -1;
size_t worst_sizes = 0;
@@ -478,6 +476,7 @@
LogBufferElement *e = *it;
if (oldest && (oldest->mStart <= e->getSequence())) {
+ busy = true;
break;
}
@@ -585,7 +584,7 @@
}
bool whitelist = false;
- bool hasWhitelist = mPrune.nice();
+ bool hasWhitelist = mPrune.nice() && !clearAll;
it = mLogElements.begin();
while((pruneRows > 0) && (it != mLogElements.end())) {
LogBufferElement *e = *it;
@@ -596,6 +595,8 @@
}
if (oldest && (oldest->mStart <= e->getSequence())) {
+ busy = true;
+
if (whitelist) {
break;
}
@@ -631,6 +632,7 @@
}
if (oldest && (oldest->mStart <= e->getSequence())) {
+ busy = true;
if (stats.sizes(id) > (2 * log_buffer_size(id))) {
// kick a misbehaving log reader client off the island
oldest->release_Locked();
@@ -646,13 +648,50 @@
}
LogTimeEntry::unlock();
+
+ return (pruneRows > 0) && busy;
}
// clear all rows of type "id" from the buffer.
-void LogBuffer::clear(log_id_t id, uid_t uid) {
- pthread_mutex_lock(&mLogElementsLock);
- prune(id, ULONG_MAX, uid);
- pthread_mutex_unlock(&mLogElementsLock);
+bool LogBuffer::clear(log_id_t id, uid_t uid) {
+ bool busy = true;
+ // If it takes more than 4 tries (seconds) to clear, then kill reader(s)
+ for (int retry = 4;;) {
+ if (retry == 1) { // last pass
+ // Check if it is still busy after the sleep, we say prune
+ // one entry, not another clear run, so we are looking for
+ // the quick side effect of the return value to tell us if
+ // we have a _blocked_ reader.
+ pthread_mutex_lock(&mLogElementsLock);
+ busy = prune(id, 1, uid);
+ pthread_mutex_unlock(&mLogElementsLock);
+ // It is still busy, blocked reader(s), lets kill them all!
+ // otherwise, lets be a good citizen and preserve the slow
+ // readers and let the clear run (below) deal with determining
+ // if we are still blocked and return an error code to caller.
+ if (busy) {
+ LogTimeEntry::lock();
+ LastLogTimes::iterator times = mTimes.begin();
+ while (times != mTimes.end()) {
+ LogTimeEntry *entry = (*times);
+ // Killer punch
+ if (entry->owned_Locked() && entry->isWatching(id)) {
+ entry->release_Locked();
+ }
+ times++;
+ }
+ LogTimeEntry::unlock();
+ }
+ }
+ pthread_mutex_lock(&mLogElementsLock);
+ busy = prune(id, ULONG_MAX, uid);
+ pthread_mutex_unlock(&mLogElementsLock);
+ if (!busy || !--retry) {
+ break;
+ }
+ sleep (1); // Let reader(s) catch up after notification
+ }
+ return busy;
}
// get the used space associated with "id".
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index de76693..d8e0b90 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -63,7 +63,7 @@
int (*filter)(const LogBufferElement *element, void *arg) = NULL,
void *arg = NULL);
- void clear(log_id_t id, uid_t uid = AID_ROOT);
+ bool clear(log_id_t id, uid_t uid = AID_ROOT);
unsigned long getSize(log_id_t id);
int setSize(log_id_t id, unsigned long size);
unsigned long getSizeUsed(log_id_t id);
@@ -86,7 +86,7 @@
private:
void maybePrune(log_id_t id);
- void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
+ bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
LogBufferElementCollection::iterator erase(
LogBufferElementCollection::iterator it, bool engageStats = true);
};
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 06d865c..6d0e92e 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -42,7 +42,6 @@
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;
@@ -51,10 +50,10 @@
return false;
}
if (Gid == AID_LOG) {
- ret = true;
+ return true;
}
}
- return ret;
+ return false;
}
bool clientHasLogCredentials(SocketClient * cli) {
@@ -69,61 +68,79 @@
}
// FYI We will typically be here for 'adb logcat'
- bool ret = false;
+ char filename[256];
+ snprintf(filename, sizeof(filename), "/proc/%u/status", cli->getPid());
- char filename[1024];
- snprintf(filename, sizeof(filename), "/proc/%d/status", cli->getPid());
-
- FILE *file = fopen(filename, "r");
- if (!file) {
- return ret;
- }
-
+ bool ret;
+ bool foundLog = false;
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;
+ //
+ // Reading /proc/<pid>/status is rife with race conditions. All of /proc
+ // suffers from this and its use should be minimized. However, we have no
+ // choice.
+ //
+ // Notably the content from one 4KB page to the next 4KB page can be from a
+ // change in shape even if we are gracious enough to attempt to read
+ // atomically. getline can not even guarantee a page read is not split up
+ // and in effect can read from different vintages of the content.
+ //
+ // We are finding out in the field that a 'logcat -c' via adb occasionally
+ // is returned with permission denied when we did only one pass and thus
+ // breaking scripts. For security we still err on denying access if in
+ // doubt, but we expect the falses should be reduced significantly as
+ // three times is a charm.
+ //
+ for (int retry = 3;
+ !(ret = foundGid && foundUid && foundLog) && retry;
+ --retry) {
+ FILE *file = fopen(filename, "r");
+ if (!file) {
+ continue;
}
- }
- fclose(file);
+ char *line = NULL;
+ size_t len = 0;
+ while (getline(&line, &len, file) > 0) {
+ static const char groups_string[] = "Groups:\t";
+ static const char uid_string[] = "Uid:\t";
+ static const char gid_string[] = "Gid:\t";
- if (!foundGid || !foundUid) {
- ret = false;
+ if (strncmp(groups_string, line, sizeof(groups_string) - 1) == 0) {
+ if (groupIsLog(line + sizeof(groups_string) - 1)) {
+ foundLog = true;
+ }
+ } else if (strncmp(uid_string, line, sizeof(uid_string) - 1) == 0) {
+ uid_t u[4] = { (uid_t) -1, (uid_t) -1, (uid_t) -1, (uid_t) -1};
+
+ sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u",
+ &u[0], &u[1], &u[2], &u[3]);
+
+ // Protect against PID reuse by checking that UID is the same
+ if ((uid == u[0])
+ && (uid == u[1])
+ && (uid == u[2])
+ && (uid == u[3])) {
+ foundUid = true;
+ }
+ } else if (strncmp(gid_string, line, sizeof(gid_string) - 1) == 0) {
+ gid_t g[4] = { (gid_t) -1, (gid_t) -1, (gid_t) -1, (gid_t) -1};
+
+ sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u",
+ &g[0], &g[1], &g[2], &g[3]);
+
+ // Protect against PID reuse by checking that GID is the same
+ if ((gid == g[0])
+ && (gid == g[1])
+ && (gid == g[2])
+ && (gid == g[3])) {
+ foundGid = true;
+ }
+ }
+ }
+ free(line);
+ fclose(file);
}
return ret;
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 68a0680..229be3c 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -128,9 +128,9 @@
lock();
- while (me->threadRunning && !me->isError_Locked()) {
- uint64_t start = me->mStart;
+ uint64_t start = me->mStart;
+ while (me->threadRunning && !me->isError_Locked()) {
unlock();
if (me->mTail) {
@@ -143,8 +143,11 @@
if (start == LogBufferElement::FLUSH_ERROR) {
me->error_Locked();
+ break;
}
+ me->mStart = start + 1;
+
if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
break;
}
diff --git a/metricsd/uploader/proto/system_profile.proto b/metricsd/uploader/proto/system_profile.proto
index 4cab0d9..bac828b 100644
--- a/metricsd/uploader/proto/system_profile.proto
+++ b/metricsd/uploader/proto/system_profile.proto
@@ -88,7 +88,7 @@
optional string application_locale = 4;
message BrilloDeviceData {
- optional string build_target_id = 1;
+ optional string product_id = 1;
}
optional BrilloDeviceData brillo = 21;
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 2437b56..1d87be5 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -136,7 +136,7 @@
profile_proto->set_channel(profile_.channel);
metrics::SystemProfileProto_BrilloDeviceData* device_data =
profile_proto->mutable_brillo();
- device_data->set_build_target_id(profile_.product_id);
+ device_data->set_product_id(profile_.product_id);
return true;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 10635d3..bd4d156 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -296,6 +296,7 @@
mkdir /data/local 0751 root root
mkdir /data/misc/media 0700 media media
mkdir /data/misc/boottrace 0771 system shell
+ mkdir /data/misc/update_engine 0700 root root
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp