Merge "Update sanitize property format"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index efa18c2..49d2936 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1135,6 +1135,13 @@
/* we don't even need to send a reply */
return 0;
}
+
+ if (!strcmp(service, "reconnect")) {
+ if (s->transport != nullptr) {
+ kick_transport(s->transport);
+ }
+ return SendOkay(reply_fd, "done");
+ }
#endif // ADB_HOST
int ret = handle_forward_request(service, type, serial, reply_fd);
diff --git a/adb/adb.h b/adb/adb.h
index 59644d4..ea20800 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -50,7 +50,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 35
+#define ADB_SERVER_VERSION 36
class atransport;
struct usb_handle;
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index d29c08e..a27dd47 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -158,7 +158,8 @@
}
}
- if (memcmp(&service[0],"host",4) != 0 && switch_socket_transport(fd, error)) {
+ if ((memcmp(&service[0],"host",4) != 0 || service == "host:reconnect") &&
+ switch_socket_transport(fd, error)) {
return -1;
}
@@ -168,9 +169,11 @@
return -1;
}
- if (!adb_status(fd, error)) {
- adb_close(fd);
- return -1;
+ if (service != "reconnect") {
+ if (!adb_status(fd, error)) {
+ adb_close(fd);
+ return -1;
+ }
}
D("_adb_connect: return fd %d", fd);
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 21a82e8..611b239 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -37,7 +37,13 @@
// fds far from the range that open() returns. But all of that might defeat the
// purpose of the tests.
-TEST(io, ReadFdExactly_whole) {
+#if defined(_WIN32)
+#define POSIX_TEST(x,y) TEST(DISABLED_ ## x,y)
+#else
+#define POSIX_TEST TEST
+#endif
+
+POSIX_TEST(io, ReadFdExactly_whole) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -51,7 +57,7 @@
EXPECT_STREQ(expected, buf);
}
-TEST(io, ReadFdExactly_eof) {
+POSIX_TEST(io, ReadFdExactly_eof) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -65,7 +71,7 @@
EXPECT_EQ(0, errno) << strerror(errno);
}
-TEST(io, ReadFdExactly_partial) {
+POSIX_TEST(io, ReadFdExactly_partial) {
const char input[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -82,7 +88,7 @@
EXPECT_STREQ(expected.c_str(), buf);
}
-TEST(io, WriteFdExactly_whole) {
+POSIX_TEST(io, WriteFdExactly_whole) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -97,7 +103,7 @@
EXPECT_STREQ(expected, s.c_str());
}
-TEST(io, WriteFdExactly_partial) {
+POSIX_TEST(io, WriteFdExactly_partial) {
const char buf[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -114,7 +120,7 @@
EXPECT_EQ(expected, s);
}
-TEST(io, WriteFdExactly_ENOSPC) {
+POSIX_TEST(io, WriteFdExactly_ENOSPC) {
int fd = open("/dev/full", O_WRONLY);
ASSERT_NE(-1, fd);
@@ -123,7 +129,7 @@
ASSERT_EQ(ENOSPC, errno);
}
-TEST(io, WriteFdExactly_string) {
+POSIX_TEST(io, WriteFdExactly_string) {
const char str[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -137,7 +143,7 @@
EXPECT_STREQ(str, s.c_str());
}
-TEST(io, WriteFdFmt) {
+POSIX_TEST(io, WriteFdFmt) {
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index f5d13c3..d8b1654 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -239,6 +239,9 @@
" - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n"
" is updated.\n"
"\n"
+ "internal debugging:\n"
+ " adb reconnect Kick current connection from host side and make it reconnect.\n"
+ " adb reconnect device Kick current connection from device side and make it reconnect.\n"
"environment variables:\n"
" ADB_TRACE - Print debug information. A comma separated list of the following values\n"
" 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
@@ -1895,6 +1898,14 @@
}
}
return 0;
+ } else if (!strcmp(argv[0], "reconnect")) {
+ if (argc == 1) {
+ return adb_query_command("host:reconnect");
+ } else if (argc == 2 && !strcmp(argv[1], "device")) {
+ std::string err;
+ adb_connect("reconnect", &err);
+ return 0;
+ }
}
usage();
diff --git a/adb/services.cpp b/adb/services.cpp
index 67e8e41..3b212e9 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -184,6 +184,13 @@
adb_close(fd);
}
+static void reconnect_service(int fd, void* arg) {
+ WriteFdExactly(fd, "done");
+ adb_close(fd);
+ atransport* t = static_cast<atransport*>(arg);
+ kick_transport(t);
+}
+
int reverse_service(const char* command) {
int s[2];
if (adb_socketpair(s)) {
@@ -345,6 +352,8 @@
ret = create_service_thread(set_verity_enabled_state_service, (void*)0);
} else if(!strncmp(name, "enable-verity:", 15)) {
ret = create_service_thread(set_verity_enabled_state_service, (void*)1);
+ } else if (!strcmp(name, "reconnect")) {
+ ret = create_service_thread(reconnect_service, const_cast<atransport*>(transport));
#endif
}
if (ret >= 0) {
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 78efea8..f0c334e 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -215,3 +215,32 @@
// Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP.
EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP);
}
+
+TEST_F(sysdeps_poll, fd_count) {
+ // https://code.google.com/p/android/issues/detail?id=12141
+ static constexpr int num_sockets = 512;
+ std::vector<int> sockets;
+ std::vector<adb_pollfd> pfds;
+ sockets.resize(num_sockets * 2);
+ for (int32_t i = 0; i < num_sockets; ++i) {
+ ASSERT_EQ(0, adb_socketpair(&sockets[i * 2])) << strerror(errno);
+ ASSERT_TRUE(WriteFdExactly(sockets[i * 2], &i, sizeof(i)));
+ adb_pollfd pfd;
+ pfd.events = POLLIN;
+ pfd.fd = sockets[i * 2 + 1];
+ pfds.push_back(pfd);
+ }
+
+ ASSERT_EQ(num_sockets, adb_poll(pfds.data(), pfds.size(), 0));
+ for (int i = 0; i < num_sockets; ++i) {
+ ASSERT_NE(0, pfds[i].revents & POLLIN);
+
+ int32_t buf[2] = { -1, -1 };
+ ASSERT_EQ(adb_read(pfds[i].fd, buf, sizeof(buf)), static_cast<ssize_t>(sizeof(int32_t)));
+ ASSERT_EQ(i, buf[0]);
+ }
+
+ for (int fd : sockets) {
+ adb_close(fd);
+ }
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index a2f34fb..bc09fdc 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -191,7 +191,7 @@
#define fh_socket u.socket
#define WIN32_FH_BASE 2048
-#define WIN32_MAX_FHS 128
+#define WIN32_MAX_FHS 2048
static adb_mutex_t _win32_lock;
static FHRec _win32_fhs[ WIN32_MAX_FHS ];
diff --git a/adb/transport.cpp b/adb/transport.cpp
index e3340af..55082a5 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -295,17 +295,13 @@
transport_unref(t);
}
-static void kick_transport_locked(atransport* t) {
- CHECK(t != nullptr);
- if (!t->kicked) {
- t->kicked = true;
- t->kick(t);
- }
-}
-
void kick_transport(atransport* t) {
adb_mutex_lock(&transport_lock);
- kick_transport_locked(t);
+ // As kick_transport() can be called from threads without guarantee that t is valid,
+ // check if the transport is in transport_list first.
+ if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
+ t->Kick();
+ }
adb_mutex_unlock(&transport_lock);
}
@@ -617,7 +613,6 @@
t->ref_count--;
if (t->ref_count == 0) {
D("transport: %s unref (kicking and closing)", t->serial);
- kick_transport_locked(t);
t->close(t);
remove_transport(t);
} else {
@@ -744,6 +739,14 @@
return result;
}
+void atransport::Kick() {
+ if (!kicked_) {
+ kicked_ = true;
+ CHECK(kick_func_ != nullptr);
+ kick_func_(this);
+ }
+}
+
const std::string atransport::connection_state_name() const {
switch (connection_state) {
case kCsOffline: return "offline";
@@ -924,10 +927,7 @@
void close_usb_devices() {
adb_mutex_lock(&transport_lock);
for (const auto& t : transport_list) {
- if (!t->kicked) {
- t->kicked = 1;
- t->kick(t);
- }
+ t->Kick();
}
adb_mutex_unlock(&transport_lock);
}
@@ -998,7 +998,7 @@
// the read_transport thread will notify the main thread to make this transport
// offline. Then the main thread will notify the write_transport thread to exit.
// Finally, this transport will be closed and freed in the main thread.
- kick_transport_locked(t);
+ t->Kick();
}
}
adb_mutex_unlock(&transport_lock);
diff --git a/adb/transport.h b/adb/transport.h
index 5857249..35d7b50 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -60,7 +60,13 @@
int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
void (*close)(atransport* t) = nullptr;
- void (*kick)(atransport* t) = nullptr;
+ void SetKickFunction(void (*kick_func)(atransport*)) {
+ kick_func_ = kick_func;
+ }
+ bool IsKicked() {
+ return kicked_;
+ }
+ void Kick();
int fd = -1;
int transport_socket = -1;
@@ -82,7 +88,6 @@
char* device = nullptr;
char* devpath = nullptr;
int adb_port = -1; // Use for emulators (local transport)
- bool kicked = false;
void* key = nullptr;
unsigned char token[TOKEN_SIZE] = {};
@@ -123,6 +128,9 @@
bool MatchesTarget(const std::string& target) const;
private:
+ bool kicked_ = false;
+ void (*kick_func_)(atransport*) = nullptr;
+
// A set of features transmitted in the banner with the initial connection.
// This is stored in the banner as 'features=feature0,feature1,etc'.
FeatureSet features_;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index f6c9df4..4121f47 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -388,7 +388,7 @@
{
int fail = 0;
- t->kick = remote_kick;
+ t->SetKickFunction(remote_kick);
t->close = remote_close;
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 2028ecc..a6db07a 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,47 +20,6 @@
#include "adb.h"
-class TestTransport : public atransport {
-public:
- bool operator==(const atransport& rhs) const {
- EXPECT_EQ(read_from_remote, rhs.read_from_remote);
- EXPECT_EQ(write_to_remote, rhs.write_to_remote);
- EXPECT_EQ(close, rhs.close);
- EXPECT_EQ(kick, rhs.kick);
-
- EXPECT_EQ(fd, rhs.fd);
- EXPECT_EQ(transport_socket, rhs.transport_socket);
-
- EXPECT_EQ(
- 0, memcmp(&transport_fde, &rhs.transport_fde, sizeof(fdevent)));
-
- EXPECT_EQ(ref_count, rhs.ref_count);
- EXPECT_EQ(sync_token, rhs.sync_token);
- EXPECT_EQ(connection_state, rhs.connection_state);
- EXPECT_EQ(online, rhs.online);
- EXPECT_EQ(type, rhs.type);
-
- EXPECT_EQ(usb, rhs.usb);
- EXPECT_EQ(sfd, rhs.sfd);
-
- EXPECT_EQ(serial, rhs.serial);
- EXPECT_EQ(product, rhs.product);
- EXPECT_EQ(model, rhs.model);
- EXPECT_EQ(device, rhs.device);
- EXPECT_EQ(devpath, rhs.devpath);
- EXPECT_EQ(adb_port, rhs.adb_port);
- EXPECT_EQ(kicked, rhs.kicked);
-
- EXPECT_EQ(key, rhs.key);
- EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
- EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
-
- EXPECT_EQ(features(), rhs.features());
-
- return true;
- }
-};
-
class TransportSetup {
public:
TransportSetup() {
@@ -83,35 +42,19 @@
static TransportSetup g_TransportSetup;
TEST(transport, kick_transport) {
- TestTransport t;
-
+ atransport t;
+ static size_t kick_count;
+ kick_count = 0;
// Mutate some member so we can test that the function is run.
- t.kick = [](atransport* trans) { trans->fd = 42; };
-
- TestTransport expected;
- expected.kick = t.kick;
- expected.fd = 42;
- expected.kicked = 1;
-
- kick_transport(&t);
- ASSERT_EQ(42, t.fd);
- ASSERT_EQ(1, t.kicked);
- ASSERT_EQ(expected, t);
-}
-
-TEST(transport, kick_transport_already_kicked) {
- // Ensure that the transport is not modified if the transport has already been
- // kicked.
- TestTransport t;
- t.kicked = 1;
- t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
-
- TestTransport expected;
- expected.kicked = 1;
- expected.kick = t.kick;
-
- kick_transport(&t);
- ASSERT_EQ(expected, t);
+ t.SetKickFunction([](atransport* trans) { kick_count++; });
+ ASSERT_FALSE(t.IsKicked());
+ t.Kick();
+ ASSERT_TRUE(t.IsKicked());
+ ASSERT_EQ(1u, kick_count);
+ // A transport can only be kicked once.
+ t.Kick();
+ ASSERT_TRUE(t.IsKicked());
+ ASSERT_EQ(1u, kick_count);
}
static void DisconnectFunc(void* arg, atransport*) {
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 263f9e7..d05d928 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -84,7 +84,7 @@
{
D("transport: usb");
t->close = remote_close;
- t->kick = remote_kick;
+ t->SetKickFunction(remote_kick);
t->read_from_remote = remote_read;
t->write_to_remote = remote_write;
t->sync_token = 1;
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 54d4c6c..ddde454 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -29,86 +29,96 @@
#include <inttypes.h>
#include <stdio.h>
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <vector>
+
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include "adb.h"
#include "transport.h"
-#define DBG D
-
-// There's no strerror equivalent for the errors returned by IOKit.
-// https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Handling_Errors/AH_Handling_Errors.html
-// Search the web for "IOReturn.h" to find a complete up to date list.
-
-static IONotificationPortRef notificationPort = 0;
-static io_iterator_t notificationIterator;
-
struct usb_handle
{
UInt8 bulkIn;
UInt8 bulkOut;
IOUSBInterfaceInterface190** interface;
- io_object_t usbNotification;
unsigned int zero_mask;
+
+ // For garbage collecting disconnected devices.
+ bool mark;
+ std::string devpath;
+ std::atomic<bool> dead;
+
+ usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr),
+ zero_mask(0), mark(false), dead(false) {
+ }
};
-static CFRunLoopRef currentRunLoop = 0;
-static pthread_mutex_t start_lock;
-static pthread_cond_t start_cond;
+static std::atomic<bool> usb_inited_flag;
+static auto& g_usb_handles_mutex = *new std::mutex();
+static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
-static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
-static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
- natural_t messageType,
- void *messageArgument);
-static usb_handle* CheckInterface(IOUSBInterfaceInterface190 **iface,
- UInt16 vendor, UInt16 product);
-
-static int
-InitUSB()
-{
- CFMutableDictionaryRef matchingDict;
- CFRunLoopSourceRef runLoopSource;
-
- //* To set up asynchronous notifications, create a notification port and
- //* add its run loop event source to the program's run loop
- notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
- runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-
- //* Create our matching dictionary to find the Android device's
- //* adb interface
- //* IOServiceAddMatchingNotification consumes the reference, so we do
- //* not need to release this
- matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
-
- if (!matchingDict) {
- LOG(ERROR) << "Couldn't create USB matching dictionary.";
- return -1;
+static bool IsKnownDevice(const std::string& devpath) {
+ std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+ for (auto& usb : g_usb_handles) {
+ if (usb->devpath == devpath) {
+ // Set mark flag to indicate this device is still alive.
+ usb->mark = true;
+ return true;
+ }
}
+ return false;
+}
- //* We have to get notifications for all potential candidates and test them
- //* at connection time because the matching rules don't allow for a
- //* USB interface class of 0xff for class+subclass+protocol matches
- //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
- IOServiceAddMatchingNotification(
- notificationPort,
- kIOFirstMatchNotification,
- matchingDict,
- AndroidInterfaceAdded,
- NULL,
- ¬ificationIterator);
+static void usb_kick_locked(usb_handle* handle);
- //* Iterate over set of matching interfaces to access already-present
- //* devices and to arm the notification
- AndroidInterfaceAdded(NULL, notificationIterator);
+static void KickDisconnectedDevices() {
+ std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+ for (auto& usb : g_usb_handles) {
+ if (!usb->mark) {
+ usb_kick_locked(usb.get());
+ } else {
+ usb->mark = false;
+ }
+ }
+}
- return 0;
+static void AddDevice(std::unique_ptr<usb_handle> handle) {
+ handle->mark = true;
+ std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+ g_usb_handles.push_back(std::move(handle));
+}
+
+static void AndroidInterfaceAdded(io_iterator_t iterator);
+static std::unique_ptr<usb_handle> CheckInterface(IOUSBInterfaceInterface190 **iface,
+ UInt16 vendor, UInt16 product);
+
+static bool FindUSBDevices() {
+ // Create the matching dictionary to find the Android device's adb interface.
+ CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
+ if (!matchingDict) {
+ LOG(ERROR) << "couldn't create USB matching dictionary";
+ return false;
+ }
+ // Create an iterator for all I/O Registry objects that match the dictionary.
+ io_iterator_t iter = 0;
+ kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
+ if (kr != KERN_SUCCESS) {
+ LOG(ERROR) << "failed to get matching services";
+ return false;
+ }
+ // Iterate over all matching objects.
+ AndroidInterfaceAdded(iter);
+ IOObjectRelease(iter);
+ return true;
}
static void
-AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
+AndroidInterfaceAdded(io_iterator_t iterator)
{
kern_return_t kr;
io_service_t usbDevice;
@@ -124,8 +134,7 @@
UInt16 product;
UInt8 serialIndex;
char serial[256];
- char devpathBuf[64];
- char *devpath = NULL;
+ std::string devpath;
while ((usbInterface = IOIteratorNext(iterator))) {
//* Create an intermediate interface plugin
@@ -199,9 +208,11 @@
kr = (*dev)->GetDeviceVendor(dev, &vendor);
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->GetLocationID(dev, &locationId);
- if (kr == 0) {
- snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", locationId);
- devpath = devpathBuf;
+ if (kr == KERN_SUCCESS) {
+ devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
+ if (IsKnownDevice(devpath)) {
+ continue;
+ }
}
kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
@@ -256,49 +267,29 @@
(*dev)->Release(dev);
- LOG(INFO) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
+ VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
vendor, product, serial);
-
- usb_handle* handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
- vendor, product);
- if (handle == NULL) {
- LOG(ERROR) << "Could not find device interface";
+ if (devpath.empty()) {
+ devpath = serial;
+ }
+ if (IsKnownDevice(devpath)) {
+ (*iface)->USBInterfaceClose(iface);
(*iface)->Release(iface);
continue;
}
- LOG(DEBUG) << "AndroidDeviceAdded calling register_usb_transport";
- register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
-
- // Register for an interest notification of this device being removed.
- // Pass the reference to our private data as the refCon for the
- // notification.
- kr = IOServiceAddInterestNotification(notificationPort,
- usbInterface,
- kIOGeneralInterest,
- AndroidInterfaceNotify,
- handle,
- &handle->usbNotification);
-
- if (kIOReturnSuccess != kr) {
- LOG(ERROR) << "Unable to create interest notification (" << std::hex << kr << ")";
+ std::unique_ptr<usb_handle> handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
+ vendor, product);
+ if (handle == nullptr) {
+ LOG(ERROR) << "Could not find device interface";
+ (*iface)->Release(iface);
+ continue;
}
- }
-}
-
-static void
-AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
-{
- usb_handle *handle = (usb_handle *)refCon;
-
- if (messageType == kIOMessageServiceIsTerminated) {
- if (!handle) {
- LOG(ERROR) << "NULL handle";
- return;
- }
- LOG(DEBUG) << "AndroidInterfaceNotify";
- IOObjectRelease(handle->usbNotification);
- usb_kick(handle);
+ handle->devpath = devpath;
+ usb_handle* handle_p = handle.get();
+ VLOG(USB) << "Add usb device " << serial;
+ AddDevice(std::move(handle));
+ register_usb_transport(handle_p, serial, devpath.c_str(), 1);
}
}
@@ -316,10 +307,10 @@
//* TODO: simplify this further since we only register to get ADB interface
//* subclass+protocol events
-static usb_handle*
+static std::unique_ptr<usb_handle>
CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
{
- usb_handle* handle;
+ std::unique_ptr<usb_handle> handle;
IOReturn kr;
UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
UInt8 endpoint;
@@ -353,8 +344,10 @@
goto err_bad_adb_interface;
}
- handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
- if (handle == nullptr) goto err_bad_adb_interface;
+ handle.reset(new usb_handle);
+ if (handle == nullptr) {
+ goto err_bad_adb_interface;
+ }
//* Iterate over the endpoints for this interface and find the first
//* bulk in/out pipes available. These will be our read/write pipes.
@@ -392,39 +385,37 @@
return handle;
err_get_pipe_props:
- free(handle);
err_bad_adb_interface:
err_get_interface_class:
err_get_num_ep:
(*interface)->USBInterfaceClose(interface);
- return NULL;
+ return nullptr;
}
+std::mutex& operate_device_lock = *new std::mutex();
+
static void RunLoopThread(void* unused) {
adb_thread_setname("RunLoop");
- InitUSB();
- currentRunLoop = CFRunLoopGetCurrent();
-
- // Signal the parent that we are running
- adb_mutex_lock(&start_lock);
- adb_cond_signal(&start_cond);
- adb_mutex_unlock(&start_lock);
-
- CFRunLoopRun();
- currentRunLoop = 0;
-
- IOObjectRelease(notificationIterator);
- IONotificationPortDestroy(notificationPort);
-
- LOG(DEBUG) << "RunLoopThread done";
+ VLOG(USB) << "RunLoopThread started";
+ while (true) {
+ {
+ std::lock_guard<std::mutex> lock_guard(operate_device_lock);
+ FindUSBDevices();
+ KickDisconnectedDevices();
+ }
+ // Signal the parent that we are running
+ usb_inited_flag = true;
+ adb_sleep_ms(1000);
+ }
+ VLOG(USB) << "RunLoopThread done";
}
static void usb_cleanup() {
- LOG(DEBUG) << "usb_cleanup";
+ VLOG(USB) << "usb_cleanup";
+ // Wait until usb operations in RunLoopThread finish, and prevent further operations.
+ operate_device_lock.lock();
close_usb_devices();
- if (currentRunLoop)
- CFRunLoopStop(currentRunLoop);
}
void usb_init() {
@@ -432,20 +423,16 @@
if (!initialized) {
atexit(usb_cleanup);
- adb_mutex_init(&start_lock, NULL);
- adb_cond_init(&start_cond, NULL);
+ usb_inited_flag = false;
if (!adb_thread_create(RunLoopThread, nullptr)) {
fatal_errno("cannot create RunLoop thread");
}
// Wait for initialization to finish
- adb_mutex_lock(&start_lock);
- adb_cond_wait(&start_cond, &start_lock);
- adb_mutex_unlock(&start_lock);
-
- adb_mutex_destroy(&start_lock);
- adb_cond_destroy(&start_cond);
+ while (!usb_inited_flag) {
+ adb_sleep_ms(100);
+ }
initialized = true;
}
@@ -458,7 +445,7 @@
if (!len)
return 0;
- if (!handle)
+ if (!handle || handle->dead)
return -1;
if (NULL == handle->interface) {
@@ -499,7 +486,7 @@
return 0;
}
- if (!handle) {
+ if (!handle || handle->dead) {
return -1;
}
@@ -532,20 +519,33 @@
int usb_close(usb_handle *handle)
{
+ std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+ for (auto it = g_usb_handles.begin(); it != g_usb_handles.end(); ++it) {
+ if ((*it).get() == handle) {
+ g_usb_handles.erase(it);
+ break;
+ }
+ }
return 0;
}
-void usb_kick(usb_handle *handle)
+static void usb_kick_locked(usb_handle *handle)
{
LOG(INFO) << "Kicking handle";
/* release the interface */
if (!handle)
return;
- if (handle->interface)
+ if (!handle->dead)
{
+ handle->dead = true;
(*handle->interface)->USBInterfaceClose(handle->interface);
(*handle->interface)->Release(handle->interface);
- handle->interface = 0;
}
}
+
+void usb_kick(usb_handle *handle) {
+ // Use the lock to avoid multiple thread kicking the device at the same time.
+ std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+ usb_kick_locked(handle);
+}
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 913a9a0..299ec35 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -123,8 +123,11 @@
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-#define LIKELY(x) __builtin_expect((x), true)
-#define UNLIKELY(x) __builtin_expect((x), false)
+// Changing this definition will cause you a lot of pain. A majority of
+// vendor code defines LIKELY and UNLIKELY this way, and includes
+// this header through an indirect path.
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
#define WARN_UNUSED __attribute__((warn_unused_result))
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 8bc49ce..ab41c55 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -19,7 +19,10 @@
#include <unistd.h>
-#include <android-base/macros.h>
+// DO NOT INCLUDE OTHER LIBBASE HEADERS!
+// This file gets used in libbinder, and libbinder is used everywhere.
+// Including other headers from libbase frequently results in inclusion of
+// android-base/macros.h, which causes macro collisions.
// Container for a file descriptor that automatically closes the descriptor as
// it goes out of scope.
@@ -75,7 +78,8 @@
private:
int value_;
- DISALLOW_COPY_AND_ASSIGN(unique_fd);
+ unique_fd(const unique_fd&);
+ void operator=(const unique_fd&);
};
} // namespace base
diff --git a/healthd/Android.mk b/healthd/Android.mk
index d866887..127f39e 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -9,6 +9,7 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := libbinder
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libbinder
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index ba86632..19551dc 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <inttypes.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
@@ -46,8 +47,8 @@
}
bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
- unsigned long int start;
- unsigned long int end;
+ uint64_t start;
+ uint64_t end;
char permissions[5];
int name_pos;
@@ -56,14 +57,14 @@
// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
- if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
+ if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c %n",
&start, &end, permissions, &name_pos) != 3) {
#else
// Linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
- if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d %n",
+ if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
&start, &end, permissions, &name_pos) != 3) {
#endif
return false;
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index 09a721d..b4dc48d 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -33,7 +33,7 @@
#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
#define PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
-static bool ReadData(int fd, unsigned long place, uint64_t *data) {
+static bool ReadData(int fd, off_t place, uint64_t *data) {
if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
return false;
}
@@ -71,12 +71,13 @@
total_pss = 0;
break;
}
- for (size_t page = start/pagesize; page < end/pagesize; page++) {
+ for (off_t page = static_cast<off_t>(start/pagesize);
+ page < static_cast<off_t>(end/pagesize); page++) {
uint64_t data;
if (ReadData(pagemap_fd, page, &data)) {
if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
uint64_t count;
- if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
+ if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
total_pss += (count >= 1) ? pagesize / count : 0;
}
}
diff --git a/libcrypto_utils/android_pubkey.c b/libcrypto_utils/android_pubkey.c
index 9cd9aab..3052e52 100644
--- a/libcrypto_utils/android_pubkey.c
+++ b/libcrypto_utils/android_pubkey.c
@@ -20,6 +20,8 @@
#include <stdlib.h>
#include <string.h>
+#include <openssl/bn.h>
+
// Better safe than sorry.
#if (ANDROID_PUBKEY_MODULUS_SIZE % 4) != 0
#error RSA modulus size must be multiple of the word size!
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 6bba3a7..7bb8223 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -306,7 +306,7 @@
char thread_name[255];
int fd;
- sprintf(statfile, "/proc/%d/stat", tid);
+ snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid);
memset(thread_name, 0, sizeof(thread_name));
fd = open(statfile, O_RDONLY);
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 79a5670..bd8d5af 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -63,7 +63,6 @@
static void refresh_cache(struct cache *cache, const char *key)
{
- uint32_t serial;
char buf[PROP_VALUE_MAX];
if (!cache->pinfo) {
@@ -71,13 +70,8 @@
if (!cache->pinfo) {
return;
}
- cache->serial = -1;
}
- serial = __system_property_serial(cache->pinfo);
- if (serial == cache->serial) {
- return;
- }
- cache->serial = serial;
+ cache->serial = __system_property_serial(cache->pinfo);
__system_property_read(cache->pinfo, 0, buf);
switch(buf[0]) {
case 't': case 'T':
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 456f8b3..1a7d4aa 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1338,7 +1338,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, levels[j].level));
}
@@ -1347,7 +1347,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, levels[j].level));
}
@@ -1379,7 +1379,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1388,7 +1388,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1408,7 +1408,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1417,7 +1417,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1439,7 +1439,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1448,7 +1448,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1468,7 +1468,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1477,7 +1477,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1513,7 +1513,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1522,7 +1522,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1542,7 +1542,7 @@
fprintf(stderr, "\n");
}
EXPECT_FALSE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_FALSE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
@@ -1551,7 +1551,7 @@
fprintf(stderr, "\n");
}
EXPECT_TRUE(android_log_is_loggable);
- for(size_t k = 1000; k; --k) {
+ for(size_t k = 10; k; --k) {
EXPECT_TRUE(__android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index cf0e0d2..70d1dd4 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -2,10 +2,10 @@
# all exec/services are called with umask(077), so no gain beyond 0700
mkdir /data/misc/logd 0700 logd log
# logd for write to /data/misc/logd, log group for read from pstore (-L)
- exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n 256
+ exec - logd log -- /system/bin/logcat -L -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
start logcatd
-service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n 256
+service logcatd /system/bin/logcat -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
class late_start
disabled
# logd for write to /data/misc/logd, log group for read from log daemon
diff --git a/logcat/logpersist b/logcat/logpersist
index 8762ff1..e448456 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -1,5 +1,5 @@
#! /system/bin/sh
-# logpersist cat start and stop handlers
+# logpersist cat, start and stop handlers
progname="${0##*/}"
case `getprop ro.debuggable` in
1) ;;
@@ -7,36 +7,134 @@
exit 1
;;
esac
+
data=/data/misc/logd
property=persist.logd.logpersistd
service=logcatd
-if [ X"${1}" = X"-h" -o X"${1}" = X"--help" ]; then
- echo "${progname%.*}.cat - dump current ${service%d} logs"
- echo "${progname%.*}.start - start ${service} service"
- echo "${progname%.*}.stop [--clear] - stop ${service} service"
- exit 0
+size_default=256
+buffer_default=all
+args="${@}"
+
+size=${size_default}
+buffer=${buffer_default}
+clear=false
+while [ ${#} -gt 0 ]; do
+ case ${1} in
+ -c|--clear) clear=true ;;
+ --size=*) size="${1#--size=}" ;;
+ --rotate-count=*) size="${1#--rotate-count=}" ;;
+ -n|--size|--rotate-count) size="${2}" ; shift ;;
+ --buffer=*) buffer="${1#--buffer=}" ;;
+ -b|--buffer) buffer="${2}" ; shift ;;
+ -h|--help|*)
+ LEAD_SPACE_="`echo ${progname%.*} | tr '[ -~]' ' '`"
+ echo "${progname%.*}.cat - dump current ${service%d} logs"
+ echo "${progname%.*}.start [--size=<size_in_kb>] [--buffer=<buffers>] [--clear]"
+ echo "${LEAD_SPACE_} - start ${service} service"
+ echo "${progname%.*}.stop [--clear] - stop ${service} service"
+ case ${1} in
+ -h|--help) exit 0 ;;
+ *) echo ERROR: bad argument ${@} >&2 ; exit 1 ;;
+ esac
+ ;;
+ esac
+ shift
+done
+
+if [ -z "${size}" -o "${size_default}" = "${size}" ]; then
+ unset size
fi
+if [ -n "${size}" ] &&
+ ! ( [ 0 -lt "${size}" ] && [ 2048 -ge "${size}" ] ) >/dev/null 2>&1; then
+ echo ERROR: Invalid --size ${size} >&2
+ exit 1
+fi
+if [ -z "${buffer}" -o "${buffer_default}" = "${buffer}" ]; then
+ unset buffer
+fi
+if [ -n "${buffer}" ] && ! logcat -b ${buffer} -g >/dev/null 2>&1; then
+ echo ERROR: Invalid --buffer ${buffer} >&2
+ exit 1
+fi
+
case ${progname} in
*.cat)
- su 1036 ls "${data}" |
+ if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
+ echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2
+ fi
+ su logd ls "${data}" |
tr -d '\r' |
sort -ru |
sed "s#^#${data}/#" |
- su 1036 xargs cat
+ su logd xargs cat
;;
*.start)
- su 0 setprop ${property} ${service}
+ current_buffer="`getprop ${property}.buffer`"
+ current_size="`getprop ${property}.size`"
+ if [ "${service}" = "`getprop ${property}`" ]; then
+ if [ "true" = "${clear}" ]; then
+ su root stop ${service}
+ su root setprop ${property} ""
+ # 20ms done, guarantees content stop before rm
+ sleep 1
+ elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
+ echo "ERROR: Changing existing collection parameters from" >&2
+ if [ "${buffer}" != "${current_buffer}" ]; then
+ a=${current_buffer}
+ b=${buffer}
+ if [ -z "${a}" ]; then a="${default_buffer}"; fi
+ if [ -z "${b}" ]; then b="${default_buffer}"; fi
+ echo " --buffer ${a} to ${b}" >&2
+ fi
+ if [ "${size}" != "${current_size}" ]; then
+ a=${current_size}
+ b=${size}
+ if [ -z "${a}" ]; then a="${default_size}"; fi
+ if [ -z "${b}" ]; then b="${default_size}"; fi
+ echo " --size ${a} to ${b}" >&2
+ fi
+ echo " Are you sure you want to do this?" >&2
+ echo " Suggest add --clear to erase data and restart with new settings." >&2
+ echo " To blindly override and retain data, ${progname%.*}.stop first." >&2
+ exit 1
+ fi
+ fi
+ if [ "true" = "${clear}" ]; then
+ su logd,misc rm -rf "${data}"
+ fi
+ if [ -n "${buffer}${current_buffer}" ]; then
+ su root setprop ${property}.buffer "${buffer}"
+ fi
+ if [ -n "${size}${current_size}" ]; then
+ su root setprop ${property}.size "${size}"
+ fi
+ # ${service}.rc does the heavy lifting with the following trigger
+ su root setprop ${property} ${service}
getprop ${property}
+ # 20ms done, to permit process feedback check
sleep 1
+ # also generate an error return code if not found running, bonus
ps -t | grep "${data##*/}.*${service%d}"
;;
*.stop)
- su 0 stop ${service}
- su 0 setprop ${property} ""
- [ X"${1}" != X"-c" -a X"${1}" != X"--clear" ] ||
- ( sleep 1 ; su 1036,9998 rm -rf "${data}" )
+ if [ -n "${size}${buffer}" ]; then
+ echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
+ fi
+ su root stop ${service}
+ su root setprop ${property} ""
+ if [ -n "`getprop ${property}.buffer`" ]; then
+ su root setprop ${property}.buffer ""
+ fi
+ if [ -n "`getprop ${property}.size`" ]; then
+ su root setprop ${property}.size ""
+ fi
+ if [ "true" = "${clear}" ]; then
+ # 20ms done, guarantees content stop before rm
+ sleep 1
+ su logd,misc rm -rf "${data}"
+ fi
;;
*)
- echo "Unexpected command ${0##*/} ${@}" >&2
+ echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
exit 1
esac
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 8b32418..85f9415 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -32,7 +32,6 @@
OUR_TOOLS := \
getevent \
- iftop \
ioctl \
log \
nandread \
diff --git a/toolbox/iftop.c b/toolbox/iftop.c
deleted file mode 100644
index 800c0f0..0000000
--- a/toolbox/iftop.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, 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 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 <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-
-#define PROC_NET_DEV "/proc/net/dev"
-
-#define MAX_IF 8 /* max interfaces we can handle */
-
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-
-#define _STR(s) #s
-#define STR(s) _STR(s)
-
-struct if_stats {
- char name[IFNAMSIZ];
-
- unsigned int mtu;
-
- unsigned int rx_bytes;
- unsigned int rx_packets;
- unsigned int rx_errors;
- unsigned int rx_dropped;
-
- unsigned int tx_bytes;
- unsigned int tx_packets;
- unsigned int tx_errors;
- unsigned int tx_dropped;
-};
-
-static int get_mtu(const char *if_name)
-{
- struct ifreq ifr;
- int s, ret;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&ifr, 0, sizeof(struct ifreq));
- ifr.ifr_addr.sa_family = AF_INET;
- strcpy(ifr.ifr_name, if_name);
-
- ret = ioctl(s, SIOCGIFMTU, &ifr);
- if (ret < 0) {
- perror("ioctl");
- exit(EXIT_FAILURE);
- }
-
- ret = close(s);
- if (ret < 0) {
- perror("close");
- exit(EXIT_FAILURE);
- }
-
- return ifr.ifr_mtu;
-}
-
-static int get_interfaces(struct if_stats *ifs)
-{
- char buf[PAGE_SIZE];
- char *p;
- int ret, nr, fd;
-
- fd = open(PROC_NET_DEV, O_RDONLY);
- if (fd < 0) {
- perror("open");
- exit(EXIT_FAILURE);
- }
-
- ret = read(fd, buf, sizeof(buf) - 1);
- if (ret < 0) {
- perror("read");
- exit(EXIT_FAILURE);
- } else if (!ret) {
- fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
- exit(EXIT_FAILURE);
- }
- buf[ret] = '\0';
-
- /* skip down to the third line */
- p = strchr(buf, '\n');
- if (!p) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
- p = strchr(p + 1, '\n');
- if (!p) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
- p += 1;
-
- /*
- * Key:
- * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
- * (Tx) bytes packets errs drop fifo colls carrier compressed
- */
- for (nr = 0; nr < MAX_IF; nr++) {
- char *c;
-
- ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
- if (ret != 1) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
-
- /*
- * This works around a bug in the proc file where large interface names
- * or Rx byte counts eat the delimiter, breaking sscanf.
- */
- c = strchr(ifs->name, ':');
- if (c)
- *c = '\0';
-
- p = strchr(p, ':') + 1;
-
- ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
- "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
- &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
- &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
- if (ret != 8) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
-
- ifs->mtu = get_mtu(ifs->name);
-
- p = strchr(p, '\n') + 1;
- if (*p == '\0') {
- nr++;
- break;
- }
-
- ifs++;
- }
-
- ret = close(fd);
- if (ret) {
- perror("close");
- exit(EXIT_FAILURE);
- }
-
- return nr;
-}
-
-static void print_header(void)
-{
- printf(" Rx Tx\n");
- printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
- "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
- "packets", "errs", "drpd");
-}
-
-static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
-{
- int i = 0;
-
- while (nr--) {
- if (old->rx_packets || old->tx_packets) {
- printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
- new->name, new->mtu,
- new->rx_bytes - old->rx_bytes,
- new->rx_packets - old->rx_packets,
- new->rx_errors - old->rx_errors,
- new->rx_dropped - old->rx_dropped,
- new->tx_bytes - old->tx_bytes,
- new->tx_packets - old->tx_packets,
- new->tx_errors - old->tx_errors,
- new->tx_dropped - old->tx_dropped);
- i++;
- }
- old++;
- new++;
- }
-
- return i;
-}
-
-static void usage(const char *cmd)
-{
- fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
-}
-
-int iftop_main(int argc, char *argv[])
-{
- struct if_stats ifs[2][MAX_IF];
- int count = 0, header_interval = 22, delay = 1, i;
- unsigned int toggle = 0;
-
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d")) {
- if (i >= argc - 1) {
- fprintf(stderr, "Option -d requires an argument.\n");
- exit(EXIT_FAILURE);
- }
- delay = atoi(argv[i++]);
- if (!delay)
- delay = 1;
- continue;
- }
- if (!strcmp(argv[i], "-r")) {
- if (i >= argc - 1) {
- fprintf(stderr, "Option -r requires an argument.\n");
- exit(EXIT_FAILURE);
- }
- header_interval = atoi(argv[i++]);
- if (header_interval < MAX_IF)
- header_interval = MAX_IF;
- continue;
- }
- if (!strcmp(argv[i], "-h")) {
- usage(argv[0]);
- exit(EXIT_SUCCESS);
- }
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- get_interfaces(ifs[!toggle]);
- if (header_interval)
- print_header();
- while (1) {
- int nr;
-
- sleep(delay);
- nr = get_interfaces(ifs[toggle]);
- if (header_interval && count + nr > header_interval) {
- print_header();
- count = 0;
- }
- count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
- toggle = !toggle;
- }
-
- return 0;
-}