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,
-            &notificationIterator);
+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;
-}