Merge "Added function to explicitly initialize a namespace"
diff --git a/adb/Android.mk b/adb/Android.mk
index 4777883..f1d3bee 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -79,10 +79,12 @@
 
 LIBADB_darwin_SRC_FILES := \
     get_my_path_darwin.cpp \
+    sysdeps_unix.cpp \
     usb_osx.cpp \
 
 LIBADB_linux_SRC_FILES := \
     get_my_path_linux.cpp \
+    sysdeps_unix.cpp \
     usb_linux.cpp \
 
 LIBADB_windows_SRC_FILES := \
@@ -286,7 +288,11 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
-$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
+$(call dist-for-goals,dist_files sdk win_sdk,$(LOCAL_BUILT_MODULE))
+ifdef HOST_CROSS_OS
+# Archive adb.exe for win_sdk build.
+$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
+endif
 
 
 # adbd device daemon
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 26e376c..3333fc6 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -153,7 +153,9 @@
   // - Recursive, so it uses stack space relative to number of directory
   //   components.
 
-  if (directory_exists(path)) {
+  // If path points to a symlink to a directory, that's fine.
+  struct stat sb;
+  if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
     return true;
   }
 
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 3a81ce6..cdbff11 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -188,6 +188,7 @@
         WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
         expect_done_ = true;
         total_bytes_ += data_length;
+        ReportProgress(rpath, data_length, data_length);
         return true;
     }
 
diff --git a/adb/services.cpp b/adb/services.cpp
index 2eef1c2..d5e963b 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -421,6 +421,11 @@
     close_on_exec(fd);
     disable_tcp_nagle(fd);
 
+    // Send a TCP keepalive ping to the device every second so we can detect disconnects.
+    if (!set_tcp_keepalive(fd, 1)) {
+        D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
+    }
+
     int ret = register_socket_transport(fd, serial.c_str(), port, 0);
     if (ret < 0) {
         adb_close(fd);
diff --git a/adb/socket.h b/adb/socket.h
index 4083036..9eb1b19 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -114,4 +114,13 @@
 void connect_to_remote(asocket *s, const char *destination);
 void connect_to_smartsocket(asocket *s);
 
+// Internal functions that are only made available here for testing purposes.
+namespace internal {
+
+#if ADB_HOST
+char* skip_host_serial(const char* service);
+#endif
+
+}  // namespace internal
+
 #endif  // __ADB_SOCKET_H
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 471ca09..5cbef6d 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -270,3 +270,49 @@
 }
 
 #endif  // defined(__linux__)
+
+#if ADB_HOST
+
+// Checks that skip_host_serial(serial) returns a pointer to the part of |serial| which matches
+// |expected|, otherwise logs the failure to gtest.
+void VerifySkipHostSerial(const std::string& serial, const char* expected) {
+    const char* result = internal::skip_host_serial(serial.c_str());
+    if (expected == nullptr) {
+        EXPECT_EQ(nullptr, result);
+    } else {
+        EXPECT_STREQ(expected, result);
+    }
+}
+
+// Check [tcp:|udp:]<serial>[:<port>]:<command> format.
+TEST(socket_test, test_skip_host_serial) {
+    for (const std::string& protocol : {"", "tcp:", "udp:"}) {
+        VerifySkipHostSerial(protocol, nullptr);
+        VerifySkipHostSerial(protocol + "foo", nullptr);
+
+        VerifySkipHostSerial(protocol + "foo:bar", ":bar");
+        VerifySkipHostSerial(protocol + "foo:bar:baz", ":bar:baz");
+
+        VerifySkipHostSerial(protocol + "foo:123:bar", ":bar");
+        VerifySkipHostSerial(protocol + "foo:123:456", ":456");
+        VerifySkipHostSerial(protocol + "foo:123:bar:baz", ":bar:baz");
+
+        // Don't register a port unless it's all numbers and ends with ':'.
+        VerifySkipHostSerial(protocol + "foo:123", ":123");
+        VerifySkipHostSerial(protocol + "foo:123bar:baz", ":123bar:baz");
+    }
+}
+
+// Check <prefix>:<serial>:<command> format.
+TEST(socket_test, test_skip_host_serial_prefix) {
+    for (const std::string& prefix : {"usb:", "product:", "model:", "device:"}) {
+        VerifySkipHostSerial(prefix, nullptr);
+        VerifySkipHostSerial(prefix + "foo", nullptr);
+
+        VerifySkipHostSerial(prefix + "foo:bar", ":bar");
+        VerifySkipHostSerial(prefix + "foo:bar:baz", ":bar:baz");
+        VerifySkipHostSerial(prefix + "foo:123:bar", ":123:bar");
+    }
+}
+
+#endif  // ADB_HOST
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index d8e4e93..c083ee1 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -26,6 +26,8 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <string>
+#include <vector>
 
 #if !ADB_HOST
 #include "cutils/properties.h"
@@ -623,43 +625,43 @@
 
 #if ADB_HOST
 
-#define PREFIX(str) { str, sizeof(str) - 1 }
-static const struct prefix_struct {
-    const char *str;
-    const size_t len;
-} prefixes[] = {
-    PREFIX("usb:"),
-    PREFIX("product:"),
-    PREFIX("model:"),
-    PREFIX("device:"),
-};
-static const int num_prefixes = (sizeof(prefixes) / sizeof(prefixes[0]));
+namespace internal {
 
-/* skip_host_serial return the position in a string
-   skipping over the 'serial' parameter in the ADB protocol,
-   where parameter string may be a host:port string containing
-   the protocol delimiter (colon). */
-static char *skip_host_serial(char *service) {
-    char *first_colon, *serial_end;
-    int i;
+// Returns the position in |service| following the target serial parameter. Serial format can be
+// any of:
+//   * [tcp:|udp:]<serial>[:<port>]:<command>
+//   * <prefix>:<serial>:<command>
+// Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
+//
+// The returned pointer will point to the ':' just before <command>, or nullptr if not found.
+char* skip_host_serial(const char* service) {
+    static const std::vector<std::string>& prefixes =
+        *(new std::vector<std::string>{"usb:", "product:", "model:", "device:"});
 
-    for (i = 0; i < num_prefixes; i++) {
-        if (!strncmp(service, prefixes[i].str, prefixes[i].len))
-            return strchr(service + prefixes[i].len, ':');
+    for (const std::string& prefix : prefixes) {
+        if (!strncmp(service, prefix.c_str(), prefix.length())) {
+            return strchr(service + prefix.length(), ':');
+        }
     }
 
-    first_colon = strchr(service, ':');
+    // For fastboot compatibility, ignore protocol prefixes.
+    if (!strncmp(service, "tcp:", 4) || !strncmp(service, "udp:", 4)) {
+        service += 4;
+    }
+
+    char* first_colon = strchr(service, ':');
     if (!first_colon) {
-        /* No colon in service string. */
-        return NULL;
+        // No colon in service string.
+        return nullptr;
     }
-    serial_end = first_colon;
+
+    char* serial_end = first_colon;
     if (isdigit(serial_end[1])) {
         serial_end++;
-        while ((*serial_end) && isdigit(*serial_end)) {
+        while (*serial_end && isdigit(*serial_end)) {
             serial_end++;
         }
-        if ((*serial_end) != ':') {
+        if (*serial_end != ':') {
             // Something other than numbers was found, reset the end.
             serial_end = first_colon;
         }
@@ -667,6 +669,8 @@
     return serial_end;
 }
 
+}  // namespace internal
+
 #endif // ADB_HOST
 
 static int smart_socket_enqueue(asocket *s, apacket *p)
@@ -725,7 +729,7 @@
         service += strlen("host-serial:");
 
         // serial number should follow "host:" and could be a host:port string.
-        serial_end = skip_host_serial(service);
+        serial_end = internal::skip_host_serial(service);
         if (serial_end) {
             *serial_end = 0; // terminate string
             serial = service;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 7af2979..ce0f289 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -841,4 +841,9 @@
     adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
 }
 
+// Sets TCP socket |fd| to send a keepalive TCP message every |interval_sec| seconds. Set
+// |interval_sec| to 0 to disable keepalives. If keepalives are enabled, the connection will be
+// configured to drop after 10 missed keepalives. Returns true on success.
+bool set_tcp_keepalive(int fd, int interval_sec);
+
 #endif /* _ADB_SYSDEPS_H */
diff --git a/adb/sysdeps_unix.cpp b/adb/sysdeps_unix.cpp
new file mode 100644
index 0000000..4445a44
--- /dev/null
+++ b/adb/sysdeps_unix.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sysdeps.h"
+
+bool set_tcp_keepalive(int fd, int interval_sec) {
+    int enable = (interval_sec > 0);
+    if (adb_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable))) {
+        return false;
+    }
+
+    if (!enable) {
+        return true;
+    }
+
+    // Idle time before sending the first keepalive is TCP_KEEPIDLE on Linux, TCP_KEEPALIVE on Mac.
+#if defined(TCP_KEEPIDLE)
+    if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &interval_sec, sizeof(interval_sec))) {
+        return false;
+    }
+#elif defined(TCP_KEEPALIVE)
+    if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &interval_sec, sizeof(interval_sec))) {
+        return false;
+    }
+#endif
+
+    // TCP_KEEPINTVL and TCP_KEEPCNT are available on Linux 2.4+ and OS X 10.8+ (Mountain Lion).
+#if defined(TCP_KEEPINTVL)
+    if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &interval_sec, sizeof(interval_sec))) {
+        return false;
+    }
+#endif
+
+#if defined(TCP_KEEPCNT)
+    // On Windows this value is hardcoded to 10. This is a reasonable value, so we do the same here
+    // to match behavior. See SO_KEEPALIVE documentation at
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/ee470551(v=vs.85).aspx.
+    const int keepcnt = 10;
+    if (adb_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt))) {
+        return false;
+    }
+#endif
+
+    return true;
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 7eae186..a2f34fb 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -1228,6 +1228,33 @@
     }
 }
 
+bool set_tcp_keepalive(int fd, int interval_sec) {
+    FH fh = _fh_from_int(fd, __func__);
+
+    if (!fh || fh->clazz != &_fh_socket_class) {
+        D("set_tcp_keepalive(%d) failed: invalid fd", fd);
+        errno = EBADF;
+        return false;
+    }
+
+    tcp_keepalive keepalive;
+    keepalive.onoff = (interval_sec > 0);
+    keepalive.keepalivetime = interval_sec * 1000;
+    keepalive.keepaliveinterval = interval_sec * 1000;
+
+    DWORD bytes_returned = 0;
+    if (WSAIoctl(fh->fh_socket, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), nullptr, 0,
+                 &bytes_returned, nullptr, nullptr) != 0) {
+        const DWORD err = WSAGetLastError();
+        D("set_tcp_keepalive(%d) failed: %s", fd,
+          android::base::SystemErrorCodeToString(err).c_str());
+        _socket_set_errno(err);
+        return false;
+    }
+
+    return true;
+}
+
 static adb_mutex_t g_console_output_buffer_lock;
 
 void
diff --git a/adb/test_device.py b/adb/test_device.py
index 18174a2..2acc444 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -845,6 +845,72 @@
             if host_dir is not None:
                 shutil.rmtree(host_dir)
 
+    def test_pull_dir_symlink(self):
+        """Pull a directory into a symlink to a directory.
+
+        Bug: http://b/27362811
+        """
+        if os.name != "posix":
+            raise unittest.SkipTest('requires POSIX')
+
+        try:
+            host_dir = tempfile.mkdtemp()
+            real_dir = os.path.join(host_dir, "dir")
+            symlink = os.path.join(host_dir, "symlink")
+            os.mkdir(real_dir)
+            os.symlink(real_dir, symlink)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
+
+            # Populate device directory with random files.
+            temp_files = make_random_device_files(
+                self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
+
+            self.device.pull(remote=self.DEVICE_TEMP_DIR, local=symlink)
+
+            for temp_file in temp_files:
+                host_path = os.path.join(
+                    real_dir, posixpath.basename(self.DEVICE_TEMP_DIR),
+                    temp_file.base_name)
+                self._verify_local(temp_file.checksum, host_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_pull_dir_symlink_collision(self):
+        """Pull a directory into a colliding symlink to directory."""
+        if os.name != "posix":
+            raise unittest.SkipTest('requires POSIX')
+
+        try:
+            host_dir = tempfile.mkdtemp()
+            real_dir = os.path.join(host_dir, "real")
+            tmp_dirname = os.path.basename(self.DEVICE_TEMP_DIR)
+            symlink = os.path.join(host_dir, tmp_dirname)
+            os.mkdir(real_dir)
+            os.symlink(real_dir, symlink)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
+
+            # Populate device directory with random files.
+            temp_files = make_random_device_files(
+                self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
+
+            self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
+
+            for temp_file in temp_files:
+                host_path = os.path.join(real_dir, temp_file.base_name)
+                self._verify_local(temp_file.checksum, host_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
     def test_pull_symlink_dir(self):
         """Pull a symlink to a directory of symlinks to files."""
         try:
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d9180bc..e3340af 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -30,6 +30,7 @@
 #include <list>
 
 #include <android-base/logging.h>
+#include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
@@ -679,11 +680,7 @@
 
         // Check for matching serial number.
         if (serial) {
-            if ((t->serial && !strcmp(serial, t->serial)) ||
-                (t->devpath && !strcmp(serial, t->devpath)) ||
-                qual_match(serial, "product:", t->product, false) ||
-                qual_match(serial, "model:", t->model, true) ||
-                qual_match(serial, "device:", t->device, false)) {
+            if (t->MatchesTarget(serial)) {
                 if (result) {
                     *error_out = "more than one device";
                     if (is_ambiguous) *is_ambiguous = true;
@@ -837,6 +834,43 @@
     disconnects_.clear();
 }
 
+bool atransport::MatchesTarget(const std::string& target) const {
+    if (serial) {
+        if (target == serial) {
+            return true;
+        } else if (type == kTransportLocal) {
+            // Local transports can match [tcp:|udp:]<hostname>[:port].
+            const char* local_target_ptr = target.c_str();
+
+            // For fastboot compatibility, ignore protocol prefixes.
+            if (android::base::StartsWith(target, "tcp:") ||
+                    android::base::StartsWith(target, "udp:")) {
+                local_target_ptr += 4;
+            }
+
+            // Parse our |serial| and the given |target| to check if the hostnames and ports match.
+            std::string serial_host, error;
+            int serial_port = -1;
+            if (android::base::ParseNetAddress(serial, &serial_host, &serial_port, nullptr,
+                                               &error)) {
+                // |target| may omit the port to default to ours.
+                std::string target_host;
+                int target_port = serial_port;
+                if (android::base::ParseNetAddress(local_target_ptr, &target_host, &target_port,
+                                                   nullptr, &error) &&
+                        serial_host == target_host && serial_port == target_port) {
+                    return true;
+                }
+            }
+        }
+    }
+
+    return (devpath && target == devpath) ||
+           qual_match(target.c_str(), "product:", product, false) ||
+           qual_match(target.c_str(), "model:", model, true) ||
+           qual_match(target.c_str(), "device:", device, false);
+}
+
 #if ADB_HOST
 
 static void append_transport_info(std::string* result, const char* key,
diff --git a/adb/transport.h b/adb/transport.h
index 4c0c008..5857249 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -107,6 +107,21 @@
     void RemoveDisconnect(adisconnect* disconnect);
     void RunDisconnects();
 
+    // Returns true if |target| matches this transport. A matching |target| can be any of:
+    //   * <serial>
+    //   * <devpath>
+    //   * product:<product>
+    //   * model:<model>
+    //   * device:<device>
+    //
+    // If this is a local transport, serial will also match [tcp:|udp:]<hostname>[:port] targets.
+    // For example, serial "100.100.100.100:5555" would match any of:
+    //   * 100.100.100.100
+    //   * tcp:100.100.100.100
+    //   * udp:100.100.100.100:5555
+    // This is to make it easier to use the same network target for both fastboot and adb.
+    bool MatchesTarget(const std::string& target) const;
+
 private:
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index e6e699b..372bedf 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -225,7 +225,7 @@
     static const char _ok_resp[] = "ok";
 
     const int port = (int) (uintptr_t) arg;
-    int res, fd;
+    int fd;
     char tmp[256];
     char con_name[32];
 
@@ -251,19 +251,19 @@
          */
 
         /* Send the 'accept' request. */
-        res = adb_write(fd, _accept_req, strlen(_accept_req));
-        if ((size_t)res == strlen(_accept_req)) {
+        if (WriteFdExactly(fd, _accept_req, strlen(_accept_req))) {
             /* Wait for the response. In the response we expect 'ok' on success,
              * or 'ko' on failure. */
-            res = adb_read(fd, tmp, sizeof(tmp));
-            if (res != 2 || memcmp(tmp, _ok_resp, 2)) {
+            if (!ReadFdExactly(fd, tmp, 2) || memcmp(tmp, _ok_resp, 2)) {
                 D("Accepting ADB host connection has failed.");
                 adb_close(fd);
             } else {
                 /* Host is connected. Register the transport, and start the
                  * exchange. */
                 register_socket_transport(fd, "host", port, 1);
-                adb_write(fd, _start_req, strlen(_start_req));
+                if (!WriteFdExactly(fd, _start_req, strlen(_start_req))) {
+                    adb_close(fd);
+                }
             }
 
             /* Prepare for accepting of the next ADB host connection. */
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 1bdea2a..2028ecc 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -218,3 +218,60 @@
     ASSERT_EQ(std::string("bar"), t.model);
     ASSERT_EQ(std::string("baz"), t.device);
 }
+
+TEST(transport, test_matches_target) {
+    std::string serial = "foo";
+    std::string devpath = "/path/to/bar";
+    std::string product = "test_product";
+    std::string model = "test_model";
+    std::string device = "test_device";
+
+    atransport t;
+    t.serial = &serial[0];
+    t.devpath = &devpath[0];
+    t.product = &product[0];
+    t.model = &model[0];
+    t.device = &device[0];
+
+    // These tests should not be affected by the transport type.
+    for (TransportType type : {kTransportAny, kTransportLocal}) {
+        t.type = type;
+
+        EXPECT_TRUE(t.MatchesTarget(serial));
+        EXPECT_TRUE(t.MatchesTarget(devpath));
+        EXPECT_TRUE(t.MatchesTarget("product:" + product));
+        EXPECT_TRUE(t.MatchesTarget("model:" + model));
+        EXPECT_TRUE(t.MatchesTarget("device:" + device));
+
+        // Product, model, and device don't match without the prefix.
+        EXPECT_FALSE(t.MatchesTarget(product));
+        EXPECT_FALSE(t.MatchesTarget(model));
+        EXPECT_FALSE(t.MatchesTarget(device));
+    }
+}
+
+TEST(transport, test_matches_target_local) {
+    std::string serial = "100.100.100.100:5555";
+
+    atransport t;
+    t.serial = &serial[0];
+
+    // Network address matching should only be used for local transports.
+    for (TransportType type : {kTransportAny, kTransportLocal}) {
+        t.type = type;
+        bool should_match = (type == kTransportLocal);
+
+        EXPECT_EQ(should_match, t.MatchesTarget("100.100.100.100"));
+        EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100"));
+        EXPECT_EQ(should_match, t.MatchesTarget("tcp:100.100.100.100:5555"));
+        EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100"));
+        EXPECT_EQ(should_match, t.MatchesTarget("udp:100.100.100.100:5555"));
+
+        // Wrong protocol, hostname, or port should never match.
+        EXPECT_FALSE(t.MatchesTarget("100.100.100"));
+        EXPECT_FALSE(t.MatchesTarget("100.100.100.100:"));
+        EXPECT_FALSE(t.MatchesTarget("100.100.100.100:-1"));
+        EXPECT_FALSE(t.MatchesTarget("100.100.100.100:5554"));
+        EXPECT_FALSE(t.MatchesTarget("abc:100.100.100.100"));
+    }
+}
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 31d9f0f..d993576 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -189,7 +189,7 @@
   return true;
 }
 
-bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
+bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid __unused,
                                                     FilePath *crash_directory,
                                                     bool *out_of_capacity) {
   if (out_of_capacity) *out_of_capacity = false;
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index a326f55..1b4ecbe 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -90,7 +90,11 @@
 ifeq ($(HOST_OS),linux)
 my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
 endif
-$(call dist-for-goals,dist_files sdk,$(my_dist_files))
+$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
+ifdef HOST_CROSS_OS
+# Archive fastboot.exe for win_sdk build.
+$(call dist-for-goals,win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
+endif
 my_dist_files :=
 
 ifeq ($(HOST_OS),linux)
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
index 22ca706..5f2396b 100644
--- a/libcutils/tests/PropertiesTest.cpp
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -106,14 +106,14 @@
         ResetValue();
 
         // Since the value is null, default value will be returned
-        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
         EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
         EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
     }
 
     // Trivial case => get returns what was set
     {
-        int len = SetAndGetProperty("hello_world");
+        size_t len = SetAndGetProperty("hello_world");
         EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
         EXPECT_STREQ("hello_world", mValue);
         ResetValue();
@@ -122,7 +122,7 @@
     // Set to empty string => get returns default always
     {
         const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
-        int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+        size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
         EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
         EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
         ResetValue();
@@ -147,7 +147,7 @@
 
         // Expect that the value set fails since it's too long
         EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
-        int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+        size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
 
         EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
         EXPECT_STREQ(VALID_TEST_VALUE, mValue);
diff --git a/liblog/Android.bp b/liblog/Android.bp
index ee883f0..607d667 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -14,15 +14,16 @@
 // limitations under the License.
 //
 
-liblog_host_sources = [
+liblog_sources = [
     "logd_write.c",
+    "log_event_list.c",
     "log_event_write.c",
+]
+liblog_host_sources = [
     "fake_log_device.c",
     //"event.logtags",
 ]
 liblog_target_sources = [
-    "logd_write.c",
-    "log_event_write.c",
     "event_tag_map.c",
     "log_time.cpp",
     "log_is_loggable.c",
@@ -36,6 +37,8 @@
     name: "liblog",
     host_supported: true,
 
+    srcs: liblog_sources,
+
     target: {
         host: {
             srcs: liblog_host_sources,
@@ -71,7 +74,6 @@
         //       $(LOCAL_PATH)/event.logtags)
         // so make sure we do not regret hard-coding it as follows:
         "-DLIBLOG_LOG_TAG=1005",
-        "-DSNET_EVENT_LOG_TAG=1397638484",
     ],
     compile_multilib: "both",
     stl: "none",
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 0badbd9..3d58147 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -14,66 +14,9 @@
  * limitations under the License.
  */
 
-#include <fcntl.h>
-#include <sys/cdefs.h>
-
 #include <gtest/gtest.h>
 
-// Should be in bionic test suite, *but* we are using liblog to confirm
-// end-to-end logging, so let the overly cute oedipus complex begin ...
-#include "../../../../bionic/libc/bionic/libc_logging.cpp" // not Standalone
-#define _ANDROID_LOG_H // Priorities redefined
-#define _LIBS_LOG_LOG_H // log ids redefined
-typedef unsigned char log_id_t; // log_id_t missing as a result
-#define _LIBS_LOG_LOG_READ_H // log_time redefined
-
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/log_read.h>
-
-TEST(libc, __libc_fatal_no_abort) {
-    struct logger_list *logger_list;
-
-    pid_t pid = getpid();
-
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
-    char b[80];
-    struct timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-
-    __libc_fatal_no_abort("%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
-    snprintf(b, sizeof(b),"%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
-    usleep(1000000);
-
-    int count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
-            break;
-        }
-
-        ASSERT_EQ(log_msg.entry.pid, pid);
-
-        if ((int)log_msg.id() != LOG_ID_CRASH) {
-            continue;
-        }
-
-        char *data = log_msg.msg();
-
-        if ((*data == ANDROID_LOG_FATAL)
-                && !strcmp(data + 1, "libc")
-                && !strcmp(data + 1 + strlen(data + 1) + 1, b)) {
-            ++count;
-        }
-    }
-
-    EXPECT_EQ(1, count);
-
-    android_logger_list_close(logger_list);
-}
+#include <stdio.h>
 
 TEST(libc, __pstore_append) {
     FILE *fp;
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index 7906986..09fbbb1 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -14,5 +14,4 @@
 LOCAL_CFLAGS := -Wall -Werror
 include $(BUILD_HOST_STATIC_LIBRARY)
 
-include $(LOCAL_PATH)/tools/Android.mk \
-        $(LOCAL_PATH)/test/Android.mk
+include $(LOCAL_PATH)/test/Android.mk
diff --git a/libmincrypt/tools/Android.mk b/libmincrypt/tools/Android.mk
deleted file mode 100644
index f403621..0000000
--- a/libmincrypt/tools/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Determine whether to build dumpkey from system/core/libmincrypt or from
-# bootable/recovery/tools. The dumpkey source is temporarily present in both
-# locations during the process of moving the tool to the recovery repository.
-# TODO(mnissler): Remove the guard after the transition is complete.
-ifndef BUILD_DUMPKEY_FROM_RECOVERY
-BUILD_DUMPKEY_FROM_RECOVERY := false
-endif
-
-ifeq ($(BUILD_DUMPKEY_FROM_RECOVERY),false)
-include $(CLEAR_VARS)
-LOCAL_MODULE := dumpkey
-LOCAL_SRC_FILES := DumpPublicKey.java
-LOCAL_JAR_MANIFEST := DumpPublicKey.mf
-LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
-include $(BUILD_HOST_JAVA_LIBRARY)
-endif
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
deleted file mode 100644
index 3eb1398..0000000
--- a/libmincrypt/tools/DumpPublicKey.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumpkey;
-
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import java.io.FileInputStream;
-import java.math.BigInteger;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.KeyStore;
-import java.security.Key;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.ECPoint;
-
-/**
- * Command line tool to extract RSA public keys from X.509 certificates
- * and output source code with data initializers for the keys.
- * @hide
- */
-class DumpPublicKey {
-    /**
-     * @param key to perform sanity checks on
-     * @return version number of key.  Supported versions are:
-     *     1: 2048-bit RSA key with e=3 and SHA-1 hash
-     *     2: 2048-bit RSA key with e=65537 and SHA-1 hash
-     *     3: 2048-bit RSA key with e=3 and SHA-256 hash
-     *     4: 2048-bit RSA key with e=65537 and SHA-256 hash
-     * @throws Exception if the key has the wrong size or public exponent
-     */
-    static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
-        BigInteger pubexp = key.getPublicExponent();
-        BigInteger modulus = key.getModulus();
-        int version;
-
-        if (pubexp.equals(BigInteger.valueOf(3))) {
-            version = useSHA256 ? 3 : 1;
-        } else if (pubexp.equals(BigInteger.valueOf(65537))) {
-            version = useSHA256 ? 4 : 2;
-        } else {
-            throw new Exception("Public exponent should be 3 or 65537 but is " +
-                                pubexp.toString(10) + ".");
-        }
-
-        if (modulus.bitLength() != 2048) {
-             throw new Exception("Modulus should be 2048 bits long but is " +
-                        modulus.bitLength() + " bits.");
-        }
-
-        return version;
-    }
-
-    /**
-     * @param key to perform sanity checks on
-     * @return version number of key.  Supported versions are:
-     *     5: 256-bit EC key with curve NIST P-256
-     * @throws Exception if the key has the wrong size or public exponent
-     */
-    static int checkEC(ECPublicKey key) throws Exception {
-        if (key.getParams().getCurve().getField().getFieldSize() != 256) {
-            throw new Exception("Curve must be NIST P-256");
-        }
-
-        return 5;
-    }
-
-    /**
-     * Perform sanity check on public key.
-     */
-    static int check(PublicKey key, boolean useSHA256) throws Exception {
-        if (key instanceof RSAPublicKey) {
-            return checkRSA((RSAPublicKey) key, useSHA256);
-        } else if (key instanceof ECPublicKey) {
-            if (!useSHA256) {
-                throw new Exception("Must use SHA-256 with EC keys!");
-            }
-            return checkEC((ECPublicKey) key);
-        } else {
-            throw new Exception("Unsupported key class: " + key.getClass().getName());
-        }
-    }
-
-    /**
-     * @param key to output
-     * @return a String representing this public key.  If the key is a
-     *    version 1 key, the string will be a C initializer; this is
-     *    not true for newer key versions.
-     */
-    static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
-        int version = check(key, useSHA256);
-
-        BigInteger N = key.getModulus();
-
-        StringBuilder result = new StringBuilder();
-
-        int nwords = N.bitLength() / 32;    // # of 32 bit integers in modulus
-
-        if (version > 1) {
-            result.append("v");
-            result.append(Integer.toString(version));
-            result.append(" ");
-        }
-
-        result.append("{");
-        result.append(nwords);
-
-        BigInteger B = BigInteger.valueOf(0x100000000L);  // 2^32
-        BigInteger N0inv = B.subtract(N.modInverse(B));   // -1 / N[0] mod 2^32
-
-        result.append(",0x");
-        result.append(N0inv.toString(16));
-
-        BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
-        BigInteger RR = R.multiply(R).mod(N);    // 2^4096 mod N
-
-        // Write out modulus as little endian array of integers.
-        result.append(",{");
-        for (int i = 0; i < nwords; ++i) {
-            long n = N.mod(B).longValue();
-            result.append(n);
-
-            if (i != nwords - 1) {
-                result.append(",");
-            }
-
-            N = N.divide(B);
-        }
-        result.append("}");
-
-        // Write R^2 as little endian array of integers.
-        result.append(",{");
-        for (int i = 0; i < nwords; ++i) {
-            long rr = RR.mod(B).longValue();
-            result.append(rr);
-
-            if (i != nwords - 1) {
-                result.append(",");
-            }
-
-            RR = RR.divide(B);
-        }
-        result.append("}");
-
-        result.append("}");
-        return result.toString();
-    }
-
-    /**
-     * @param key to output
-     * @return a String representing this public key.  If the key is a
-     *    version 1 key, the string will be a C initializer; this is
-     *    not true for newer key versions.
-     */
-    static String printEC(ECPublicKey key) throws Exception {
-        int version = checkEC(key);
-
-        StringBuilder result = new StringBuilder();
-
-        result.append("v");
-        result.append(Integer.toString(version));
-        result.append(" ");
-
-        BigInteger X = key.getW().getAffineX();
-        BigInteger Y = key.getW().getAffineY();
-        int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8;    // # of 32 bit integers in X coordinate
-
-        result.append("{");
-        result.append(nbytes);
-
-        BigInteger B = BigInteger.valueOf(0x100L);  // 2^8
-
-        // Write out Y coordinate as array of characters.
-        result.append(",{");
-        for (int i = 0; i < nbytes; ++i) {
-            long n = X.mod(B).longValue();
-            result.append(n);
-
-            if (i != nbytes - 1) {
-                result.append(",");
-            }
-
-            X = X.divide(B);
-        }
-        result.append("}");
-
-        // Write out Y coordinate as array of characters.
-        result.append(",{");
-        for (int i = 0; i < nbytes; ++i) {
-            long n = Y.mod(B).longValue();
-            result.append(n);
-
-            if (i != nbytes - 1) {
-                result.append(",");
-            }
-
-            Y = Y.divide(B);
-        }
-        result.append("}");
-
-        result.append("}");
-        return result.toString();
-    }
-
-    static String print(PublicKey key, boolean useSHA256) throws Exception {
-        if (key instanceof RSAPublicKey) {
-            return printRSA((RSAPublicKey) key, useSHA256);
-        } else if (key instanceof ECPublicKey) {
-            return printEC((ECPublicKey) key);
-        } else {
-            throw new Exception("Unsupported key class: " + key.getClass().getName());
-        }
-    }
-
-    public static void main(String[] args) {
-        if (args.length < 1) {
-            System.err.println("Usage: DumpPublicKey certfile ... > source.c");
-            System.exit(1);
-        }
-        Security.addProvider(new BouncyCastleProvider());
-        try {
-            for (int i = 0; i < args.length; i++) {
-                FileInputStream input = new FileInputStream(args[i]);
-                CertificateFactory cf = CertificateFactory.getInstance("X.509");
-                X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
-
-                boolean useSHA256 = false;
-                String sigAlg = cert.getSigAlgName();
-                if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
-                    // SignApk has historically accepted "MD5withRSA"
-                    // certificates, but treated them as "SHA1withRSA"
-                    // anyway.  Continue to do so for backwards
-                    // compatibility.
-                  useSHA256 = false;
-                } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
-                  useSHA256 = true;
-                } else {
-                  System.err.println(args[i] + ": unsupported signature algorithm \"" +
-                                     sigAlg + "\"");
-                  System.exit(1);
-                }
-
-                PublicKey key = cert.getPublicKey();
-                check(key, useSHA256);
-                System.out.print(print(key, useSHA256));
-                System.out.println(i < args.length - 1 ? "," : "");
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            System.exit(1);
-        }
-        System.exit(0);
-    }
-}
diff --git a/libmincrypt/tools/DumpPublicKey.mf b/libmincrypt/tools/DumpPublicKey.mf
deleted file mode 100644
index 7bb3bc8..0000000
--- a/libmincrypt/tools/DumpPublicKey.mf
+++ /dev/null
@@ -1 +0,0 @@
-Main-Class: com.android.dumpkey.DumpPublicKey
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index d9b32f9..24ecf86 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -89,9 +89,9 @@
   vector.add(4);
 
   vector.setCapacity(8);
-  ASSERT_EQ(8, vector.capacity());
+  ASSERT_EQ(8U, vector.capacity());
   vector.setCapacity(2);
-  ASSERT_EQ(8, vector.capacity());
+  ASSERT_EQ(8U, vector.capacity());
 }
 
 // NOTE: All of the tests below are useless because of the "TODO" above.
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 230dd11..4eb5e83 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -99,11 +99,20 @@
 }
 
 void LogAudit::enforceIntegrity() {
+    static bool loggedOnce;
+    bool once = loggedOnce;
+
+    loggedOnce = true;
+
     if (!AUDITD_ENFORCE_INTEGRITY) {
-        logToDmesg("integrity enforcement suppressed; not rebooting");
+        if (!once) {
+            logToDmesg("integrity enforcement suppressed; not rebooting");
+        }
     } else if (rebootToSafeMode) {
         if (getProperty("persist.sys.safemode") == "1") {
-            logToDmesg("integrity enforcement suppressed; in safe mode");
+            if (!once) {
+                logToDmesg("integrity enforcement suppressed; in safe mode");
+            }
             return;
         }
 
@@ -155,6 +164,10 @@
         }
     }
 
+    // Note: The audit log can include untrusted strings, but those containing
+    // "a control character, unprintable character, double quote mark, or a
+    // space" are hex encoded. The space character before the search term is
+    // therefore needed to prevent denial of service. Do not remove the space.
     bool permissive = strstr(str, " enforcing=0") ||
                       strstr(str, " permissive=1");
 
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index a4b96d3..2a04880 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -90,7 +90,7 @@
         while(it != times.end()) {
             if (*it == me) {
                 times.erase(it);
-                me->release_Locked();
+                me->release_nodelete_Locked();
                 break;
             }
             it++;
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index f5969df..b66ff9e 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -75,7 +75,13 @@
     void triggerSkip_Locked(log_id_t id, unsigned int skip) { skipAhead[id] = skip; }
     void cleanSkip_Locked(void);
 
-    // Called after LogTimeEntry removed from list, lock implicitly held
+    // These called after LogTimeEntry removed from list, lock implicitly held
+    void release_nodelete_Locked(void) {
+        mRelease = true;
+        pthread_cond_signal(&threadTriggeredCondition);
+        // assumes caller code path will call decRef_Locked()
+    }
+
     void release_Locked(void) {
         mRelease = true;
         pthread_cond_signal(&threadTriggeredCondition);
diff --git a/logd/main.cpp b/logd/main.cpp
index f4d7464..3095f7f 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -165,7 +165,7 @@
         char newkey[PROPERTY_KEY_MAX];
         snprintf(newkey, sizeof(newkey), "ro.%s", key);
         property_get(newkey, property, "");
-        // persist properties set by /data require innoculation with
+        // persist properties set by /data require inoculation with
         // logd-reinit. They may be set in init.rc early and function, but
         // otherwise are defunct unless reset. Do not rely on persist
         // properties for startup-only keys unless you are willing to restart
@@ -265,8 +265,11 @@
     set_sched_policy(0, SP_BACKGROUND);
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
 
-    setgid(AID_SYSTEM);
-    setuid(AID_SYSTEM);
+    // If we are AID_ROOT, we should drop to AID_SYSTEM, if we are anything
+    // else, we have even lesser privileges and accept our fate. Not worth
+    // checking for error returns setting this thread's privileges.
+    (void)setgid(AID_SYSTEM);
+    (void)setuid(AID_SYSTEM);
 
     while (reinit_running && !sem_wait(&reinit) && reinit_running) {
 
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index aea2585..f95d703 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -19,6 +19,7 @@
 from os import fstat
 from struct import pack
 from hashlib import sha1
+import sys
 
 def filesize(f):
     if f is None:
@@ -133,8 +134,10 @@
     img_id = write_header(args)
     write_data(args)
     if args.id:
-        print('0x' + ''.join('{:02x}'.format(ord(c)) for c in img_id))
-
+        if isinstance(img_id, str):
+            # Python 2's struct.pack returns a string, but py3 returns bytes.
+            img_id = [ord(x) for x in img_id]
+        print('0x' + ''.join('{:02x}'.format(c) for c in img_id))
 
 if __name__ == '__main__':
     main()
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
index 30485a0..a2b9111 100755
--- a/toolbox/generate-input.h-labels.py
+++ b/toolbox/generate-input.h-labels.py
@@ -16,6 +16,7 @@
 #
 # pylint: disable=bad-indentation,bad-continuation
 
+from __future__ import print_function
 import os
 import re
 import sys
@@ -72,11 +73,11 @@
         ff_list.append(name)
 
 def Dump(struct_name, values):
-  print 'static struct label %s[] = {' % (struct_name)
+  print('static struct label %s[] = {' % (struct_name))
   for value in values:
-    print '    LABEL(%s),' % (value)
-  print '    LABEL_END,'
-  print '};'
+    print('    LABEL(%s),' % (value))
+  print('    LABEL_END,')
+  print('};')
 
 Dump("input_prop_labels", input_prop_list)
 Dump("ev_labels", ev_list)
diff --git a/toolbox/top.c b/toolbox/top.c
index 0ea5a5e..6fda132 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -62,12 +62,13 @@
     char state;
     uint64_t utime;
     uint64_t stime;
+    char pr[3];
+    long ni;
     uint64_t delta_utime;
     uint64_t delta_stime;
     uint64_t delta_time;
     uint64_t vss;
     uint64_t rss;
-    int prs;
     int num_threads;
     char policy[POLICY_NAME_LEN];
 };
@@ -183,11 +184,11 @@
         old_procs = new_procs;
         num_old_procs = num_new_procs;
         memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
-        sleep(delay);
         read_procs();
         print_procs();
         free_old_procs();
         fflush(stdout);
+        if (iterations != 0) sleep(delay);
     }
 
     return 0;
@@ -339,20 +340,30 @@
     strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
     proc->tname[THREAD_NAME_LEN-1] = 0;
 
-    /* Scan rest of string. */
+    // Scan rest of string.
+    long pr;
     sscanf(close_paren + 1,
-           " %c " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
-           "%" SCNu64
-           "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d "
-           "%" SCNu64
-           "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
-           "%d",
+           " %c "
+           "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+           "%" SCNu64 // utime %lu (14)
+           "%" SCNu64 // stime %lu (15)
+           "%*d %*d "
+           "%ld " // priority %ld (18)
+           "%ld " // nice %ld (19)
+           "%*d %*d %*d "
+           "%" SCNu64 // vsize %lu (23)
+           "%" SCNu64, // rss %ld (24)
            &proc->state,
            &proc->utime,
            &proc->stime,
+           &pr,
+           &proc->ni,
            &proc->vss,
-           &proc->rss,
-           &proc->prs);
+           &proc->rss);
+
+    // Translate the PR field.
+    if (pr < -9) strcpy(proc->pr, "RT");
+    else snprintf(proc->pr, sizeof(proc->pr), "%ld", pr);
 
     return 0;
 }
@@ -414,11 +425,10 @@
 }
 
 static void print_procs(void) {
+    static int call = 0;
     int i;
     struct proc_info *old_proc, *proc;
     long unsigned total_delta_time;
-    struct passwd *user;
-    char *user_str, user_buf[20];
 
     for (i = 0; i < num_new_procs; i++) {
         if (new_procs[i]) {
@@ -441,7 +451,7 @@
 
     qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
 
-    printf("\n\n\n");
+    if (call++ > 0) printf("\n\n\n");
     printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
             ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100  / total_delta_time,
             ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
@@ -459,16 +469,18 @@
             total_delta_time);
     printf("\n");
     if (!threads)
-        printf("%5s %2s %4s %1s %5s %7s %7s %3s %-8s %s\n", "PID", "PR", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "UID", "Name");
+        printf("%5s %-8s %2s %3s %4s %1s %5s %7s %7s %3s %s\n", "PID", "USER", "PR", "NI", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "Name");
     else
-        printf("%5s %5s %2s %4s %1s %7s %7s %3s %-8s %-15s %s\n", "PID", "TID", "PR", "CPU%", "S", "VSS", "RSS", "PCY", "UID", "Thread", "Proc");
+        printf("%5s %5s %-8s %2s %3s %4s %1s %7s %7s %3s %-15s %s\n", "PID", "TID", "USER", "PR", "NI", "CPU%", "S", "VSS", "RSS", "PCY", "Thread", "Proc");
 
     for (i = 0; i < num_new_procs; i++) {
         proc = new_procs[i];
 
         if (!proc || (max_procs && (i >= max_procs)))
             break;
-        user  = getpwuid(proc->uid);
+        struct passwd* user = getpwuid(proc->uid);
+        char user_buf[20];
+        char* user_str;
         if (user && user->pw_name) {
             user_str = user->pw_name;
         } else {
@@ -476,13 +488,17 @@
             user_str = user_buf;
         }
         if (!threads) {
-            printf("%5d %2d %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %s\n",
-                   proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
-                   proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
+            printf("%5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %s\n",
+                   proc->pid, user_str, proc->pr, proc->ni,
+                   proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
+                   proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
+                   proc->name[0] != 0 ? proc->name : proc->tname);
         } else {
-            printf("%5d %5d %2d %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %-15s %s\n",
-                   proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
-                   proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name);
+            printf("%5d %5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-15s %s\n",
+                   proc->pid, proc->tid, user_str, proc->pr, proc->ni,
+                   proc->delta_time * 100 / total_delta_time, proc->state,
+                   proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
+                   proc->tname, proc->name);
         }
     }
 }