Merge "Revert "adb: Make HOME=/data/local/tmp""
diff --git a/adb/adb.h b/adb/adb.h
index be29f29..774215e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -214,18 +214,23 @@
 void local_connect(int port);
 int  local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
 
-/* usb host/client interface */
+// USB host/client interface.
 void usb_init();
 int usb_write(usb_handle *h, const void *data, int len);
 int usb_read(usb_handle *h, void *data, int len);
 int usb_close(usb_handle *h);
 void usb_kick(usb_handle *h);
 
-/* used for USB device detection */
+// USB device detection.
 #if ADB_HOST
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
 #endif
 
+// USB permission error help text. The short version will be one line, long may be multi-line.
+// Returns a string message to print, or an empty string if no problems could be found.
+std::string UsbNoPermissionsShortHelpText();
+std::string UsbNoPermissionsLongHelpText();
+
 int adb_commandline(int argc, const char **argv);
 
 ConnectionState connection_state(atransport *t);
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index 463b496..c4ffc85 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -228,13 +228,13 @@
 
 static void adb_auth_listener(int fd, unsigned events, void *data)
 {
-    struct sockaddr addr;
+    sockaddr_storage addr;
     socklen_t alen;
     int s;
 
     alen = sizeof(addr);
 
-    s = adb_socket_accept(fd, &addr, &alen);
+    s = adb_socket_accept(fd, reinterpret_cast<sockaddr*>(&addr), &alen);
     if (s < 0) {
         D("Failed to accept: errno=%d", errno);
         return;
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index d7b892c..e8c2338 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -34,9 +34,10 @@
 
 static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
     if (ev & FDE_READ) {
-        struct sockaddr addr;
-        socklen_t alen = sizeof(addr);
-        int fd = adb_socket_accept(_fd, &addr, &alen);
+        sockaddr_storage ss;
+        sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
+        socklen_t alen = sizeof(ss);
+        int fd = adb_socket_accept(_fd, addrp, &alen);
         if (fd < 0) return;
 
         int rcv_buf_size = CHUNK_SIZE;
@@ -58,12 +59,13 @@
     asocket *s;
 
     if (ev & FDE_READ) {
-        struct sockaddr addr;
+        sockaddr_storage ss;
+        sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
         socklen_t alen;
         int fd;
 
-        alen = sizeof(addr);
-        fd = adb_socket_accept(_fd, &addr, &alen);
+        alen = sizeof(ss);
+        fd = adb_socket_accept(_fd, addrp, &alen);
         if (fd < 0) {
             return;
         }
@@ -79,7 +81,7 @@
     }
 }
 
-static void  free_listener(alistener*  l)
+static void free_listener(alistener*  l)
 {
     if (l->next) {
         l->next->prev = l->prev;
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 463c1c0..239aaf8 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -76,6 +76,8 @@
             ReadOrderlyShutdown(fd);
         }
         adb_close(fd);
+
+        line_printer_.KeepInfoLine();
     }
 
     bool IsValid() { return fd >= 0; }
@@ -243,8 +245,7 @@
     }
 
     void Print(const std::string& s) {
-        // TODO: we actually don't want ELIDE; we want "ELIDE if smart, FULL if dumb".
-        line_printer_.Print(s, LinePrinter::ELIDE);
+        line_printer_.Print(s, LinePrinter::INFO);
     }
 
     void Printf(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
@@ -265,7 +266,7 @@
         android::base::StringAppendV(&s, fmt, ap);
         va_end(ap);
 
-        line_printer_.Print(s, LinePrinter::FULL);
+        line_printer_.Print(s, LinePrinter::ERROR);
     }
 
     void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
@@ -276,7 +277,7 @@
         android::base::StringAppendV(&s, fmt, ap);
         va_end(ap);
 
-        line_printer_.Print(s, LinePrinter::FULL);
+        line_printer_.Print(s, LinePrinter::WARNING);
     }
 
     uint64_t total_bytes;
@@ -664,7 +665,7 @@
         }
     }
 
-    sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath.c_str(),
+    sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s", rpath.c_str(),
               pushed, (pushed == 1) ? "" : "s", skipped,
               (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
     return true;
@@ -739,7 +740,6 @@
         success &= sync_send(sc, src_path, dst_path, st.st_mtime, st.st_mode);
     }
 
-    sc.Print("\n");
     return success;
 }
 
@@ -858,7 +858,7 @@
         }
     }
 
-    sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath.c_str(),
+    sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s", rpath.c_str(),
               pulled, (pulled == 1) ? "" : "s", skipped,
               (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
     return true;
@@ -967,7 +967,6 @@
         }
     }
 
-    sc.Print("\n");
     return success;
 }
 
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index cc2d44e..3c812cc 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -460,11 +460,11 @@
                    const char*   sockname,
                    int           socknamelen )
 {
-    struct sockaddr_un   addr;
-    socklen_t            addrlen;
-    int                  s;
-    int                  maxpath = sizeof(addr.sun_path);
-    int                  pathlen = socknamelen;
+    sockaddr_un   addr;
+    socklen_t     addrlen;
+    int           s;
+    int           maxpath = sizeof(addr.sun_path);
+    int           pathlen = socknamelen;
 
     if (pathlen >= maxpath) {
         D( "vm debug control socket name too long (%d extra chars)",
@@ -485,7 +485,7 @@
 
     addrlen = (pathlen + sizeof(addr.sun_family));
 
-    if (bind(s, (struct sockaddr*)&addr, addrlen) < 0) {
+    if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
         D( "could not bind vm debug control socket: %d: %s",
            errno, strerror(errno) );
         adb_close(s);
@@ -523,13 +523,14 @@
     JdwpControl*  control = (JdwpControl*) _control;
 
     if (events & FDE_READ) {
-        struct sockaddr   addr;
-        socklen_t         addrlen = sizeof(addr);
-        int               s = -1;
-        JdwpProcess*      proc;
+        sockaddr_storage   ss;
+        sockaddr*          addrp = reinterpret_cast<sockaddr*>(&ss);
+        socklen_t          addrlen = sizeof(ss);
+        int                s = -1;
+        JdwpProcess*       proc;
 
         do {
-            s = adb_socket_accept( control->listen_socket, &addr, &addrlen );
+            s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
             if (s < 0) {
                 if (errno == EINTR)
                     continue;
diff --git a/adb/line_printer.cpp b/adb/line_printer.cpp
index 4c57c7e..e8fe6c9 100644
--- a/adb/line_printer.cpp
+++ b/adb/line_printer.cpp
@@ -43,7 +43,7 @@
   return result;
 }
 
-LinePrinter::LinePrinter() : have_blank_line_(true), console_locked_(false) {
+LinePrinter::LinePrinter() : have_blank_line_(true) {
 #ifndef _WIN32
   const char* term = getenv("TERM");
   smart_terminal_ = unix_isatty(1) && term && string(term) != "dumb";
@@ -59,20 +59,24 @@
 #endif
 }
 
+static void Out(const std::string& s) {
+  // Avoid printf and C strings, since the actual output might contain null
+  // bytes like UTF-16 does (yuck).
+  fwrite(s.data(), 1, s.size(), stdout);
+}
+
 void LinePrinter::Print(string to_print, LineType type) {
-  if (console_locked_) {
-    line_buffer_ = to_print;
-    line_type_ = type;
+  if (!smart_terminal_) {
+    Out(to_print);
     return;
   }
 
-  if (smart_terminal_) {
-    printf("\r");  // Print over previous line, if any.
-    // On Windows, calling a C library function writing to stdout also handles
-    // pausing the executable when the "Pause" key or Ctrl-S is pressed.
-  }
+  // Print over previous line, if any.
+  // On Windows, calling a C library function writing to stdout also handles
+  // pausing the executable when the "Pause" key or Ctrl-S is pressed.
+  printf("\r");
 
-  if (smart_terminal_ && type == ELIDE) {
+  if (type == INFO) {
 #ifdef _WIN32
     CONSOLE_SCREEN_BUFFER_INFO csbi;
     GetConsoleScreenBufferInfo(console_, &csbi);
@@ -105,57 +109,19 @@
     if ((ioctl(0, TIOCGWINSZ, &size) == 0) && size.ws_col) {
       to_print = ElideMiddle(to_print, size.ws_col);
     }
-    printf("%s", to_print.c_str());
+    Out(to_print);
     printf("\x1B[K");  // Clear to end of line.
     fflush(stdout);
 #endif
 
     have_blank_line_ = false;
   } else {
-    printf("%s\n", to_print.c_str());
+    Out(to_print);
+    Out("\n");
+    have_blank_line_ = true;
   }
 }
 
-void LinePrinter::PrintOrBuffer(const char* data, size_t size) {
-  if (console_locked_) {
-    output_buffer_.append(data, size);
-  } else {
-    // Avoid printf and C strings, since the actual output might contain null
-    // bytes like UTF-16 does (yuck).
-    fwrite(data, 1, size, stdout);
-  }
-}
-
-void LinePrinter::PrintOnNewLine(const string& to_print) {
-  if (console_locked_ && !line_buffer_.empty()) {
-    output_buffer_.append(line_buffer_);
-    output_buffer_.append(1, '\n');
-    line_buffer_.clear();
-  }
-  if (!have_blank_line_) {
-    PrintOrBuffer("\n", 1);
-  }
-  if (!to_print.empty()) {
-    PrintOrBuffer(&to_print[0], to_print.size());
-  }
-  have_blank_line_ = to_print.empty() || *to_print.rbegin() == '\n';
-}
-
-void LinePrinter::SetConsoleLocked(bool locked) {
-  if (locked == console_locked_)
-    return;
-
-  if (locked)
-    PrintOnNewLine("");
-
-  console_locked_ = locked;
-
-  if (!locked) {
-    PrintOnNewLine(output_buffer_);
-    if (!line_buffer_.empty()) {
-      Print(line_buffer_, line_type_);
-    }
-    output_buffer_.clear();
-    line_buffer_.clear();
-  }
+void LinePrinter::KeepInfoLine() {
+  if (!have_blank_line_) Out("\n");
 }
diff --git a/adb/line_printer.h b/adb/line_printer.h
index 3d0a5bd..42345e2 100644
--- a/adb/line_printer.h
+++ b/adb/line_printer.h
@@ -26,20 +26,14 @@
   bool is_smart_terminal() const { return smart_terminal_; }
   void set_smart_terminal(bool smart) { smart_terminal_ = smart; }
 
-  enum LineType {
-    FULL,
-    ELIDE
-  };
-  /// Overprints the current line. If type is ELIDE, elides to_print to fit on
-  /// one line.
+  enum LineType { INFO, WARNING, ERROR };
+
+  /// Outputs the given line. INFO output will be overwritten.
+  /// WARNING and ERROR appear on a line to themselves.
   void Print(std::string to_print, LineType type);
 
-  /// Prints a string on a new line, not overprinting previous output.
-  void PrintOnNewLine(const std::string& to_print);
-
-  /// Lock or unlock the console.  Any output sent to the LinePrinter while the
-  /// console is locked will not be printed until it is unlocked.
-  void SetConsoleLocked(bool locked);
+  /// If there's an INFO line, keep it. If not, do nothing.
+  void KeepInfoLine();
 
  private:
   /// Whether we can do fancy terminal control codes.
@@ -48,24 +42,9 @@
   /// Whether the caret is at the beginning of a blank line.
   bool have_blank_line_;
 
-  /// Whether console is locked.
-  bool console_locked_;
-
-  /// Buffered current line while console is locked.
-  std::string line_buffer_;
-
-  /// Buffered line type while console is locked.
-  LineType line_type_;
-
-  /// Buffered console output while console is locked.
-  std::string output_buffer_;
-
 #ifdef _WIN32
   void* console_;
 #endif
-
-  /// Print the given data to the console, or buffer it if it is locked.
-  void PrintOrBuffer(const char *data, size_t size);
 };
 
 #endif  // NINJA_LINE_PRINTER_H_
diff --git a/adb/test_device.py b/adb/test_device.py
new file mode 100644
index 0000000..955b67a
--- /dev/null
+++ b/adb/test_device.py
@@ -0,0 +1,951 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015 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.
+#
+from __future__ import print_function
+
+import contextlib
+import hashlib
+import os
+import posixpath
+import random
+import re
+import shlex
+import shutil
+import signal
+import socket
+import string
+import subprocess
+import sys
+import tempfile
+import unittest
+
+import mock
+
+import adb
+
+
+def requires_root(func):
+    def wrapper(self, *args):
+        if self.device.get_prop('ro.debuggable') != '1':
+            raise unittest.SkipTest('requires rootable build')
+
+        was_root = self.device.shell(['id', '-un'])[0].strip() == 'root'
+        if not was_root:
+            self.device.root()
+            self.device.wait()
+
+        try:
+            func(self, *args)
+        finally:
+            if not was_root:
+                self.device.unroot()
+                self.device.wait()
+
+    return wrapper
+
+
+def requires_non_root(func):
+    def wrapper(self, *args):
+        was_root = self.device.shell(['id', '-un'])[0].strip() == 'root'
+        if was_root:
+            self.device.unroot()
+            self.device.wait()
+
+        try:
+            func(self, *args)
+        finally:
+            if was_root:
+                self.device.root()
+                self.device.wait()
+
+    return wrapper
+
+
+class GetDeviceTest(unittest.TestCase):
+    def setUp(self):
+        self.android_serial = os.getenv('ANDROID_SERIAL')
+        if 'ANDROID_SERIAL' in os.environ:
+            del os.environ['ANDROID_SERIAL']
+
+    def tearDown(self):
+        if self.android_serial is not None:
+            os.environ['ANDROID_SERIAL'] = self.android_serial
+        else:
+            if 'ANDROID_SERIAL' in os.environ:
+                del os.environ['ANDROID_SERIAL']
+
+    @mock.patch('adb.device.get_devices')
+    def test_explicit(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        device = adb.get_device('foo')
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_from_env(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        os.environ['ANDROID_SERIAL'] = 'foo'
+        device = adb.get_device()
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_arg_beats_env(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        os.environ['ANDROID_SERIAL'] = 'bar'
+        device = adb.get_device('foo')
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_no_such_device(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        self.assertRaises(adb.DeviceNotFoundError, adb.get_device, ['baz'])
+
+        os.environ['ANDROID_SERIAL'] = 'baz'
+        self.assertRaises(adb.DeviceNotFoundError, adb.get_device)
+
+    @mock.patch('adb.device.get_devices')
+    def test_unique_device(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo']
+        device = adb.get_device()
+        self.assertEqual(device.serial, 'foo')
+
+    @mock.patch('adb.device.get_devices')
+    def test_no_unique_device(self, mock_get_devices):
+        mock_get_devices.return_value = ['foo', 'bar']
+        self.assertRaises(adb.NoUniqueDeviceError, adb.get_device)
+
+
+class DeviceTest(unittest.TestCase):
+    def setUp(self):
+        self.device = adb.get_device()
+
+
+class ForwardReverseTest(DeviceTest):
+    def _test_no_rebind(self, description, direction_list, direction,
+                       direction_no_rebind, direction_remove_all):
+        msg = direction_list()
+        self.assertEqual('', msg.strip(),
+                         description + ' list must be empty to run this test.')
+
+        # Use --no-rebind with no existing binding
+        direction_no_rebind('tcp:5566', 'tcp:6655')
+        msg = direction_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+
+        # Use --no-rebind with existing binding
+        with self.assertRaises(subprocess.CalledProcessError):
+            direction_no_rebind('tcp:5566', 'tcp:6677')
+        msg = direction_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6677', msg))
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+
+        # Use the absence of --no-rebind with existing binding
+        direction('tcp:5566', 'tcp:6677')
+        msg = direction_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6677', msg))
+
+        direction_remove_all()
+        msg = direction_list()
+        self.assertEqual('', msg.strip())
+
+    def test_forward_no_rebind(self):
+        self._test_no_rebind('forward', self.device.forward_list,
+                            self.device.forward, self.device.forward_no_rebind,
+                            self.device.forward_remove_all)
+
+    def test_reverse_no_rebind(self):
+        self._test_no_rebind('reverse', self.device.reverse_list,
+                            self.device.reverse, self.device.reverse_no_rebind,
+                            self.device.reverse_remove_all)
+
+    def test_forward(self):
+        msg = self.device.forward_list()
+        self.assertEqual('', msg.strip(),
+                         'Forwarding list must be empty to run this test.')
+        self.device.forward('tcp:5566', 'tcp:6655')
+        msg = self.device.forward_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.device.forward('tcp:7788', 'tcp:8877')
+        msg = self.device.forward_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.forward_remove('tcp:5566')
+        msg = self.device.forward_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.forward_remove_all()
+        msg = self.device.forward_list()
+        self.assertEqual('', msg.strip())
+
+    def test_reverse(self):
+        msg = self.device.reverse_list()
+        self.assertEqual('', msg.strip(),
+                         'Reverse forwarding list must be empty to run this test.')
+        self.device.reverse('tcp:5566', 'tcp:6655')
+        msg = self.device.reverse_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.device.reverse('tcp:7788', 'tcp:8877')
+        msg = self.device.reverse_list()
+        self.assertTrue(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.reverse_remove('tcp:5566')
+        msg = self.device.reverse_list()
+        self.assertFalse(re.search(r'tcp:5566.+tcp:6655', msg))
+        self.assertTrue(re.search(r'tcp:7788.+tcp:8877', msg))
+        self.device.reverse_remove_all()
+        msg = self.device.reverse_list()
+        self.assertEqual('', msg.strip())
+
+    # Note: If you run this test when adb connect'd to a physical device over
+    # TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
+    def test_forward_reverse_echo(self):
+        """Send data through adb forward and read it back via adb reverse"""
+        forward_port = 12345
+        reverse_port = forward_port + 1
+        forward_spec = "tcp:" + str(forward_port)
+        reverse_spec = "tcp:" + str(reverse_port)
+        forward_setup = False
+        reverse_setup = False
+
+        try:
+            # listen on localhost:forward_port, connect to remote:forward_port
+            self.device.forward(forward_spec, forward_spec)
+            forward_setup = True
+            # listen on remote:forward_port, connect to localhost:reverse_port
+            self.device.reverse(forward_spec, reverse_spec)
+            reverse_setup = True
+
+            listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            with contextlib.closing(listener):
+                # Use SO_REUSEADDR so that subsequent runs of the test can grab
+                # the port even if it is in TIME_WAIT.
+                listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+                # Listen on localhost:reverse_port before connecting to
+                # localhost:forward_port because that will cause adb to connect
+                # back to localhost:reverse_port.
+                listener.bind(('127.0.0.1', reverse_port))
+                listener.listen(4)
+
+                client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                with contextlib.closing(client):
+                    # Connect to the listener.
+                    client.connect(('127.0.0.1', forward_port))
+
+                    # Accept the client connection.
+                    accepted_connection, addr = listener.accept()
+                    with contextlib.closing(accepted_connection) as server:
+                        data = 'hello'
+
+                        # Send data into the port setup by adb forward.
+                        client.sendall(data)
+                        # Explicitly close() so that server gets EOF.
+                        client.close()
+
+                        # Verify that the data came back via adb reverse.
+                        self.assertEqual(data, server.makefile().read())
+        finally:
+            if reverse_setup:
+                self.device.reverse_remove(forward_spec)
+            if forward_setup:
+                self.device.forward_remove(forward_spec)
+
+
+class ShellTest(DeviceTest):
+    def _interactive_shell(self, shell_args, input):
+        """Runs an interactive adb shell.
+
+        Args:
+          shell_args: List of string arguments to `adb shell`.
+          input: String input to send to the interactive shell.
+
+        Returns:
+          The remote exit code.
+
+        Raises:
+          unittest.SkipTest: The device doesn't support exit codes.
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('exit codes are unavailable on this device')
+
+        proc = subprocess.Popen(
+                self.device.adb_cmd + ['shell'] + shell_args,
+                stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE)
+        # Closing host-side stdin doesn't trigger a PTY shell to exit so we need
+        # to explicitly add an exit command to close the session from the device
+        # side, plus the necessary newline to complete the interactive command.
+        proc.communicate(input + '; exit\n')
+        return proc.returncode
+
+    def test_cat(self):
+        """Check that we can at least cat a file."""
+        out = self.device.shell(['cat', '/proc/uptime'])[0].strip()
+        elements = out.split()
+        self.assertEqual(len(elements), 2)
+
+        uptime, idle = elements
+        self.assertGreater(float(uptime), 0.0)
+        self.assertGreater(float(idle), 0.0)
+
+    def test_throws_on_failure(self):
+        self.assertRaises(adb.ShellError, self.device.shell, ['false'])
+
+    def test_output_not_stripped(self):
+        out = self.device.shell(['echo', 'foo'])[0]
+        self.assertEqual(out, 'foo' + self.device.linesep)
+
+    def test_shell_nocheck_failure(self):
+        rc, out, _ = self.device.shell_nocheck(['false'])
+        self.assertNotEqual(rc, 0)
+        self.assertEqual(out, '')
+
+    def test_shell_nocheck_output_not_stripped(self):
+        rc, out, _ = self.device.shell_nocheck(['echo', 'foo'])
+        self.assertEqual(rc, 0)
+        self.assertEqual(out, 'foo' + self.device.linesep)
+
+    def test_can_distinguish_tricky_results(self):
+        # If result checking on ADB shell is naively implemented as
+        # `adb shell <cmd>; echo $?`, we would be unable to distinguish the
+        # output from the result for a cmd of `echo -n 1`.
+        rc, out, _ = self.device.shell_nocheck(['echo', '-n', '1'])
+        self.assertEqual(rc, 0)
+        self.assertEqual(out, '1')
+
+    def test_line_endings(self):
+        """Ensure that line ending translation is not happening in the pty.
+
+        Bug: http://b/19735063
+        """
+        output = self.device.shell(['uname'])[0]
+        self.assertEqual(output, 'Linux' + self.device.linesep)
+
+    def test_pty_logic(self):
+        """Tests that a PTY is allocated when it should be.
+
+        PTY allocation behavior should match ssh; some behavior requires
+        a terminal stdin to test so this test will be skipped if stdin
+        is not a terminal.
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('PTY arguments unsupported on this device')
+        if not os.isatty(sys.stdin.fileno()):
+            raise unittest.SkipTest('PTY tests require stdin terminal')
+
+        def check_pty(args):
+            """Checks adb shell PTY allocation.
+
+            Tests |args| for terminal and non-terminal stdin.
+
+            Args:
+                args: -Tt args in a list (e.g. ['-t', '-t']).
+
+            Returns:
+                A tuple (<terminal>, <non-terminal>). True indicates
+                the corresponding shell allocated a remote PTY.
+            """
+            test_cmd = self.device.adb_cmd + ['shell'] + args + ['[ -t 0 ]']
+
+            terminal = subprocess.Popen(
+                    test_cmd, stdin=None,
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            terminal.communicate()
+
+            non_terminal = subprocess.Popen(
+                    test_cmd, stdin=subprocess.PIPE,
+                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            non_terminal.communicate()
+
+            return (terminal.returncode == 0, non_terminal.returncode == 0)
+
+        # -T: never allocate PTY.
+        self.assertEqual((False, False), check_pty(['-T']))
+
+        # No args: PTY only if stdin is a terminal and shell is interactive,
+        # which is difficult to reliably test from a script.
+        self.assertEqual((False, False), check_pty([]))
+
+        # -t: PTY if stdin is a terminal.
+        self.assertEqual((True, False), check_pty(['-t']))
+
+        # -t -t: always allocate PTY.
+        self.assertEqual((True, True), check_pty(['-t', '-t']))
+
+    def test_shell_protocol(self):
+        """Tests the shell protocol on the device.
+
+        If the device supports shell protocol, this gives us the ability
+        to separate stdout/stderr and return the exit code directly.
+
+        Bug: http://b/19734861
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('shell protocol unsupported on this device')
+
+        # Shell protocol should be used by default.
+        result = self.device.shell_nocheck(
+                shlex.split('echo foo; echo bar >&2; exit 17'))
+        self.assertEqual(17, result[0])
+        self.assertEqual('foo' + self.device.linesep, result[1])
+        self.assertEqual('bar' + self.device.linesep, result[2])
+
+        self.assertEqual(17, self._interactive_shell([], 'exit 17'))
+
+        # -x flag should disable shell protocol.
+        result = self.device.shell_nocheck(
+                shlex.split('-x echo foo; echo bar >&2; exit 17'))
+        self.assertEqual(0, result[0])
+        self.assertEqual('foo{0}bar{0}'.format(self.device.linesep), result[1])
+        self.assertEqual('', result[2])
+
+        self.assertEqual(0, self._interactive_shell(['-x'], 'exit 17'))
+
+    def test_non_interactive_sigint(self):
+        """Tests that SIGINT in a non-interactive shell kills the process.
+
+        This requires the shell protocol in order to detect the broken
+        pipe; raw data transfer mode will only see the break once the
+        subprocess tries to read or write.
+
+        Bug: http://b/23825725
+        """
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('shell protocol unsupported on this device')
+
+        # Start a long-running process.
+        sleep_proc = subprocess.Popen(
+                self.device.adb_cmd + shlex.split('shell echo $$; sleep 60'),
+                stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+                stderr=subprocess.STDOUT)
+        remote_pid = sleep_proc.stdout.readline().strip()
+        self.assertIsNone(sleep_proc.returncode, 'subprocess terminated early')
+        proc_query = shlex.split('ps {0} | grep {0}'.format(remote_pid))
+
+        # Verify that the process is running, send signal, verify it stopped.
+        self.device.shell(proc_query)
+        os.kill(sleep_proc.pid, signal.SIGINT)
+        sleep_proc.communicate()
+        self.assertEqual(1, self.device.shell_nocheck(proc_query)[0],
+                         'subprocess failed to terminate')
+
+    def test_non_interactive_stdin(self):
+        """Tests that non-interactive shells send stdin."""
+        if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+            raise unittest.SkipTest('non-interactive stdin unsupported '
+                                    'on this device')
+
+        # Test both small and large inputs.
+        small_input = 'foo'
+        large_input = '\n'.join(c * 100 for c in (string.ascii_letters +
+                                                  string.digits))
+
+        for input in (small_input, large_input):
+            proc = subprocess.Popen(self.device.adb_cmd + ['shell', 'cat'],
+                                    stdin=subprocess.PIPE,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE)
+            stdout, stderr = proc.communicate(input)
+            self.assertEqual(input.splitlines(), stdout.splitlines())
+            self.assertEqual('', stderr)
+
+
+class ArgumentEscapingTest(DeviceTest):
+    def test_shell_escaping(self):
+        """Make sure that argument escaping is somewhat sane."""
+
+        # http://b/19734868
+        # Note that this actually matches ssh(1)'s behavior --- it's
+        # converted to `sh -c echo hello; echo world` which sh interprets
+        # as `sh -c echo` (with an argument to that shell of "hello"),
+        # and then `echo world` back in the first shell.
+        result = self.device.shell(
+            shlex.split("sh -c 'echo hello; echo world'"))[0]
+        result = result.splitlines()
+        self.assertEqual(['', 'world'], result)
+        # If you really wanted "hello" and "world", here's what you'd do:
+        result = self.device.shell(
+            shlex.split(r'echo hello\;echo world'))[0].splitlines()
+        self.assertEqual(['hello', 'world'], result)
+
+        # http://b/15479704
+        result = self.device.shell(shlex.split("'true && echo t'"))[0].strip()
+        self.assertEqual('t', result)
+        result = self.device.shell(
+            shlex.split("sh -c 'true && echo t'"))[0].strip()
+        self.assertEqual('t', result)
+
+        # http://b/20564385
+        result = self.device.shell(shlex.split('FOO=a BAR=b echo t'))[0].strip()
+        self.assertEqual('t', result)
+        result = self.device.shell(
+            shlex.split(r'echo -n 123\;uname'))[0].strip()
+        self.assertEqual('123Linux', result)
+
+    def test_install_argument_escaping(self):
+        """Make sure that install argument escaping works."""
+        # http://b/20323053, http://b/3090932.
+        for file_suffix in ('-text;ls;1.apk', "-Live Hold'em.apk"):
+            tf = tempfile.NamedTemporaryFile('wb', suffix=file_suffix,
+                                             delete=False)
+            tf.close()
+
+            # Installing bogus .apks fails if the device supports exit codes.
+            try:
+                output = self.device.install(tf.name)
+            except subprocess.CalledProcessError as e:
+                output = e.output
+
+            self.assertIn(file_suffix, output)
+            os.remove(tf.name)
+
+
+class RootUnrootTest(DeviceTest):
+    def _test_root(self):
+        message = self.device.root()
+        if 'adbd cannot run as root in production builds' in message:
+            return
+        self.device.wait()
+        self.assertEqual('root', self.device.shell(['id', '-un'])[0].strip())
+
+    def _test_unroot(self):
+        self.device.unroot()
+        self.device.wait()
+        self.assertEqual('shell', self.device.shell(['id', '-un'])[0].strip())
+
+    def test_root_unroot(self):
+        """Make sure that adb root and adb unroot work, using id(1)."""
+        if self.device.get_prop('ro.debuggable') != '1':
+            raise unittest.SkipTest('requires rootable build')
+
+        original_user = self.device.shell(['id', '-un'])[0].strip()
+        try:
+            if original_user == 'root':
+                self._test_unroot()
+                self._test_root()
+            elif original_user == 'shell':
+                self._test_root()
+                self._test_unroot()
+        finally:
+            if original_user == 'root':
+                self.device.root()
+            else:
+                self.device.unroot()
+            self.device.wait()
+
+
+class TcpIpTest(DeviceTest):
+    def test_tcpip_failure_raises(self):
+        """adb tcpip requires a port.
+
+        Bug: http://b/22636927
+        """
+        self.assertRaises(
+            subprocess.CalledProcessError, self.device.tcpip, '')
+        self.assertRaises(
+            subprocess.CalledProcessError, self.device.tcpip, 'foo')
+
+
+class SystemPropertiesTest(DeviceTest):
+    def test_get_prop(self):
+        self.assertEqual(self.device.get_prop('init.svc.adbd'), 'running')
+
+    @requires_root
+    def test_set_prop(self):
+        prop_name = 'foo.bar'
+        self.device.shell(['setprop', prop_name, '""'])
+
+        self.device.set_prop(prop_name, 'qux')
+        self.assertEqual(
+            self.device.shell(['getprop', prop_name])[0].strip(), 'qux')
+
+
+def compute_md5(string):
+    hsh = hashlib.md5()
+    hsh.update(string)
+    return hsh.hexdigest()
+
+
+def get_md5_prog(device):
+    """Older platforms (pre-L) had the name md5 rather than md5sum."""
+    try:
+        device.shell(['md5sum', '/proc/uptime'])
+        return 'md5sum'
+    except adb.ShellError:
+        return 'md5'
+
+
+class HostFile(object):
+    def __init__(self, handle, checksum):
+        self.handle = handle
+        self.checksum = checksum
+        self.full_path = handle.name
+        self.base_name = os.path.basename(self.full_path)
+
+
+class DeviceFile(object):
+    def __init__(self, checksum, full_path):
+        self.checksum = checksum
+        self.full_path = full_path
+        self.base_name = posixpath.basename(self.full_path)
+
+
+def make_random_host_files(in_dir, num_files):
+    min_size = 1 * (1 << 10)
+    max_size = 16 * (1 << 10)
+
+    files = []
+    for _ in xrange(num_files):
+        file_handle = tempfile.NamedTemporaryFile(dir=in_dir, delete=False)
+
+        size = random.randrange(min_size, max_size, 1024)
+        rand_str = os.urandom(size)
+        file_handle.write(rand_str)
+        file_handle.flush()
+        file_handle.close()
+
+        md5 = compute_md5(rand_str)
+        files.append(HostFile(file_handle, md5))
+    return files
+
+
+def make_random_device_files(device, in_dir, num_files, prefix='device_tmpfile'):
+    min_size = 1 * (1 << 10)
+    max_size = 16 * (1 << 10)
+
+    files = []
+    for file_num in xrange(num_files):
+        size = random.randrange(min_size, max_size, 1024)
+
+        base_name = prefix + str(file_num)
+        full_path = posixpath.join(in_dir, base_name)
+
+        device.shell(['dd', 'if=/dev/urandom', 'of={}'.format(full_path),
+                      'bs={}'.format(size), 'count=1'])
+        dev_md5, _ = device.shell([get_md5_prog(device), full_path])[0].split()
+
+        files.append(DeviceFile(dev_md5, full_path))
+    return files
+
+
+class FileOperationsTest(DeviceTest):
+    SCRATCH_DIR = '/data/local/tmp'
+    DEVICE_TEMP_FILE = SCRATCH_DIR + '/adb_test_file'
+    DEVICE_TEMP_DIR = SCRATCH_DIR + '/adb_test_dir'
+
+    def _verify_remote(self, checksum, remote_path):
+        dev_md5, _ = self.device.shell([get_md5_prog(self.device),
+                                        remote_path])[0].split()
+        self.assertEqual(checksum, dev_md5)
+
+    def _verify_local(self, checksum, local_path):
+        with open(local_path, 'rb') as host_file:
+            host_md5 = compute_md5(host_file.read())
+            self.assertEqual(host_md5, checksum)
+
+    def test_push(self):
+        """Push a randomly generated file to specified device."""
+        kbytes = 512
+        tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
+        rand_str = os.urandom(1024 * kbytes)
+        tmp.write(rand_str)
+        tmp.close()
+
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
+        self.device.push(local=tmp.name, remote=self.DEVICE_TEMP_FILE)
+
+        self._verify_remote(compute_md5(rand_str), self.DEVICE_TEMP_FILE)
+        self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
+
+        os.remove(tmp.name)
+
+    def test_push_dir(self):
+        """Push a randomly generated directory of files to the device."""
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            # Make sure the temp directory isn't setuid, or else adb will complain.
+            os.chmod(host_dir, 0o700)
+
+            # Create 32 random files.
+            temp_files = make_random_host_files(in_dir=host_dir, num_files=32)
+            self.device.push(host_dir, self.DEVICE_TEMP_DIR)
+
+            for temp_file in temp_files:
+                remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                             os.path.basename(host_dir),
+                                             temp_file.base_name)
+                self._verify_remote(temp_file.checksum, remote_path)
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    @unittest.expectedFailure # b/25566053
+    def test_push_empty(self):
+        """Push a directory containing an empty directory to the device."""
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            # Make sure the temp directory isn't setuid, or else adb will complain.
+            os.chmod(host_dir, 0o700)
+
+            # Create an empty directory.
+            os.mkdir(os.path.join(host_dir, 'empty'))
+
+            self.device.push(host_dir, self.DEVICE_TEMP_DIR)
+
+            test_empty_cmd = ['[', '-d',
+                              os.path.join(self.DEVICE_TEMP_DIR, 'empty')]
+            rc, _, _ = self.device.shell_nocheck(test_empty_cmd)
+            self.assertEqual(rc, 0)
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_multiple_push(self):
+        """Push multiple files to the device in one adb push command.
+
+        Bug: http://b/25324823
+        """
+
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            # Create some random files and a subdirectory containing more files.
+            temp_files = make_random_host_files(in_dir=host_dir, num_files=4)
+
+            subdir = os.path.join(host_dir, "subdir")
+            os.mkdir(subdir)
+            subdir_temp_files = make_random_host_files(in_dir=subdir,
+                                                       num_files=4)
+
+            paths = map(lambda temp_file: temp_file.full_path, temp_files)
+            paths.append(subdir)
+            self.device._simple_call(['push'] + paths + [self.DEVICE_TEMP_DIR])
+
+            for temp_file in temp_files:
+                remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                             temp_file.base_name)
+                self._verify_remote(temp_file.checksum, remote_path)
+
+            for subdir_temp_file in subdir_temp_files:
+                remote_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                             # BROKEN: http://b/25394682
+                                             # "subdir",
+                                             temp_file.base_name)
+                self._verify_remote(temp_file.checksum, remote_path)
+
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+
+    def _test_pull(self, remote_file, checksum):
+        tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
+        tmp_write.close()
+        self.device.pull(remote=remote_file, local=tmp_write.name)
+        with open(tmp_write.name, 'rb') as tmp_read:
+            host_contents = tmp_read.read()
+            host_md5 = compute_md5(host_contents)
+        self.assertEqual(checksum, host_md5)
+        os.remove(tmp_write.name)
+
+    @requires_non_root
+    def test_pull_error_reporting(self):
+        self.device.shell(['touch', self.DEVICE_TEMP_FILE])
+        self.device.shell(['chmod', 'a-rwx', self.DEVICE_TEMP_FILE])
+
+        try:
+            output = self.device.pull(remote=self.DEVICE_TEMP_FILE, local='x')
+        except subprocess.CalledProcessError as e:
+            output = e.output
+
+        self.assertIn('Permission denied', output)
+
+        self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
+
+    def test_pull(self):
+        """Pull a randomly generated file from specified device."""
+        kbytes = 512
+        self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
+        cmd = ['dd', 'if=/dev/urandom',
+               'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024',
+               'count={}'.format(kbytes)]
+        self.device.shell(cmd)
+        dev_md5, _ = self.device.shell(
+            [get_md5_prog(self.device), self.DEVICE_TEMP_FILE])[0].split()
+        self._test_pull(self.DEVICE_TEMP_FILE, dev_md5)
+        self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE])
+
+    def test_pull_dir(self):
+        """Pull a randomly generated directory of files from the device."""
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            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(
+                    host_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_empty(self):
+        """Pull a directory containing an empty directory from the device."""
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            remote_empty_path = posixpath.join(self.DEVICE_TEMP_DIR, 'empty')
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', remote_empty_path])
+
+            self.device.pull(remote=remote_empty_path, local=host_dir)
+            self.assertTrue(os.path.isdir(os.path.join(host_dir, 'empty')))
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_multiple_pull(self):
+        """Pull a randomly generated directory of files from the device."""
+
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            subdir = posixpath.join(self.DEVICE_TEMP_DIR, "subdir")
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', subdir])
+
+            # Create some random files and a subdirectory containing more files.
+            temp_files = make_random_device_files(
+                self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=4)
+
+            subdir_temp_files = make_random_device_files(
+                self.device, in_dir=subdir, num_files=4, prefix='subdir_')
+
+            paths = map(lambda temp_file: temp_file.full_path, temp_files)
+            paths.append(subdir)
+            self.device._simple_call(['pull'] + paths + [host_dir])
+
+            for temp_file in temp_files:
+                local_path = os.path.join(host_dir, temp_file.base_name)
+                self._verify_local(temp_file.checksum, local_path)
+
+            for subdir_temp_file in subdir_temp_files:
+                local_path = os.path.join(host_dir,
+                                          "subdir",
+                                          subdir_temp_file.base_name)
+                self._verify_local(subdir_temp_file.checksum, local_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
+    def test_sync(self):
+        """Sync a randomly generated directory of files to specified device."""
+
+        try:
+            base_dir = tempfile.mkdtemp()
+
+            # Create mirror device directory hierarchy within base_dir.
+            full_dir_path = base_dir + self.DEVICE_TEMP_DIR
+            os.makedirs(full_dir_path)
+
+            # Create 32 random files within the host mirror.
+            temp_files = make_random_host_files(in_dir=full_dir_path, num_files=32)
+
+            # Clean up any trash on the device.
+            device = adb.get_device(product=base_dir)
+            device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+
+            device.sync('data')
+
+            # Confirm that every file on the device mirrors that on the host.
+            for temp_file in temp_files:
+                device_full_path = posixpath.join(self.DEVICE_TEMP_DIR,
+                                                  temp_file.base_name)
+                dev_md5, _ = device.shell(
+                    [get_md5_prog(self.device), device_full_path])[0].split()
+                self.assertEqual(temp_file.checksum, dev_md5)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if base_dir is not None:
+                shutil.rmtree(base_dir)
+
+    def test_unicode_paths(self):
+        """Ensure that we can support non-ASCII paths, even on Windows."""
+        name = u'로보카 폴리'
+
+        self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
+        remote_path = u'/data/local/tmp/adb-test-{}'.format(name)
+
+        ## push.
+        tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+        tf.close()
+        self.device.push(tf.name, remote_path)
+        os.remove(tf.name)
+        self.assertFalse(os.path.exists(tf.name))
+
+        # Verify that the device ended up with the expected UTF-8 path
+        output = self.device.shell(
+                ['ls', '/data/local/tmp/adb-test-*'])[0].strip()
+        self.assertEqual(remote_path.encode('utf-8'), output)
+
+        # pull.
+        self.device.pull(remote_path, tf.name)
+        self.assertTrue(os.path.exists(tf.name))
+        os.remove(tf.name)
+        self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
+
+
+def main():
+    random.seed(0)
+    if len(adb.get_devices()) > 0:
+        suite = unittest.TestLoader().loadTestsFromName(__name__)
+        unittest.TextTestRunner(verbosity=3).run(suite)
+    else:
+        print('Test suite must be run with attached devices')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d20eaff..d4f60ec 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -674,7 +674,11 @@
     adb_mutex_lock(&transport_lock);
     for (const auto& t : transport_list) {
         if (t->connection_state == kCsNoPerm) {
-            *error_out = "insufficient permissions for device";
+            *error_out = UsbNoPermissionsLongHelpText();
+            // If we couldn't figure out a reasonable help message default to something generic.
+            if (error_out->empty()) {
+                *error_out = "insufficient permissions for device";
+            }
             continue;
         }
 
@@ -748,17 +752,20 @@
     return result;
 }
 
-const char* atransport::connection_state_name() const {
+const std::string atransport::connection_state_name() const {
     switch (connection_state) {
-    case kCsOffline: return "offline";
-    case kCsBootloader: return "bootloader";
-    case kCsDevice: return "device";
-    case kCsHost: return "host";
-    case kCsRecovery: return "recovery";
-    case kCsNoPerm: return "no permissions";
-    case kCsSideload: return "sideload";
-    case kCsUnauthorized: return "unauthorized";
-    default: return "unknown";
+        case kCsOffline: return "offline";
+        case kCsBootloader: return "bootloader";
+        case kCsDevice: return "device";
+        case kCsHost: return "host";
+        case kCsRecovery: return "recovery";
+        case kCsNoPerm: {
+            std::string message = UsbNoPermissionsShortHelpText();
+            return message.empty() ? "no permissions" : message;
+        }
+        case kCsSideload: return "sideload";
+        case kCsUnauthorized: return "unauthorized";
+        default: return "unknown";
     }
 }
 
@@ -866,7 +873,8 @@
         *result += '\t';
         *result += t->connection_state_name();
     } else {
-        android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name());
+        android::base::StringAppendF(result, "%-22s %s", serial,
+                                     t->connection_state_name().c_str());
 
         append_transport_info(result, "", t->devpath, false);
         append_transport_info(result, "product:", t->product, false);
diff --git a/adb/transport.h b/adb/transport.h
index d9845b6..76d6afa 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -90,7 +90,7 @@
     fdevent auth_fde;
     size_t failed_auth_attempts = 0;
 
-    const char* connection_state_name() const;
+    const std::string connection_state_name() const;
 
     void update_version(int version, size_t payload);
     int get_protocol_version() const;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 2c1a71d..d2a375a 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -143,7 +143,8 @@
 static void *server_socket_thread(void * arg)
 {
     int serverfd, fd;
-    struct sockaddr addr;
+    sockaddr_storage ss;
+    sockaddr *addrp = reinterpret_cast<sockaddr*>(&ss);
     socklen_t alen;
     int port = (int) (uintptr_t) arg;
 
@@ -162,9 +163,9 @@
             close_on_exec(serverfd);
         }
 
-        alen = sizeof(addr);
+        alen = sizeof(ss);
         D("server: trying to get new connection from %d", port);
-        fd = adb_socket_accept(serverfd, &addr, &alen);
+        fd = adb_socket_accept(serverfd, addrp, &alen);
         if(fd >= 0) {
             D("server: new connection on fd %d", fd);
             close_on_exec(fd);
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index ed5d2d67..e887a94 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -22,6 +22,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <grp.h>
 #include <linux/usb/ch9.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/version.h>
@@ -595,3 +596,54 @@
         fatal_errno("cannot create device_poll thread");
     }
 }
+
+static const char kPermissionsHelpUrl[] = "developer.android.com/tools/device.html";
+
+// Returns a message describing any potential problems we find with udev, or nullptr if we can't
+// find plugdev information (i.e. udev is not installed).
+static const char* GetUdevProblem() {
+    errno = 0;
+    group* plugdev_group = getgrnam("plugdev");
+
+    if (plugdev_group == nullptr) {
+        if (errno != 0) {
+            D("failed to read plugdev group info: %s", strerror(errno));
+        }
+        // We can't give any generally useful advice here, just let the caller print the help URL.
+        return nullptr;
+    }
+
+    // getgroups(2) indicates that the group_member() may not check the egid so we check it
+    // additionally just to be sure.
+    if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
+        // The user is in plugdev so the problem is likely with the udev rules.
+        return "verify udev rules";
+    }
+    return "udev requires plugdev group membership";
+}
+
+// Short help text must be a single line, and will look something like:
+//   no permissions (reason); see <URL>
+std::string UsbNoPermissionsShortHelpText() {
+    std::string help_text = "no permissions";
+
+    const char* problem = GetUdevProblem();
+    if (problem != nullptr) {
+        help_text += android::base::StringPrintf(" (%s)", problem);
+    }
+
+    return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
+}
+
+// Long help text can span multiple lines and should provide more detailed information.
+std::string UsbNoPermissionsLongHelpText() {
+    std::string header = "USB permission failure";
+
+    const char* problem = GetUdevProblem();
+    if (problem != nullptr) {
+        header += android::base::StringPrintf(": %s", problem);
+    }
+
+    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
+                                       header.c_str(), kPermissionsHelpUrl);
+}
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index ceed8fa..c5e7452 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -571,3 +571,12 @@
 {
     h->kick(h);
 }
+
+// kCsNoPerm is a host-side issue, we can just ignore it here.
+std::string UsbNoPermissionsShortHelpText() {
+    return "";
+}
+
+std::string UsbNoPermissionsLongHelpText() {
+    return "";
+}
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 148be1d..f494795 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -552,3 +552,12 @@
         handle->interface = 0;
     }
 }
+
+// kCsNoPerm is Linux-only.
+std::string UsbNoPermissionsShortHelpText() {
+    return "";
+}
+
+std::string UsbNoPermissionsLongHelpText() {
+    return "";
+}
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 8d3501e..9124685 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -659,3 +659,12 @@
   }
   adb_mutex_unlock(&usb_lock);
 }
+
+// kCsNoPerm is Linux-only.
+std::string UsbNoPermissionsShortHelpText() {
+    return "";
+}
+
+std::string UsbNoPermissionsLongHelpText() {
+    return "";
+}
diff --git a/base/include/android-base b/base/include/android-base
deleted file mode 120000
index 8681f8b..0000000
--- a/base/include/android-base
+++ /dev/null
@@ -1 +0,0 @@
-base
\ No newline at end of file
diff --git a/base/include/base/file.h b/base/include/android-base/file.h
similarity index 100%
rename from base/include/base/file.h
rename to base/include/android-base/file.h
diff --git a/base/include/base/logging.h b/base/include/android-base/logging.h
similarity index 100%
rename from base/include/base/logging.h
rename to base/include/android-base/logging.h
diff --git a/base/include/base/macros.h b/base/include/android-base/macros.h
similarity index 100%
rename from base/include/base/macros.h
rename to base/include/android-base/macros.h
diff --git a/base/include/base/memory.h b/base/include/android-base/memory.h
similarity index 100%
rename from base/include/base/memory.h
rename to base/include/android-base/memory.h
diff --git a/base/include/base/parseint.h b/base/include/android-base/parseint.h
similarity index 100%
rename from base/include/base/parseint.h
rename to base/include/android-base/parseint.h
diff --git a/base/include/base/stringprintf.h b/base/include/android-base/stringprintf.h
similarity index 100%
rename from base/include/base/stringprintf.h
rename to base/include/android-base/stringprintf.h
diff --git a/base/include/base/strings.h b/base/include/android-base/strings.h
similarity index 100%
rename from base/include/base/strings.h
rename to base/include/android-base/strings.h
diff --git a/base/include/base/test_utils.h b/base/include/android-base/test_utils.h
similarity index 100%
rename from base/include/base/test_utils.h
rename to base/include/android-base/test_utils.h
diff --git a/base/include/base/unique_fd.h b/base/include/android-base/unique_fd.h
similarity index 100%
rename from base/include/base/unique_fd.h
rename to base/include/android-base/unique_fd.h
diff --git a/base/include/base/utf8.h b/base/include/android-base/utf8.h
similarity index 100%
rename from base/include/base/utf8.h
rename to base/include/android-base/utf8.h
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 2a9d1d3..b3fdcb4 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -47,7 +47,6 @@
 const char kDefaultLogConfig[] = "/etc/crash_reporter_logs.conf";
 const char kDefaultUserName[] = "chronos";
 const char kLeaveCoreFile[] = "/data/misc/crash_reporter/.leave_core";
-const char kLsbRelease[] = "/etc/lsb-release";
 const char kShellPath[] = "/system/bin/sh";
 const char kSystemCrashPath[] = "/data/misc/crash_reporter/crash";
 const char kUploadVarPrefix[] = "upload_var_";
@@ -90,8 +89,7 @@
 using base::StringPrintf;
 
 CrashCollector::CrashCollector()
-    : lsb_release_(kLsbRelease),
-      log_config_path_(kDefaultLogConfig) {
+    : log_config_path_(kDefaultLogConfig) {
 }
 
 CrashCollector::~CrashCollector() {
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
index cfd76fd..24cbfb3 100644
--- a/crash_reporter/crash_collector.h
+++ b/crash_reporter/crash_collector.h
@@ -158,7 +158,6 @@
   IsFeedbackAllowedFunction is_feedback_allowed_function_;
   std::string extra_metadata_;
   base::FilePath forced_crash_directory_;
-  std::string lsb_release_;
   base::FilePath log_config_path_;
 
  private:
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index d00a5b5..b55c324 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -177,15 +177,8 @@
 TEST_F(CrashCollectorTest, MetaData) {
   const char kMetaFileBasename[] = "generated.meta";
   FilePath meta_file = test_dir_.Append(kMetaFileBasename);
-  FilePath lsb_release = test_dir_.Append("lsb-release");
   FilePath payload_file = test_dir_.Append("payload-file");
   std::string contents;
-  collector_.lsb_release_ = lsb_release.value();
-  const char kLsbContents[] =
-      "CHROMEOS_RELEASE_BOARD=lumpy\n"
-      "CHROMEOS_RELEASE_VERSION=6727.0.2015_01_26_0853\n"
-      "CHROMEOS_RELEASE_NAME=Chromium OS\n";
-  ASSERT_TRUE(base::WriteFile(lsb_release, kLsbContents, strlen(kLsbContents)));
   const char kPayload[] = "foo";
   ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
   collector_.AddCrashMetaData("foo", "bar");
@@ -194,7 +187,6 @@
   const char kExpectedMeta[] =
       "foo=bar\n"
       "exec_name=kernel\n"
-      "ver=6727.0.2015_01_26_0853\n"
       "payload=test/payload-file\n"
       "payload_size=3\n"
       "done=1\n";
diff --git a/crash_reporter/crash_reporter_logs_test.cc b/crash_reporter/crash_reporter_logs_test.cc
index e778002..77f5a7f 100644
--- a/crash_reporter/crash_reporter_logs_test.cc
+++ b/crash_reporter/crash_reporter_logs_test.cc
@@ -23,10 +23,11 @@
 namespace {
 
 // Name of the checked-in configuration file containing log-collection commands.
-const char kConfigFile[] = "crash_reporter_logs.conf";
+const char kConfigFile[] = "/system/etc/crash_reporter_logs.conf";
 
-// Executable name for Chrome. kConfigFile is expected to contain this entry.
-const char kChromeExecName[] = "chrome";
+// Signature name for crash_reporter user collection.
+// kConfigFile is expected to contain this entry.
+const char kUserCollectorSignature[] = "crash_reporter-user-collection";
 
 }  // namespace
 
@@ -35,6 +36,6 @@
   brillo::KeyValueStore store;
   ASSERT_TRUE(store.Load(base::FilePath(kConfigFile)));
   std::string command;
-  EXPECT_TRUE(store.GetString(kChromeExecName, &command));
+  EXPECT_TRUE(store.GetString(kUserCollectorSignature, &command));
   EXPECT_FALSE(command.empty());
 }
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
index cdb0ae7..015f624 100644
--- a/crash_reporter/kernel_collector_test.cc
+++ b/crash_reporter/kernel_collector_test.cc
@@ -253,15 +253,6 @@
   ASSERT_EQ(0, s_crashes);
 }
 
-TEST_F(KernelCollectorTest, CollectBadDirectory) {
-  WriteStringToFile(kcrash_file(), "====1.1\nsomething");
-  ASSERT_TRUE(collector_.Collect());
-  ASSERT_TRUE(FindLog("Unable to create appropriate crash directory"))
-      << "Did not find expected error string in log: {\n"
-      << GetLog() << "}";
-  ASSERT_EQ(1, s_crashes);
-}
-
 void KernelCollectorTest::SetUpSuccessfulCollect() {
   collector_.ForceCrashDirectory(test_crash_directory());
   WriteStringToFile(kcrash_file(), "====1.1\nsomething");
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index 72e61e6..638ea34 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -37,11 +37,6 @@
 
 const char kFilePath[] = "/my/path";
 
-// Keep in sync with UserCollector::ShouldDump.
-const char kChromeIgnoreMsg[] =
-    "ignoring call by kernel - chrome crash; "
-    "waiting for chrome to call us directly";
-
 void CountCrash() {
   ++s_crashes;
 }
@@ -167,24 +162,6 @@
   ASSERT_EQ(s_crashes, 1);
 }
 
-TEST_F(UserCollectorTest, HandleChromeCrashWithConsent) {
-  s_metrics = true;
-  collector_.HandleCrash("5:2:ignored", "chrome");
-  EXPECT_TRUE(FindLog(
-      "Received crash notification for chrome[5] sig 2"));
-  EXPECT_TRUE(FindLog(kChromeIgnoreMsg));
-  ASSERT_EQ(s_crashes, 0);
-}
-
-TEST_F(UserCollectorTest, HandleSuppliedChromeCrashWithConsent) {
-  s_metrics = true;
-  collector_.HandleCrash("0:2:chrome", nullptr);
-  EXPECT_TRUE(FindLog(
-      "Received crash notification for supplied_chrome[0] sig 2"));
-  EXPECT_TRUE(FindLog(kChromeIgnoreMsg));
-  ASSERT_EQ(s_crashes, 0);
-}
-
 TEST_F(UserCollectorTest, GetProcessPath) {
   FilePath path = collector_.GetProcessPath(100);
   ASSERT_EQ("/proc/100", path.value());
@@ -226,7 +203,7 @@
   pid_t my_pid = getpid();
   EXPECT_TRUE(collector_.GetExecutableBaseNameFromPid(my_pid, &base_name));
   EXPECT_FALSE(FindLog("Readlink failed"));
-  EXPECT_EQ("crash_reporter_test", base_name);
+  EXPECT_EQ("crash_reporter_tests", base_name);
 }
 
 TEST_F(UserCollectorTest, GetFirstLineWithPrefix) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 884d4d5..0afa895 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -518,11 +518,12 @@
   ALOGI("debuggerd: starting\n");
 
   for (;;) {
-    sockaddr addr;
-    socklen_t alen = sizeof(addr);
+    sockaddr_storage ss;
+    sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
+    socklen_t alen = sizeof(ss);
 
     ALOGV("waiting for connection\n");
-    int fd = accept(s, &addr, &alen);
+    int fd = accept(s, addrp, &alen);
     if (fd < 0) {
       ALOGV("accept failed: %s\n", strerror(errno));
       continue;
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index cc9f06c..1ab9436 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -279,6 +279,10 @@
             "                                           override the fs type and/or size\n"
             "                                           the bootloader reports.\n"
             "  getvar <variable>                        Display a bootloader variable.\n"
+            "  set_active <suffix>                      Sets the active slot. If slots are\n"
+            "                                           not supported, this does nothing.\n"
+            "                                           note: suffixes starting with a '-'\n"
+            "                                           must use set_active -- <suffix>\n"
             "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
             "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
             "                                           Create bootimage and flash it.\n"
@@ -321,7 +325,8 @@
             "  -a, --set-active[=<suffix>]              Sets the active slot. If no suffix is\n"
             "                                           provided, this will default to the value\n"
             "                                           given by --slot. If slots are not\n"
-            "                                           supported, this does nothing.\n"
+            "                                           supported, this does nothing. This will\n"
+            "                                           run after all non-reboot commands.\n"
             "  --unbuffered                             Do not buffer input or output.\n"
             "  --version                                Display version.\n"
             "  -h, --help                               show this message.\n"
@@ -724,9 +729,19 @@
     return android::base::Split(suffix_list, ",");
 }
 
-static std::string verify_slot(Transport* transport, const char *slot) {
+static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) {
     if (strcmp(slot, "all") == 0) {
-        return "all";
+        if (allow_all) {
+            return "all";
+        } else {
+            std::vector<std::string> suffixes = get_suffixes(transport);
+            if (!suffixes.empty()) {
+                return suffixes[0];
+            } else {
+                fprintf(stderr, "No known slots.\n");
+                exit(1);
+            }
+        }
     }
     std::vector<std::string> suffixes = get_suffixes(transport);
     for (const std::string &suffix : suffixes) {
@@ -740,6 +755,10 @@
     exit(1);
 }
 
+static std::string verify_slot(Transport* transport, const char *slot) {
+   return verify_slot(transport, slot, true);
+}
+
 static void do_for_partition(Transport* transport, const char *part, const char *slot,
                              std::function<void(const std::string&)> func, bool force_slot) {
     std::string has_slot;
@@ -1220,14 +1239,14 @@
     if (slot_override != "")
         slot_override = verify_slot(transport, slot_override.c_str());
     if (next_active != "")
-        next_active = verify_slot(transport, next_active.c_str());
+        next_active = verify_slot(transport, next_active.c_str(), false);
 
     if (wants_set_active) {
         if (next_active == "") {
             if (slot_override == "") {
                 wants_set_active = false;
             } else {
-                next_active = slot_override;
+                next_active = verify_slot(transport, slot_override.c_str(), false);
             }
         }
     }
@@ -1385,6 +1404,12 @@
                 do_update(transport, "update.zip", slot_override.c_str(), erase_first);
                 skip(1);
             }
+            wants_reboot = 1;
+        } else if(!strcmp(*argv, "set_active")) {
+            require(2);
+            std::string slot = verify_slot(transport, argv[1], false);
+            fb_set_active(slot.c_str());
+            skip(2);
             wants_reboot = true;
         } else if(!strcmp(*argv, "oem")) {
             argc = do_oem_command(argc, argv);
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 928d56c..b5141c9 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -254,7 +254,7 @@
         res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
                     mode_flag);
     } else {
-        res = strlcpy(buf, params->table, bufsize);
+        res = snprintf(buf, bufsize, "%s 1 " VERITY_TABLE_OPT_IGNZERO, params->table);
     }
 
     if (res < 0 || (size_t)res >= bufsize) {
@@ -695,31 +695,27 @@
     int match = 0;
     off64_t offset = 0;
 
+    /* unless otherwise specified, use EIO mode */
+    *mode = VERITY_MODE_EIO;
+
     /* use the kernel parameter if set */
     property_get("ro.boot.veritymode", propbuf, "");
 
     if (*propbuf != '\0') {
         if (!strcmp(propbuf, "enforcing")) {
             *mode = VERITY_MODE_DEFAULT;
-            return 0;
-        } else if (!strcmp(propbuf, "logging")) {
-            *mode = VERITY_MODE_LOGGING;
-            return 0;
-        } else {
-            INFO("Unknown value %s for veritymode; ignoring", propbuf);
         }
+        return 0;
     }
 
     if (get_verity_state_offset(fstab, &offset) < 0) {
         /* fall back to stateless behavior */
-        *mode = VERITY_MODE_EIO;
         return 0;
     }
 
     if (was_verity_restart()) {
         /* device was restarted after dm-verity detected a corrupted
-         * block, so switch to logging mode */
-        *mode = VERITY_MODE_LOGGING;
+         * block, so use EIO mode */
         return write_verity_state(fstab->verity_loc, offset, *mode);
     }
 
@@ -784,7 +780,6 @@
 int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
 {
     alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
-    bool use_state = true;
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
     char *mount_point;
     char propbuf[PROPERTY_VALUE_MAX];
@@ -793,15 +788,11 @@
     int i;
     int mode;
     int rc = -1;
-    off64_t offset = 0;
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
     struct fstab *fstab = NULL;
 
-    /* check if we need to store the state */
-    property_get("ro.boot.veritymode", propbuf, "");
-
-    if (*propbuf != '\0') {
-        use_state = false; /* state is kept by the bootloader */
+    if (!callback) {
+        return -1;
     }
 
     if (fs_mgr_load_verity_state(&mode) == -1) {
@@ -841,16 +832,7 @@
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
-        if (use_state && *status == 'C') {
-            if (write_verity_state(fstab->recs[i].verity_loc, offset,
-                    VERITY_MODE_LOGGING) < 0) {
-                continue;
-            }
-        }
-
-        if (callback) {
-            callback(&fstab->recs[i], mount_point, mode, *status);
-        }
+        callback(&fstab->recs[i], mount_point, mode, *status);
     }
 
     rc = 0;
@@ -962,13 +944,43 @@
 
     // load the verity mapping table
     if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
-            format_verity_table) < 0 &&
-        // try the legacy format for backwards compatibility
-        load_verity_table(io, mount_point, verity.data_size, fd, &params,
-            format_legacy_verity_table) < 0) {
-        goto out;
+            format_verity_table) == 0) {
+        goto loaded;
     }
 
+    if (params.ecc.valid) {
+        // kernel may not support error correction, try without
+        INFO("Disabling error correction for %s\n", mount_point);
+        params.ecc.valid = false;
+
+        if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
+                format_verity_table) == 0) {
+            goto loaded;
+        }
+    }
+
+    // try the legacy format for backwards compatibility
+    if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
+            format_legacy_verity_table) == 0) {
+        goto loaded;
+    }
+
+    if (params.mode != VERITY_MODE_EIO) {
+        // as a last resort, EIO mode should always be supported
+        INFO("Falling back to EIO mode for %s\n", mount_point);
+        params.mode = VERITY_MODE_EIO;
+
+        if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
+                format_legacy_verity_table) == 0) {
+            goto loaded;
+        }
+    }
+
+    ERROR("Failed to load verity table for %s\n", mount_point);
+    goto out;
+
+loaded:
+
     // activate the device
     if (resume_verity_table(io, mount_point, fd) < 0) {
         goto out;
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 63904b6..0085a07 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -39,6 +39,7 @@
 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
 #define FAKE_BATTERY_CAPACITY 42
 #define FAKE_BATTERY_TEMPERATURE 424
+#define ALWAYS_PLUGGED_CAPACITY 100
 
 namespace android {
 
@@ -211,6 +212,15 @@
         mBatteryFixedTemperature :
         getIntField(mHealthdConfig->batteryTemperaturePath);
 
+    // For devices which do not have battery and are always plugged
+    // into power souce.
+    if (mAlwaysPluggedDevice) {
+        props.chargerAcOnline = true;
+        props.batteryPresent = true;
+        props.batteryStatus = BATTERY_STATUS_CHARGING;
+        props.batteryHealth = BATTERY_HEALTH_GOOD;
+    }
+
     const int SIZE = 128;
     char buf[SIZE];
     String8 btech;
@@ -593,8 +603,15 @@
         closedir(dir);
     }
 
-    if (!mChargerNames.size())
+    // This indicates that there is no charger driver registered.
+    // Typically the case for devices which do not have a battery and
+    // and are always plugged into AC mains.
+    if (!mChargerNames.size()) {
         KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
+        mBatteryFixedCapacity = ALWAYS_PLUGGED_CAPACITY;
+        mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
+        mAlwaysPluggedDevice = true;
+    }
     if (!mBatteryDevicePresent) {
         KLOG_WARNING(LOG_TAG, "No battery devices found\n");
         hc->periodic_chores_interval_fast = -1;
diff --git a/healthd/BatteryMonitor.h b/healthd/BatteryMonitor.h
index 3425f27..a61171f 100644
--- a/healthd/BatteryMonitor.h
+++ b/healthd/BatteryMonitor.h
@@ -46,6 +46,7 @@
     struct healthd_config *mHealthdConfig;
     Vector<String8> mChargerNames;
     bool mBatteryDevicePresent;
+    bool mAlwaysPluggedDevice;
     int mBatteryFixedCapacity;
     int mBatteryFixedTemperature;
     struct BatteryProperties props;
diff --git a/include/log/log.h b/include/log/log.h
index 086d742..619bf23 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -620,6 +620,8 @@
  */
 int __android_log_is_loggable(int prio, const char *tag, int default_prio);
 
+int __android_log_security(); /* Device Owner is present */
+
 int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
                               uint32_t dataLen);
 
diff --git a/include/nativeloader/native_loader.h b/include/nativeloader/native_loader.h
index 18b7ba4..e7c69d6 100644
--- a/include/nativeloader/native_loader.h
+++ b/include/nativeloader/native_loader.h
@@ -24,7 +24,7 @@
 
 __attribute__((visibility("default")))
 void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
-                        jobject class_loader, jstring library_path);
+                        jobject class_loader, jstring library_path, jstring permitted_path);
 
 };  // namespace android
 
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 58dbce1..10f9d81 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -642,7 +642,7 @@
 static int do_verity_load_state(const std::vector<std::string>& args) {
     int mode = -1;
     int rc = fs_mgr_load_verity_state(&mode);
-    if (rc == 0 && mode == VERITY_MODE_LOGGING) {
+    if (rc == 0 && mode != VERITY_MODE_DEFAULT) {
         ActionManager::GetInstance().QueueEventTrigger("verity-logging");
     }
     return rc;
diff --git a/init/init.cpp b/init/init.cpp
index 9f4f625..4aef823 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -350,6 +350,18 @@
     }
 }
 
+static void export_oem_lock_status() {
+    if (property_get("ro.oem_unlock_supported") != "1") {
+        return;
+    }
+
+    std::string value = property_get("ro.boot.verifiedbootstate");
+
+    if (!value.empty()) {
+        property_set("ro.boot.flash.locked", value == "orange" ? "0" : "1");
+    }
+}
+
 static void export_kernel_boot_props() {
     struct {
         const char *src_prop;
@@ -614,6 +626,7 @@
     signal_handler_init();
 
     property_load_boot_defaults();
+    export_oem_lock_status();
     start_property_service();
 
     const BuiltinFunctionMap function_map;
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 6e58233..806608e 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -60,35 +60,14 @@
 #define RECOVERY_MOUNT_POINT "/recovery"
 
 static int persistent_properties_loaded = 0;
-static bool property_area_initialized = false;
 
 static int property_set_fd = -1;
 
-struct workspace {
-    size_t size;
-    int fd;
-};
-
-static workspace pa_workspace;
-
 void property_init() {
-    if (property_area_initialized) {
-        return;
-    }
-
-    property_area_initialized = true;
-
     if (__system_property_area_init()) {
         ERROR("Failed to initialize property area\n");
         exit(1);
     }
-
-    pa_workspace.size = 0;
-    pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
-    if (pa_workspace.fd == -1) {
-        ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno));
-        return;
-    }
 }
 
 static int check_mac_perms(const char *name, char *sctx, struct ucred *cr)
@@ -354,12 +333,6 @@
     }
 }
 
-void get_property_workspace(int *fd, int *sz)
-{
-    *fd = pa_workspace.fd;
-    *sz = pa_workspace.size;
-}
-
 static void load_properties_from_file(const char *, const char *);
 
 /*
@@ -498,10 +471,6 @@
     load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
 }
 
-bool properties_initialized() {
-    return property_area_initialized;
-}
-
 static void load_override_properties() {
     if (ALLOW_LOCAL_PROP_OVERRIDE) {
         std::string debuggable = property_get("ro.debuggable");
diff --git a/init/property_service.h b/init/property_service.h
index 8b76d2b..dbaed34 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -32,10 +32,8 @@
 extern void load_persist_props(void);
 extern void load_system_props(void);
 extern void start_property_service(void);
-void get_property_workspace(int *fd, int *sz);
 std::string property_get(const char* name);
 extern int property_set(const char *name, const char *value);
-extern bool properties_initialized();
 
 
-#endif	/* _INIT_PROPERTY_H */
+#endif  /* _INIT_PROPERTY_H */
diff --git a/init/service.cpp b/init/service.cpp
index 1af3e60..40a4bc7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -76,11 +76,6 @@
 }
 
 void Service::NotifyStateChange(const std::string& new_state) const {
-    if (!properties_initialized()) {
-        // If properties aren't available yet, we can't set them.
-        return;
-    }
-
     if ((flags_ & SVC_EXEC) != 0) {
         // 'exec' commands don't have properties tracking their state.
         return;
@@ -400,14 +395,7 @@
 
     pid_t pid = fork();
     if (pid == 0) {
-        int fd, sz;
-
         umask(077);
-        if (properties_initialized()) {
-            get_property_workspace(&fd, &sz);
-            std::string tmp = StringPrintf("%d,%d", dup(fd), sz);
-            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp.c_str());
-        }
 
         for (const auto& ei : envvars_) {
             add_environment(ei.name.c_str(), ei.value.c_str());
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 9c6742e..5d3dd86 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -68,6 +68,7 @@
 # Use static llvm libraries on host to remove dependency on 32-bit llvm shared library
 # which is not included in the prebuilt.
 libbacktrace_static_libraries_host := \
+	libcutils \
 	libLLVMObject \
 	libLLVMBitReader \
 	libLLVMMC \
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index df94280..3c8f879 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -27,8 +27,6 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <cutils/threads.h>
-
 #include "BacktraceLog.h"
 #include "BacktraceOffline.h"
 #include "thread_utils.h"
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index d339550..8e22366 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -29,8 +29,6 @@
 #include <backtrace/Backtrace.h>
 #include <backtrace/BacktraceMap.h>
 
-#include <cutils/threads.h>
-
 #include "BacktraceCurrent.h"
 #include "BacktraceLog.h"
 #include "ThreadEntry.h"
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 27dfb83..abc186b 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -22,7 +22,9 @@
 }
 
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <ucontext.h>
 #include <unistd.h>
@@ -616,7 +618,30 @@
   return debug_frame;
 }
 
+static bool IsValidElfPath(const std::string& filename) {
+  static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
+
+  struct stat st;
+  if (stat(filename.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
+    return false;
+  }
+  FILE* fp = fopen(filename.c_str(), "reb");
+  if (fp == nullptr) {
+    return false;
+  }
+  char buf[4];
+  if (fread(buf, 4, 1, fp) != 1) {
+    fclose(fp);
+    return false;
+  }
+  fclose(fp);
+  return memcmp(buf, elf_magic, 4) == 0;
+}
+
 static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) {
+  if (!IsValidElfPath(filename)) {
+    return nullptr;
+  }
   auto owning_binary = llvm::object::createBinary(llvm::StringRef(filename));
   if (owning_binary.getError()) {
     return nullptr;
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
index df83581..9590657 100644
--- a/libbacktrace/thread_utils.h
+++ b/libbacktrace/thread_utils.h
@@ -19,6 +19,10 @@
 
 #include <unistd.h>
 
+#if !defined(__ANDROID__)
+#include <cutils/threads.h>
+#endif
+
 __BEGIN_DECLS
 
 int tgkill(int tgid, int tid, int sig);
diff --git a/libcutils/socket_inaddr_any_server.c b/libcutils/socket_inaddr_any_server.c
index 7f0ccb8..e1b7d84 100644
--- a/libcutils/socket_inaddr_any_server.c
+++ b/libcutils/socket_inaddr_any_server.c
@@ -34,21 +34,21 @@
 /* open listen() port on any interface */
 int socket_inaddr_any_server(int port, int type)
 {
-    struct sockaddr_in addr;
+    struct sockaddr_in6 addr;
     int s, n;
 
     memset(&addr, 0, sizeof(addr));
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(port);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addr.sin6_family = AF_INET6;
+    addr.sin6_port = htons(port);
+    addr.sin6_addr = in6addr_any;
 
-    s = socket(AF_INET, type, 0);
-    if(s < 0) return -1;
+    s = socket(AF_INET6, type, 0);
+    if (s < 0) return -1;
 
     n = 1;
     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
 
-    if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+    if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
         close(s);
         return -1;
     }
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 7fc01d9..b4711d2 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -42,9 +42,12 @@
 struct cache {
     const prop_info *pinfo;
     uint32_t serial;
-    char c;
+    unsigned char c;
 };
 
+#define BOOLEAN_TRUE 0xFF
+#define BOOLEAN_FALSE 0xFE
+
 static void refresh_cache(struct cache *cache, const char *key)
 {
     uint32_t serial;
@@ -62,7 +65,16 @@
     }
     cache->serial = serial;
     __system_property_read(cache->pinfo, 0, buf);
-    cache->c = buf[0];
+    switch(buf[0]) {
+    case 't': case 'T':
+        cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
+        break;
+    case 'f': case 'F':
+        cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
+        break;
+    default:
+        cache->c = buf[0];
+    }
 }
 
 static int __android_log_level(const char *tag, int default_prio)
@@ -147,6 +159,7 @@
     case 'F': /* Not officially supported */
     case 'A':
     case 'S':
+    case BOOLEAN_FALSE: /* Not officially supported */
         break;
     default:
         /* clear '.' after log.tag */
@@ -180,6 +193,7 @@
     case 'E': return ANDROID_LOG_ERROR;
     case 'F': /* FALLTHRU */ /* Not officially supported */
     case 'A': return ANDROID_LOG_FATAL;
+    case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
     case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
     }
     return default_prio;
@@ -226,3 +240,36 @@
 
     return (tolower(c) == 'm') ? CLOCK_MONOTONIC : CLOCK_REALTIME;
 }
+
+/*
+ * security state generally remains constant, since a change is
+ * rare, we can accept a trylock failure gracefully.
+ */
+static pthread_mutex_t lock_security = PTHREAD_MUTEX_INITIALIZER;
+
+int __android_log_security()
+{
+    static struct cache r_do_cache = { NULL, -1, BOOLEAN_FALSE };
+    static struct cache p_security_cache = { NULL, -1, BOOLEAN_FALSE };
+    int retval;
+
+    if (pthread_mutex_trylock(&lock_security)) {
+        /* We are willing to accept some race in this context */
+        retval = (r_do_cache.c != BOOLEAN_FALSE) && r_do_cache.c &&
+                 (p_security_cache.c == BOOLEAN_TRUE);
+    } else {
+        static uint32_t serial;
+        uint32_t current_serial = __system_property_area_serial();
+        if (current_serial != serial) {
+            refresh_cache(&r_do_cache, "ro.device_owner");
+            refresh_cache(&p_security_cache, "persist.logd.security");
+            serial = current_serial;
+        }
+        retval = (r_do_cache.c != BOOLEAN_FALSE) && r_do_cache.c &&
+                 (p_security_cache.c == BOOLEAN_TRUE);
+
+        pthread_mutex_unlock(&lock_security);
+    }
+
+    return retval;
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 110f1eb..597d8f6 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -164,6 +164,43 @@
     android_logger_list_close(logger_list);
 }
 
+TEST(liblog, __security) {
+    static const char persist_key[] = "persist.logd.security";
+    static const char readonly_key[] = "ro.device_owner";
+    static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
+    char persist[PROP_VALUE_MAX];
+    char readonly[PROP_VALUE_MAX];
+
+    property_get(persist_key, persist, "");
+    property_get(readonly_key, readonly, nothing_val);
+
+    if (!strcmp(readonly, nothing_val)) {
+        EXPECT_FALSE(__android_log_security());
+        fprintf(stderr, "Warning, setting ro.device_owner to a domain\n");
+        property_set(readonly_key, "com.google.android.SecOps.DeviceOwner");
+    } else if (!strcasecmp(readonly, "false") || !readonly[0]) {
+        EXPECT_FALSE(__android_log_security());
+        return;
+    }
+
+    if (!strcasecmp(persist, "true")) {
+        EXPECT_TRUE(__android_log_security());
+    } else {
+        EXPECT_FALSE(__android_log_security());
+    }
+    property_set(persist_key, "TRUE");
+    EXPECT_TRUE(__android_log_security());
+    property_set(persist_key, "FALSE");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, "true");
+    EXPECT_TRUE(__android_log_security());
+    property_set(persist_key, "false");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, "");
+    EXPECT_FALSE(__android_log_security());
+    property_set(persist_key, persist);
+}
+
 static unsigned signaled;
 log_time signal_time;
 
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 33870e2..cef2d75 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -28,8 +28,8 @@
 #include <string>
 #include <mutex>
 
-#include "base/macros.h"
-#include "base/strings.h"
+#include "android-base/macros.h"
+#include "android-base/strings.h"
 
 namespace android {
 
@@ -55,10 +55,18 @@
  public:
   LibraryNamespaces() : initialized_(false) { }
 
-  android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader, jstring library_path) {
-    ScopedUtfChars libraryPath(env, library_path);
+  android_namespace_t* GetOrCreate(JNIEnv* env, jobject class_loader,
+                                   jstring java_library_path,
+                                   jstring java_permitted_path) {
+    ScopedUtfChars library_path(env, java_library_path);
 
-    if (!initialized_ && !InitPublicNamespace(libraryPath.c_str())) {
+    std::string permitted_path;
+    if (java_permitted_path != nullptr) {
+      ScopedUtfChars path(env, java_permitted_path);
+      permitted_path = path.c_str();
+    }
+
+    if (!initialized_ && !InitPublicNamespace(library_path.c_str())) {
       return nullptr;
     }
 
@@ -73,8 +81,11 @@
     android_namespace_t* ns =
             android_create_namespace("classloader-namespace",
                                      nullptr,
-                                     libraryPath.c_str(),
-                                     true);
+                                     library_path.c_str(),
+                                     true,
+                                     java_permitted_path != nullptr ?
+                                        permitted_path.c_str() :
+                                        nullptr);
 
     namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
 
@@ -118,13 +129,16 @@
 
 
 void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
-                        jobject class_loader, jstring library_path) {
+                        jobject class_loader, jstring java_library_path,
+                        jstring java_permitted_path) {
 #if defined(__ANDROID__)
   if (target_sdk_version == 0 || class_loader == nullptr) {
     return dlopen(path, RTLD_NOW);
   }
 
-  android_namespace_t* ns = g_namespaces->GetOrCreate(env, class_loader, library_path);
+  android_namespace_t* ns =
+      g_namespaces->GetOrCreate(env, class_loader, java_library_path,
+                                java_permitted_path);
 
   if (ns == nullptr) {
     return nullptr;
@@ -136,7 +150,8 @@
 
   return android_dlopen_ext(path, RTLD_NOW, &extinfo);
 #else
-  UNUSED(env, target_sdk_version, class_loader, library_path);
+  UNUSED(env, target_sdk_version, class_loader,
+         java_library_path, java_permitted_path);
   return dlopen(path, RTLD_NOW);
 #endif
 }
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 3011ed7..168899c 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -199,13 +199,14 @@
             continue;
         }
         if (mListen && FD_ISSET(mSock, &read_fds)) {
-            struct sockaddr addr;
+            sockaddr_storage ss;
+            sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
             socklen_t alen;
             int c;
 
             do {
-                alen = sizeof(addr);
-                c = accept(mSock, &addr, &alen);
+                alen = sizeof(ss);
+                c = accept(mSock, addrp, &alen);
                 SLOGV("%s got %d from accept", mSocketName, c);
             } while (c < 0 && errno == EINTR);
             if (c < 0) {
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 7bbc811..50bf6a4 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -410,7 +410,8 @@
 }
 
 static void ctrl_connect_handler(uint32_t events __unused) {
-    struct sockaddr addr;
+    struct sockaddr_storage ss;
+    struct sockaddr *addrp = (struct sockaddr *)&ss;
     socklen_t alen;
     struct epoll_event epev;
 
@@ -419,8 +420,8 @@
         ctrl_dfd_reopened = 1;
     }
 
-    alen = sizeof(addr);
-    ctrl_dfd = accept(ctrl_lfd, &addr, &alen);
+    alen = sizeof(ss);
+    ctrl_dfd = accept(ctrl_lfd, addrp, &alen);
 
     if (ctrl_dfd < 0) {
         ALOGE("lmkd control socket accept failed; errno=%d", errno);
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 839ab65..3553753 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -146,9 +146,7 @@
 LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
 LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
 LOCAL_INIT_RC := metrics_collector.rc
-LOCAL_REQUIRED_MODULES := \
-  metrics.json \
-  metrics.schema.json
+LOCAL_REQUIRED_MODULES := metrics.json
 LOCAL_RTTI_FLAG := -frtti
 LOCAL_SHARED_LIBRARIES := $(metrics_collector_shared_libraries)
 LOCAL_SRC_FILES := $(metrics_collector_common) \
@@ -207,13 +205,6 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := metrics.json
 LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/commands
-LOCAL_SRC_FILES := etc/weaved/commands/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := metrics.schema.json
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/states
-LOCAL_SRC_FILES := etc/weaved/states/$(LOCAL_MODULE)
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/weaved/traits
+LOCAL_SRC_FILES := etc/weaved/traits/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
diff --git a/metricsd/etc/weaved/commands/metrics.json b/metricsd/etc/weaved/commands/metrics.json
deleted file mode 100644
index b7f32d5..0000000
--- a/metricsd/etc/weaved/commands/metrics.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "_metrics": {
-    "_enableAnalyticsReporting": {
-      "minimalRole": "manager"
-    },
-    "_disableAnalyticsReporting": {
-      "minimalRole": "manager"
-    }
-  }
-}
diff --git a/metricsd/etc/weaved/states/metrics.schema.json b/metricsd/etc/weaved/states/metrics.schema.json
deleted file mode 100644
index 130ac46..0000000
--- a/metricsd/etc/weaved/states/metrics.schema.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "_metrics": {
-    "_AnalyticsReportingState": {
-      "enum": ["enabled", "disabled"],
-      "default": "disabled"
-    }
-  }
-}
diff --git a/metricsd/etc/weaved/traits/metrics.json b/metricsd/etc/weaved/traits/metrics.json
new file mode 100644
index 0000000..7d17c77
--- /dev/null
+++ b/metricsd/etc/weaved/traits/metrics.json
@@ -0,0 +1,18 @@
+{
+  "_metrics": {
+    "commands": {
+      "_enableAnalyticsReporting": {
+        "minimalRole": "manager"
+      },
+      "_disableAnalyticsReporting": {
+        "minimalRole": "manager"
+      }
+    },
+    "state": {
+      "_AnalyticsReportingState": {
+        "type": "string",
+        "enum": [ "enabled", "disabled" ]
+      }
+    }
+  }
+}
diff --git a/metricsd/metrics_collector.cc b/metricsd/metrics_collector.cc
index 28f9ad3..5468b9f 100644
--- a/metricsd/metrics_collector.cc
+++ b/metricsd/metrics_collector.cc
@@ -40,8 +40,6 @@
 using base::TimeDelta;
 using base::TimeTicks;
 using chromeos_metrics::PersistentInteger;
-using com::android::Weave::CommandProxy;
-using com::android::Weave::ManagerProxy;
 using std::map;
 using std::string;
 using std::vector;
@@ -73,6 +71,8 @@
 const char kMeminfoFileName[] = "/proc/meminfo";
 const char kVmStatFileName[] = "/proc/vmstat";
 
+const char kWeaveComponent[] = "metrics";
+
 }  // namespace
 
 // Zram sysfs entries.
@@ -248,10 +248,13 @@
   device_ = weaved::Device::CreateInstance(
       bus_,
       base::Bind(&MetricsCollector::UpdateWeaveState, base::Unretained(this)));
+  device_->AddComponent(kWeaveComponent, {"_metrics"});
   device_->AddCommandHandler(
+      kWeaveComponent,
       "_metrics._enableAnalyticsReporting",
       base::Bind(&MetricsCollector::OnEnableMetrics, base::Unretained(this)));
   device_->AddCommandHandler(
+      kWeaveComponent,
       "_metrics._disableAnalyticsReporting",
       base::Bind(&MetricsCollector::OnDisableMetrics, base::Unretained(this)));
 
@@ -326,12 +329,13 @@
   if (!device_)
     return;
 
-  brillo::VariantDictionary state_change{
-    { "_metrics._AnalyticsReportingState",
-      metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled" }
-  };
+  std::string enabled =
+      metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled";
 
-  if (!device_->SetStateProperties(state_change, nullptr)) {
+  if (!device_->SetStateProperty(kWeaveComponent,
+                                 "_metrics._AnalyticsReportingState",
+                                 enabled,
+                                 nullptr)) {
     LOG(ERROR) << "failed to update weave's state";
   }
 }
diff --git a/metricsd/uploader/bn_metricsd_impl.cc b/metricsd/uploader/bn_metricsd_impl.cc
index 113a705..2cbc2da 100644
--- a/metricsd/uploader/bn_metricsd_impl.cc
+++ b/metricsd/uploader/bn_metricsd_impl.cc
@@ -21,6 +21,7 @@
 #include <base/metrics/statistics_recorder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <utils/Errors.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 
@@ -33,11 +34,14 @@
 
 BnMetricsdImpl::BnMetricsdImpl(const std::shared_ptr<CrashCounters>& counters)
     : counters_(counters) {
-  CHECK(counters_);
+  CHECK(counters_) << "Invalid counters argument to constructor";
 }
 
 void BnMetricsdImpl::Run() {
-  android::defaultServiceManager()->addService(getInterfaceDescriptor(), this);
+  android::status_t status =
+      android::defaultServiceManager()->addService(getInterfaceDescriptor(),
+                                                   this);
+  CHECK(status == android::OK) << "Metricsd service registration failed";
   android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
   android::IPCThreadState::self()->disableBackgroundScheduling(true);
   android::IPCThreadState::self()->joinThreadPool();
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a0b1acf..011defb 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -138,23 +138,27 @@
     # sets up initial cpusets for ActivityManager
     mkdir /dev/cpuset
     mount cpuset none /dev/cpuset
-    mkdir /dev/cpuset/foreground
-    mkdir /dev/cpuset/foreground/boost
-    mkdir /dev/cpuset/background
-    # system-background is for system tasks that should only run on
-    # little cores, not on bigs
-    # to be used only by init, so don't change the permissions
-    mkdir /dev/cpuset/system-background
+
     # this ensures that the cpusets are present and usable, but the device's
     # init.rc must actually set the correct cpus
+    mkdir /dev/cpuset/foreground
     write /dev/cpuset/foreground/cpus 0
-    write /dev/cpuset/foreground/boost/cpus 0
-    write /dev/cpuset/background/cpus 0
-    write /dev/cpuset/system-background/cpus 0
     write /dev/cpuset/foreground/mems 0
+    mkdir /dev/cpuset/foreground/boost
+    write /dev/cpuset/foreground/boost/cpus 0
     write /dev/cpuset/foreground/boost/mems 0
+    mkdir /dev/cpuset/background
+    write /dev/cpuset/background/cpus 0
     write /dev/cpuset/background/mems 0
+
+    # system-background is for system tasks that should only run on
+    # little cores, not on bigs
+    # to be used only by init, so don't change system-bg permissions
+    mkdir /dev/cpuset/system-background
+    write /dev/cpuset/system-background/cpus 0
     write /dev/cpuset/system-background/mems 0
+
+    # change permissions for all cpusets we'll touch at runtime
     chown system system /dev/cpuset
     chown system system /dev/cpuset/foreground
     chown system system /dev/cpuset/foreground/boost
@@ -244,6 +248,9 @@
     # Mount default storage into root namespace
     mount none /mnt/runtime/default /storage slave bind rec
 
+    # Make sure /sys/kernel/debug (if present) is labeled properly
+    restorecon_recursive /sys/kernel/debug
+
     # We chown/chmod /cache again so because mount is run as root + defaults
     chown system cache /cache
     chmod 0770 /cache
@@ -486,6 +493,8 @@
     class_start core
 
 on nonencrypted
+    # A/B update verifier that marks a successful boot.
+    exec - root -- /system/bin/update_verifier nonencrypted
     class_start main
     class_start late_start
 
@@ -514,9 +523,13 @@
     trigger post-fs-data
 
 on property:vold.decrypt=trigger_restart_min_framework
+    # A/B update verifier that marks a successful boot.
+    exec - root -- /system/bin/update_verifier trigger_restart_min_framework
     class_start main
 
 on property:vold.decrypt=trigger_restart_framework
+    # A/B update verifier that marks a successful boot.
+    exec - root -- /system/bin/update_verifier trigger_restart_framework
     class_start main
     class_start late_start