Merge "Revert "STOPSHIP: Additional Wifi logging temporarily disabled""
diff --git a/adb/Android.mk b/adb/Android.mk
index d120f0a..6951904 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -69,6 +69,8 @@
     qemu_tracing.cpp \
     usb_linux_client.cpp \
 
+LOCAL_SHARED_LIBRARIES := libbase
+
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
@@ -80,6 +82,8 @@
     $(LIBADB_$(HOST_OS)_SRC_FILES) \
     adb_auth_host.cpp \
 
+LOCAL_SHARED_LIBRARIES := libbase
+
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the SSL includes to our path.
 LOCAL_STATIC_LIBRARIES := libcrypto_static
diff --git a/adb/adb.cpp b/adb/adb.cpp
index b09e853..de82cd4 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -32,6 +32,8 @@
 
 #include <string>
 
+#include <base/stringprintf.h>
+
 #include "adb_auth.h"
 #include "adb_io.h"
 #include "adb_listeners.h"
@@ -802,7 +804,6 @@
     if (!strncmp(service, "forward:",8) ||
         !strncmp(service, "killforward:",12)) {
         char *local, *remote;
-        int r;
         atransport *transport;
 
         int createForward = strncmp(service, "kill", 4);
@@ -845,12 +846,13 @@
             return 1;
         }
 
+        install_status_t r;
         if (createForward) {
             r = install_listener(local, remote, transport, no_rebind);
         } else {
             r = remove_listener(local, transport);
         }
-        if(r == 0) {
+        if (r == INSTALL_STATUS_OK) {
 #if ADB_HOST
             /* On the host: 1st OKAY is connect, 2nd OKAY is status */
             WriteFdExactly(reply_fd, "OKAY", 4);
@@ -859,22 +861,19 @@
             return 1;
         }
 
-        if (createForward) {
-            const char* message;
-            switch (r) {
-              case INSTALL_STATUS_CANNOT_BIND:
-                message = "cannot bind to socket";
-                break;
-              case INSTALL_STATUS_CANNOT_REBIND:
-                message = "cannot rebind existing socket";
-                break;
-              default:
-                message = "internal error";
-            }
-            sendfailmsg(reply_fd, message);
-        } else {
-            sendfailmsg(reply_fd, "cannot remove listener");
+        std::string message;
+        switch (r) {
+          case INSTALL_STATUS_OK: message = " "; break;
+          case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
+          case INSTALL_STATUS_CANNOT_BIND:
+            message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_CANNOT_REBIND:
+            message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno));
+            break;
+          case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
         }
+        sendfailmsg(reply_fd, message.c_str());
         return 1;
     }
     return 0;
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 84b9c64..a1a5ddb 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -190,17 +190,17 @@
     return result;
 }
 
-int remove_listener(const char *local_name, atransport* transport)
+install_status_t remove_listener(const char *local_name, atransport* transport)
 {
     alistener *l;
 
     for (l = listener_list.next; l != &listener_list; l = l->next) {
         if (!strcmp(local_name, l->local_name)) {
             listener_disconnect(l, l->transport);
-            return 0;
+            return INSTALL_STATUS_OK;
         }
     }
-    return -1;
+    return INSTALL_STATUS_LISTENER_NOT_FOUND;
 }
 
 void remove_all_listeners(void)
@@ -268,10 +268,10 @@
 
     listener->fd = local_name_to_fd(local_name);
     if (listener->fd < 0) {
+        printf("cannot bind '%s': %s\n", local_name, strerror(errno));
         free(listener->local_name);
         free(listener->connect_to);
         free(listener);
-        printf("cannot bind '%s'\n", local_name);
         return INSTALL_STATUS_CANNOT_BIND;
     }
 
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 6421df1..f55fdee 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -25,6 +25,7 @@
   INSTALL_STATUS_INTERNAL_ERROR = -1,
   INSTALL_STATUS_CANNOT_BIND = -2,
   INSTALL_STATUS_CANNOT_REBIND = -3,
+  INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
 };
 
 extern alistener listener_list;
@@ -40,7 +41,7 @@
 
 int format_listeners(char* buf, size_t buflen);
 
-int remove_listener(const char *local_name, atransport* transport);
+install_status_t remove_listener(const char* local_name, atransport* transport);
 void remove_all_listeners(void);
 
 #endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 710ef3c..f10c143 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -35,19 +35,18 @@
   return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode);
 }
 
-static bool should_escape(const char c) {
-  return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
-}
-
 std::string escape_arg(const std::string& s) {
-  // Preserve empty arguments.
-  if (s.empty()) return "\"\"";
+  std::string result = s;
 
-  std::string result(s);
+  // Insert a \ before any ' in the string.
   for (auto it = result.begin(); it != result.end(); ++it) {
-      if (should_escape(*it)) {
+      if (*it == '\'') {
           it = result.insert(it, '\\') + 1;
       }
   }
+
+  // Prefix and suffix the whole string with '.
+  result.insert(result.begin(), '\'');
+  result.push_back('\'');
   return result;
 }
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 95e28a8..a395079 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -25,28 +25,28 @@
 }
 
 TEST(adb_utils, escape_arg) {
-  ASSERT_EQ(R"("")", escape_arg(""));
+  ASSERT_EQ(R"('')", escape_arg(""));
 
-  ASSERT_EQ(R"(abc)", escape_arg("abc"));
+  ASSERT_EQ(R"('abc')", escape_arg("abc"));
 
-  ASSERT_EQ(R"(\ abc)", escape_arg(" abc"));
-  ASSERT_EQ(R"(\'abc)", escape_arg("'abc"));
-  ASSERT_EQ(R"(\"abc)", escape_arg("\"abc"));
-  ASSERT_EQ(R"(\\abc)", escape_arg("\\abc"));
-  ASSERT_EQ(R"(\(abc)", escape_arg("(abc"));
-  ASSERT_EQ(R"(\)abc)", escape_arg(")abc"));
+  ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
+  ASSERT_EQ(R"('\'abc')", escape_arg("'abc"));
+  ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
+  ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
+  ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
+  ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
 
-  ASSERT_EQ(R"(abc\ abc)", escape_arg("abc abc"));
-  ASSERT_EQ(R"(abc\'abc)", escape_arg("abc'abc"));
-  ASSERT_EQ(R"(abc\"abc)", escape_arg("abc\"abc"));
-  ASSERT_EQ(R"(abc\\abc)", escape_arg("abc\\abc"));
-  ASSERT_EQ(R"(abc\(abc)", escape_arg("abc(abc"));
-  ASSERT_EQ(R"(abc\)abc)", escape_arg("abc)abc"));
+  ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
+  ASSERT_EQ(R"('abc\'abc')", escape_arg("abc'abc"));
+  ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
+  ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
+  ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
+  ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
 
-  ASSERT_EQ(R"(abc\ )", escape_arg("abc "));
-  ASSERT_EQ(R"(abc\')", escape_arg("abc'"));
-  ASSERT_EQ(R"(abc\")", escape_arg("abc\""));
-  ASSERT_EQ(R"(abc\\)", escape_arg("abc\\"));
-  ASSERT_EQ(R"(abc\()", escape_arg("abc("));
-  ASSERT_EQ(R"(abc\))", escape_arg("abc)"));
+  ASSERT_EQ(R"('abc ')", escape_arg("abc "));
+  ASSERT_EQ(R"('abc\'')", escape_arg("abc'"));
+  ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
+  ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
+  ASSERT_EQ(R"('abc(')", escape_arg("abc("));
+  ASSERT_EQ(R"('abc)')", escape_arg("abc)"));
 }
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index f193d2f..e59a96a 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -312,6 +312,7 @@
 static void copy_to_file(int inFd, int outFd) {
     const size_t BUFSIZE = 32 * 1024;
     char* buf = (char*) malloc(BUFSIZE);
+    if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
     int len;
     long total = 0;
 
@@ -419,6 +420,11 @@
     fdi = 0; //dup(0);
 
     int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2));
+    if (fds == nullptr) {
+        fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno));
+        return 1;
+    }
+
     fds[0] = fd;
     fds[1] = fdi;
 
@@ -764,8 +770,7 @@
         cmd += " " + escape_arg(*argv++);
     }
 
-    send_shell_command(transport, serial, cmd);
-    return 0;
+    return send_shell_command(transport, serial, cmd);
 }
 
 static int mkdirs(const char *path)
@@ -1457,27 +1462,27 @@
         return uninstall_app(ttype, serial, argc, argv);
     }
     else if (!strcmp(argv[0], "sync")) {
-        std::string src_arg;
+        std::string src;
         bool list_only = false;
         if (argc < 2) {
             // No local path was specified.
-            src_arg = "";
+            src = "";
         } else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
-            list_only = 1;
+            list_only = true;
             if (argc == 3) {
-                src_arg = argv[2];
+                src = argv[2];
             } else {
-                src_arg = "";
+                src = "";
             }
         } else if (argc == 2) {
             // A local path or "android"/"data" arg was specified.
-            src_arg = argv[1];
+            src = argv[1];
         } else {
             return usage();
         }
 
-        if (src_arg != "" &&
-            src_arg != "system" && src_arg != "data" && src_arg != "vendor" && src_arg != "oem") {
+        if (src != "" &&
+            src != "system" && src != "data" && src != "vendor" && src != "oem") {
             return usage();
         }
 
@@ -1485,25 +1490,19 @@
         std::string data_src_path = product_file("data");
         std::string vendor_src_path = product_file("vendor");
         std::string oem_src_path = product_file("oem");
-        if (!directory_exists(vendor_src_path)) {
-            vendor_src_path = "";
-        }
-        if (!directory_exists(oem_src_path)) {
-            oem_src_path = "";
-        }
 
         int rc = 0;
-        if (rc == 0 && (src_arg.empty() || src_arg == "system")) {
-            rc = do_sync_sync(system_src_path.c_str(), "/system", list_only);
+        if (rc == 0 && (src.empty() || src == "system")) {
+            rc = do_sync_sync(system_src_path, "/system", list_only);
         }
-        if (rc == 0 && (src_arg.empty() || src_arg == "vendor")) {
-            rc = do_sync_sync(vendor_src_path.c_str(), "/vendor", list_only);
+        if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
+            rc = do_sync_sync(vendor_src_path, "/vendor", list_only);
         }
-        if(rc == 0 && (src_arg.empty() || src_arg == "oem")) {
-            rc = do_sync_sync(oem_src_path.c_str(), "/oem", list_only);
+        if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
+            rc = do_sync_sync(oem_src_path, "/oem", list_only);
         }
-        if (rc == 0 && (src_arg.empty() || src_arg == "data")) {
-            rc = do_sync_sync(data_src_path.c_str(), "/data", list_only);
+        if (rc == 0 && (src.empty() || src == "data")) {
+            rc = do_sync_sync(data_src_path, "/data", list_only);
         }
         return rc;
     }
@@ -1609,8 +1608,7 @@
         cmd += " " + escape_arg(*argv++);
     }
 
-    send_shell_command(transport, serial, cmd);
-    return 0;
+    return send_shell_command(transport, serial, cmd);
 }
 
 static int uninstall_app(transport_type transport, const char* serial, int argc,
@@ -1635,8 +1633,7 @@
 static int delete_file(transport_type transport, const char* serial, char* filename)
 {
     std::string cmd = "shell:rm -f " + escape_arg(filename);
-    send_shell_command(transport, serial, cmd);
-    return 0;
+    return send_shell_command(transport, serial, cmd);
 }
 
 static const char* get_basename(const char* filename)
@@ -1697,7 +1694,7 @@
         argv[last_apk] = apk_dest; /* destination name, not source location */
     }
 
-    pm_command(transport, serial, argc, argv);
+    err = pm_command(transport, serial, argc, argv);
 
 cleanup_apk:
     delete_file(transport, serial, apk_dest);
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 730a5e2..49d8783 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -1027,18 +1027,18 @@
     }
 }
 
-int do_sync_sync(const char *lpath, const char *rpath, int listonly)
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
 {
-    fprintf(stderr,"syncing %s...\n",rpath);
+    fprintf(stderr, "syncing %s...\n", rpath.c_str());
 
     int fd = adb_connect("sync:");
-    if(fd < 0) {
-        fprintf(stderr,"error: %s\n", adb_error());
+    if (fd < 0) {
+        fprintf(stderr, "error: %s\n", adb_error());
         return 1;
     }
 
     BEGIN();
-    if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
+    if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
         return 1;
     } else {
         END();
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 6e1ccce..344eb98 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -17,6 +17,8 @@
 #ifndef _FILE_SYNC_SERVICE_H_
 #define _FILE_SYNC_SERVICE_H_
 
+#include <string>
+
 #define htoll(x) (x)
 #define ltohl(x) (x)
 
@@ -67,7 +69,7 @@
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
 int do_sync_push(const char *lpath, const char *rpath, int show_progress);
-int do_sync_sync(const char *lpath, const char *rpath, int listonly);
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
 int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
diff --git a/adb/services.cpp b/adb/services.cpp
index ff13722..e6c84a4 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -689,6 +689,10 @@
         return create_device_tracker();
     } else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
         auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info)));
+        if (sinfo == nullptr) {
+            fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
+            return NULL;
+        }
 
         if (serial)
             sinfo->serial = strdup(serial);
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index f111b043..52d8056 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -267,6 +267,18 @@
                 adb.unroot()
             adb.wait()
 
+    def test_argument_escaping(self):
+        """Make sure that argument escaping is somewhat sane."""
+        adb = AdbWrapper()
+
+        # http://b/19734868
+        result = adb.shell("sh -c 'echo hello; echo world'").splitlines()
+        self.assertEqual(["hello", "world"], result)
+
+        # http://b/15479704
+        self.assertEqual('t', adb.shell("'true && echo t'").strip())
+        self.assertEqual('t', adb.shell("sh -c 'true && echo t'").strip())
+
 
 class AdbFile(unittest.TestCase):
     SCRATCH_DIR = "/data/local/tmp"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 37f9d7b..d395a80 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -493,10 +493,8 @@
 asocket*
 create_device_tracker(void)
 {
-    device_tracker* tracker = reinterpret_cast<device_tracker*>(
-        calloc(1, sizeof(*tracker)));
-
-    if(tracker == 0) fatal("cannot allocate device tracker");
+    device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
+    if (tracker == nullptr) fatal("cannot allocate device tracker");
 
     D( "device tracker %p created\n", tracker);
 
@@ -1002,8 +1000,11 @@
 
 int register_socket_transport(int s, const char *serial, int port, int local)
 {
-    atransport *t = reinterpret_cast<atransport*>(
-        calloc(1, sizeof(atransport)));
+    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+    if (t == nullptr) {
+        return -1;
+    }
+
     atransport *n;
     char buff[32];
 
@@ -1102,8 +1103,8 @@
 
 void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
 {
-    atransport *t = reinterpret_cast<atransport*>(
-        calloc(1, sizeof(atransport)));
+    atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+    if (t == nullptr) fatal("cannot allocate USB atransport");
     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
       serial ? serial : "");
     init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index fe3c87f..30e6bf5 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -144,7 +144,7 @@
         if(serverfd == -1) {
             serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
             if(serverfd < 0) {
-                D("server: cannot bind socket yet\n");
+                D("server: cannot bind socket yet: %s\n", strerror(errno));
                 adb_sleep_ms(1000);
                 continue;
             }
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 6fd2b40..9f23511 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -598,8 +598,8 @@
 
     D("[ usb located new device %s (%d/%d/%d) ]\n",
         dev_name, ep_in, ep_out, interface);
-    usb_handle* usb = reinterpret_cast<usb_handle*>(
-        calloc(1, sizeof(usb_handle)));
+    usb_handle* usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (usb == nullptr) fatal("couldn't allocate usb_handle");
     strcpy(usb->fname, dev_name);
     usb->ep_in = ep_in;
     usb->ep_out = ep_out;
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 343f20c..18289e2 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -18,6 +18,7 @@
 
 #include "sysdeps.h"
 
+#include <cutils/properties.h>
 #include <dirent.h>
 #include <errno.h>
 #include <linux/usb/ch9.h>
@@ -240,6 +241,8 @@
 static void usb_adb_init()
 {
     usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (h == nullptr) fatal("couldn't allocate usb_handle");
+
     h->write = usb_adb_write;
     h->read = usb_adb_read;
     h->kick = usb_adb_kick;
@@ -362,6 +365,7 @@
 
             adb_sleep_ms(1000);
         }
+        property_set("sys.usb.ffs.ready", "1");
 
         D("[ usb_thread - registering device ]\n");
         register_usb_transport(usb, 0, 0, 1);
@@ -466,6 +470,8 @@
     D("[ usb_init - using FunctionFS ]\n");
 
     usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (h == nullptr) fatal("couldn't allocate usb_handle");
+
     h->write = usb_ffs_write;
     h->read = usb_ffs_read;
     h->kick = usb_ffs_kick;
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 303ae45..a795ce3 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -336,6 +336,7 @@
         goto err_bad_adb_interface;
 
     handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+    if (handle == nullptr) goto err_bad_adb_interface;
 
     //* Iterate over the endpoints for this interface and find the first
     //* bulk in/out pipes available.  These will be our read/write pipes.
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index eb10642..5f639b7 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -120,8 +120,10 @@
          * filesytsem due to an error, e2fsck is still run to do a full check
          * fix the filesystem.
          */
+        errno = 0;
         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
-        INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
+        INFO("%s(): mount(%s,%s,%s)=%d: %s\n",
+             __func__, blk_device, target, fs_type, ret, strerror(errno));
         if (!ret) {
             int i;
             for (i = 0; i < 5; i++) {
@@ -129,6 +131,7 @@
                 // Should we try rebooting if all attempts fail?
                 int result = umount(target);
                 if (result == 0) {
+                    INFO("%s(): unmount(%s) succeeded\n", __func__, target);
                     break;
                 }
                 ERROR("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno));
diff --git a/include/cutils/dir_hash.h b/include/cutils/dir_hash.h
deleted file mode 100644
index fbb4d02..0000000
--- a/include/cutils/dir_hash.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-typedef enum {
-    SHA_1,
-} HashAlgorithm;
-
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string);
-
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string);
diff --git a/include/memtrack/memtrack.h b/include/memtrack/memtrack.h
index 0f1f85e..3917300 100644
--- a/include/memtrack/memtrack.h
+++ b/include/memtrack/memtrack.h
@@ -121,7 +121,7 @@
 ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p);
 
 /**
- * memtrack_proc_gl_total
+ * memtrack_proc_other_total
  *
  * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
  * not tracked by gl or graphics calls above.
@@ -131,7 +131,7 @@
 ssize_t memtrack_proc_other_total(struct memtrack_proc *p);
 
 /**
- * memtrack_proc_gl_pss
+ * memtrack_proc_other_pss
  *
  * Same as memtrack_proc_graphics_total, but counts miscellaneous memory
  * not tracked by gl or graphics calls above.
diff --git a/include/utils/LinearAllocator.h b/include/utils/LinearAllocator.h
deleted file mode 100644
index 4772bc8..0000000
--- a/include/utils/LinearAllocator.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ANDROID_LINEARALLOCATOR_H
-#define ANDROID_LINEARALLOCATOR_H
-
-#include <stddef.h>
-
-namespace android {
-
-/**
- * A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids
- * the overhead of malloc when many objects are allocated. It is most useful when creating many
- * small objects with a similar lifetime, and doesn't add significant overhead for large
- * allocations.
- */
-class LinearAllocator {
-public:
-    LinearAllocator();
-    ~LinearAllocator();
-
-    /**
-     * Reserves and returns a region of memory of at least size 'size', aligning as needed.
-     * Typically this is used in an object's overridden new() method or as a replacement for malloc.
-     *
-     * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
-     * delete() on an object stored in a buffer is needed, it should be overridden to use
-     * rewindIfLastAlloc()
-     */
-    void* alloc(size_t size);
-
-    /**
-     * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
-     * state if possible. No destructors are called.
-     */
-    void rewindIfLastAlloc(void* ptr, size_t allocSize);
-
-    /**
-     * Dump memory usage statistics to the log (allocated and wasted space)
-     */
-    void dumpMemoryStats(const char* prefix = "");
-
-    /**
-     * The number of bytes used for buffers allocated in the LinearAllocator (does not count space
-     * wasted)
-     */
-    size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
-
-private:
-    LinearAllocator(const LinearAllocator& other);
-
-    class Page;
-
-    Page* newPage(size_t pageSize);
-    bool fitsInCurrentPage(size_t size);
-    void ensureNext(size_t size);
-    void* start(Page *p);
-    void* end(Page* p);
-
-    size_t mPageSize;
-    size_t mMaxAllocSize;
-    void* mNext;
-    Page* mCurrentPage;
-    Page* mPages;
-
-    // Memory usage tracking
-    size_t mTotalAllocated;
-    size_t mWastedSpace;
-    size_t mPageCount;
-    size_t mDedicatedPageCount;
-};
-
-}; // namespace android
-
-#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index d015421..54ec474 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -24,6 +24,8 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
+#include <utils/Compat.h>
+
 // ------------------------------------------------------------------
 // C API
 
@@ -33,46 +35,46 @@
 
 typedef int64_t nsecs_t;       // nano-seconds
 
-static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000000000;
 }
 
-static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000000;
 }
 
-static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
 {
     return secs*1000;
 }
 
-static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
 {
     return secs/1000000000;
 }
 
-static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
 {
     return secs/1000000;
 }
 
-static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
 {
     return secs/1000;
 }
 
-static inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
-static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
-static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
-static inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
-static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
-static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
+static CONSTEXPR inline nsecs_t s2ns(nsecs_t v)  {return seconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ns2s(nsecs_t v)  {return nanoseconds_to_seconds(v);}
+static CONSTEXPR inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
+static CONSTEXPR inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
 
-static inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
-static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
-static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
+static CONSTEXPR inline nsecs_t seconds(nsecs_t v)      { return s2ns(v); }
+static CONSTEXPR inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
+static CONSTEXPR inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
 
 enum {
     SYSTEM_TIME_REALTIME = 0,  // system-wide realtime clock
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 3bbaf83..4567b04 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -515,15 +515,6 @@
     return ret;
 }
 
-int do_setcon(int nargs, char **args) {
-    if (is_selinux_enabled() <= 0)
-        return 0;
-    if (setcon(args[1]) < 0) {
-        return -errno;
-    }
-    return 0;
-}
-
 int do_setprop(int nargs, char **args)
 {
     const char *name = args[1];
diff --git a/init/devices.cpp b/init/devices.cpp
index 5ca855f..4944cec 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -266,7 +266,6 @@
 static void add_platform_device(const char *path)
 {
     int path_len = strlen(path);
-    struct listnode *node;
     struct platform_node *bus;
     const char *name = path;
 
@@ -276,15 +275,6 @@
             name += 9;
     }
 
-    list_for_each_reverse(node, &platform_names) {
-        bus = node_to_item(node, struct platform_node, list);
-        if ((bus->path_len < path_len) &&
-                (path[bus->path_len] == '/') &&
-                !strncmp(path, bus->path, bus->path_len))
-            /* subdevice of an existing platform, ignore it */
-            return;
-    }
-
     INFO("adding platform device %s (%s)\n", name, path);
 
     bus = (platform_node*) calloc(1, sizeof(struct platform_node));
diff --git a/init/init.cpp b/init/init.cpp
index b1d65db..661ee2f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -940,7 +940,13 @@
     return 0;
 }
 
-static void selinux_initialize() {
+static void security_failure() {
+    ERROR("Security failure; rebooting into recovery mode...\n");
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (true) { pause(); }  // never reached
+}
+
+static void selinux_initialize(bool in_kernel_domain) {
     Timer t;
 
     selinux_callback cb;
@@ -953,19 +959,27 @@
         return;
     }
 
-    INFO("Loading SELinux policy...\n");
-    if (selinux_android_load_policy() < 0) {
-        ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
-        android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-        while (1) { pause(); }  // never reached
+    if (in_kernel_domain) {
+        if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {
+            ERROR("couldn't write to /sys/fs/selinux/checkreqprot: %s\n",
+                  strerror(errno));
+            security_failure();
+        }
+
+        INFO("Loading SELinux policy...\n");
+        if (selinux_android_load_policy() < 0) {
+            ERROR("failed to load policy: %s\n", strerror(errno));
+            security_failure();
+        }
+
+        bool is_enforcing = selinux_is_enforcing();
+        security_setenforce(is_enforcing);
+
+        NOTICE("(Initializing SELinux %s took %.2fs.)\n",
+               is_enforcing ? "enforcing" : "non-enforcing", t.duration());
+    } else {
+        selinux_init_all_handles();
     }
-
-    selinux_init_all_handles();
-    bool is_enforcing = selinux_is_enforcing();
-    INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
-    security_setenforce(is_enforcing);
-
-    NOTICE("(Initializing SELinux took %.2fs.)\n", t.duration());
 }
 
 int main(int argc, char** argv) {
@@ -1006,7 +1020,8 @@
     klog_init();
     klog_set_level(KLOG_NOTICE_LEVEL);
 
-    NOTICE("init started!\n");
+    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
+    NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
 
     property_init();
 
@@ -1019,7 +1034,23 @@
     // used by init as well as the current required properties.
     export_kernel_boot_props();
 
-    selinux_initialize();
+    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
+    selinux_initialize(is_first_stage);
+
+    // If we're in the kernel domain, re-exec init to transition to the init domain now
+    // that the SELinux policy has been loaded.
+    if (is_first_stage) {
+        if (restorecon("/init") == -1) {
+            ERROR("restorecon failed: %s\n", strerror(errno));
+            security_failure();
+        }
+        char* path = argv[0];
+        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
+        if (execv(path, args) == -1) {
+            ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
+            security_failure();
+        }
+    }
 
     // These directories were necessarily created before initial policy load
     // and therefore need their security context restored to the proper value.
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index ff31093..b76b04e 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -184,7 +184,6 @@
     case 's':
         if (!strcmp(s, "eclabel")) return K_seclabel;
         if (!strcmp(s, "ervice")) return K_service;
-        if (!strcmp(s, "etcon")) return K_setcon;
         if (!strcmp(s, "etenv")) return K_setenv;
         if (!strcmp(s, "etprop")) return K_setprop;
         if (!strcmp(s, "etrlimit")) return K_setrlimit;
diff --git a/init/keywords.h b/init/keywords.h
index 059dde1..37f01b8 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -20,7 +20,6 @@
 int do_restorecon_recursive(int nargs, char **args);
 int do_rm(int nargs, char **args);
 int do_rmdir(int nargs, char **args);
-int do_setcon(int nargs, char **args);
 int do_setprop(int nargs, char **args);
 int do_setrlimit(int nargs, char **args);
 int do_start(int nargs, char **args);
@@ -76,7 +75,6 @@
     KEYWORD(rmdir,       COMMAND, 1, do_rmdir)
     KEYWORD(seclabel,    OPTION,  0, 0)
     KEYWORD(service,     SECTION, 0, 0)
-    KEYWORD(setcon,      COMMAND, 1, do_setcon)
     KEYWORD(setenv,      OPTION,  2, 0)
     KEYWORD(setprop,     COMMAND, 2, do_setprop)
     KEYWORD(setrlimit,   COMMAND, 3, do_setrlimit)
diff --git a/init/readme.txt b/init/readme.txt
index 84afd11..6b9c42d 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -252,11 +252,6 @@
 rmdir <path>
    Calls rmdir(2) on the given path.
 
-setcon <seclabel>
-   Set the current process security context to the specified string.
-   This is typically only used from early-init to set the init context
-   before any other process is started.
-
 setprop <name> <value>
    Set system property <name> to <value>. Properties are expanded
    within <value>.
diff --git a/libcutils/dir_hash.c b/libcutils/dir_hash.c
deleted file mode 100644
index 098b5db..0000000
--- a/libcutils/dir_hash.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sha1.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-#include <resolv.h>
-
-#include <cutils/dir_hash.h>
-
-/**
- * Copies, if it fits within max_output_string bytes, into output_string
- * a hash of the contents, size, permissions, uid, and gid of the file
- * specified by path, using the specified algorithm.  Returns the length
- * of the output string, or a negative number if the buffer is too short.
- */
-int get_file_hash(HashAlgorithm algorithm, const char *path,
-                  char *output_string, size_t max_output_string) {
-    SHA1_CTX context;
-    struct stat sb;
-    unsigned char md[SHA1_DIGEST_LENGTH];
-    int used;
-    size_t n;
-
-    if (algorithm != SHA_1) {
-        errno = EINVAL;
-        return -1;
-    }
-
-    if (stat(path, &sb) != 0) {
-        return -1;
-    }
-
-    if (S_ISLNK(sb.st_mode)) {
-        char buf[PATH_MAX];
-        int len;
-
-        len = readlink(path, buf, sizeof(buf));
-        if (len < 0) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-        SHA1Update(&context, (unsigned char *) buf, len);
-        SHA1Final(md, &context);
-    } else if (S_ISREG(sb.st_mode)) {
-        char buf[10000];
-        FILE *f = fopen(path, "rb");
-        int len;
-
-        if (f == NULL) {
-            return -1;
-        }
-
-        SHA1Init(&context);
-
-        while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
-            SHA1Update(&context, (unsigned char *) buf, len);
-        }
-
-        if (ferror(f)) {
-            fclose(f);
-            return -1;
-        }
-
-        fclose(f);
-        SHA1Final(md, &context);
-    }
-
-    if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {
-        used = b64_ntop(md, SHA1_DIGEST_LENGTH,
-                        output_string, max_output_string);
-        if (used < 0) {
-            errno = ENOSPC;
-            return -1;
-        }
-
-        n = snprintf(output_string + used, max_output_string - used,
-                     " %d 0%o %d %d", (int) sb.st_size, sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    } else {
-        n = snprintf(output_string, max_output_string,
-                     "- - 0%o %d %d", sb.st_mode,
-                     (int) sb.st_uid, (int) sb.st_gid);
-    }
-
-    if (n >= max_output_string - used) {
-        errno = ENOSPC;
-        return -(used + n);
-    }
-
-    return used + n;
-}
-
-struct list {
-    char *name;
-    struct list *next;
-};
-
-static int cmp(const void *a, const void *b) {
-    struct list *const *ra = a;
-    struct list *const *rb = b;
-
-    return strcmp((*ra)->name, (*rb)->name);
-}
-
-static int recurse(HashAlgorithm algorithm, const char *directory_path,
-                    struct list **out) {
-    struct list *list = NULL;
-    struct list *f;
-
-    struct dirent *de;
-    DIR *d = opendir(directory_path);
-
-    if (d == NULL) {
-        return -1;
-    }
-
-    while ((de = readdir(d)) != NULL) {
-        if (strcmp(de->d_name, ".") == 0) {
-            continue;
-        }
-        if (strcmp(de->d_name, "..") == 0) {
-            continue;
-        }
-
-        char *name = malloc(strlen(de->d_name) + 1);
-        struct list *node = malloc(sizeof(struct list));
-
-        if (name == NULL || node == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-
-            free(name);
-            free(node);
-            closedir(d);
-            return -1;
-        }
-
-        strcpy(name, de->d_name);
-
-        node->name = name;
-        node->next = list;
-        list = node;
-    }
-
-    closedir(d);
-
-    for (f = list; f != NULL; f = f->next) {
-        struct stat sb;
-        char *name;
-        char outstr[NAME_MAX + 100];
-        char *keep;
-        struct list *res;
-
-        name = malloc(strlen(f->name) + strlen(directory_path) + 2);
-        if (name == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-            return -1;
-        }
-
-        sprintf(name, "%s/%s", directory_path, f->name);
-
-        int len = get_file_hash(algorithm, name,
-                                outstr, sizeof(outstr));
-        if (len < 0) {
-            // should not happen
-            return -1;
-        }
-
-        keep = malloc(len + strlen(name) + 3);
-        res = malloc(sizeof(struct list));
-
-        if (keep == NULL || res == NULL) {
-            struct list *next;
-            for (f = list; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            for (f = *out; f != NULL; f = f->next) {
-                next = f->next;
-                free(f->name);
-                free(f);
-            }
-            *out = NULL;
-
-            free(keep);
-            free(res);
-            return -1;
-        }
-
-        sprintf(keep, "%s %s\n", name, outstr);
-
-        res->name = keep;
-        res->next = *out;
-        *out = res;
-
-        if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
-            if (recurse(algorithm, name, out) < 0) {
-                struct list *next;
-                for (f = list; f != NULL; f = next) {
-                    next = f->next;
-                    free(f->name);
-                    free(f);
-                }
-
-                return -1;
-            }
-        }
-    }
-
-    struct list *next;
-    for (f = list; f != NULL; f = next) {
-        next = f->next;
-
-        free(f->name);
-        free(f);
-    }
-}
-
-/**
- * Allocates a string containing the names and hashes of all files recursively
- * reached under the specified directory_path, using the specified algorithm.
- * The string is returned as *output_string; the return value is the length
- * of the string, or a negative number if there was a failure.
- */
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
-                                const char *directory_path,
-                                char **output_string) {
-    struct list *out = NULL;
-    struct list *r;
-    struct list **list;
-    int count = 0;
-    int len = 0;
-    int retlen = 0;
-    int i;
-    char *buf;
-    
-    if (recurse(algorithm, directory_path, &out) < 0) {
-        return -1;
-    }
-
-    for (r = out; r != NULL; r = r->next) {
-        count++;
-        len += strlen(r->name);
-    }
-
-    list = malloc(count * sizeof(struct list *));
-    if (list == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        return -1;
-    }
-
-    count = 0;
-    for (r = out; r != NULL; r = r->next) {
-        list[count++] = r;
-    }
-
-    qsort(list, count, sizeof(struct list *), cmp);
-
-    buf = malloc(len + 1);
-    if (buf == NULL) {
-        struct list *next;
-        for (r = out; r != NULL; r = next) {
-            next = r->next;
-            free(r->name);
-            free(r);
-        }
-        free(list);
-        return -1;
-    }
-
-    for (i = 0; i < count; i++) {
-        int n = strlen(list[i]->name);
-
-        strcpy(buf + retlen, list[i]->name);
-        retlen += n;
-    }
-
-    free(list);
-
-    struct list *next;
-    for (r = out; r != NULL; r = next) {
-        next = r->next;
-
-        free(r->name);
-        free(r);
-    }
-
-    *output_string = buf;
-    return retlen;
-}
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index df67123..2e09192 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -28,7 +28,7 @@
         return def;
     }
     {
-        static const char log_namespace[] = "log.tag.";
+        static const char log_namespace[] = "persist.log.tag.";
         char key[sizeof(log_namespace) + strlen(tag)];
 
         strcpy(key, log_namespace);
@@ -37,6 +37,9 @@
         if (__system_property_get(key + 8, buf) <= 0) {
             buf[0] = '\0';
         }
+        if (!buf[0] && __system_property_get(key, buf) <= 0) {
+            buf[0] = '\0';
+        }
     }
     switch (toupper(buf[0])) {
         case 'V': return ANDROID_LOG_VERBOSE;
@@ -53,17 +56,6 @@
 
 int __android_log_is_loggable(int prio, const char *tag, int def)
 {
-    static char user;
-    int logLevel;
-
-    if (user == 0) {
-        char buf[PROP_VALUE_MAX];
-        if (__system_property_get("ro.build.type", buf) <= 0) {
-            buf[0] = '\0';
-        }
-        user = strcmp(buf, "user") ? -1 : 1;
-    }
-
-    logLevel = (user == 1) ? def : __android_log_level(tag, def);
+    int logLevel = __android_log_level(tag, def);
     return logLevel >= 0 && prio >= logLevel;
 }
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 1f61511..2060df4 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -17,3 +17,10 @@
 LOCAL_CFLAGS := -Werror
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dhcptool.c
+LOCAL_SHARED_LIBRARIES := libnetutils
+LOCAL_MODULE := dhcptool
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
new file mode 100644
index 0000000..352ac5e
--- /dev/null
+++ b/libnetutils/dhcptool.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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.
+ */
+
+#include <errno.h>
+#include <error.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <netutils/dhcp.h>
+#include <netutils/ifc.h>
+
+int main(int argc, char* argv[]) {
+  if (argc != 2) {
+    error(EXIT_FAILURE, 0, "usage: %s INTERFACE", argv[0]);
+  }
+
+  char* interface = argv[1];
+  if (ifc_init()) {
+    error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+  }
+
+  int rc = do_dhcp(interface);
+  if (rc) {
+    error(0, errno, "dhcptool %s: do_dhcp failed", interface);
+  }
+
+  ifc_close();
+
+  return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/libutils/Android.mk b/libutils/Android.mk
index e9c5f89..f675a94 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -20,7 +20,6 @@
 	CallStack.cpp \
 	FileMap.cpp \
 	JenkinsHash.cpp \
-	LinearAllocator.cpp \
 	LinearTransform.cpp \
 	Log.cpp \
 	NativeHandle.cpp \
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
deleted file mode 100644
index 8b90696..0000000
--- a/libutils/LinearAllocator.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define LOG_TAG "LinearAllocator"
-#define LOG_NDEBUG 1
-
-#include <stdlib.h>
-#include <utils/LinearAllocator.h>
-#include <utils/Log.h>
-
-
-// The ideal size of a page allocation (these need to be multiples of 8)
-#define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb
-#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
-
-// The maximum amount of wasted space we can have per page
-// Allocations exceeding this will have their own dedicated page
-// If this is too low, we will malloc too much
-// Too high, and we may waste too much space
-// Must be smaller than INITIAL_PAGE_SIZE
-#define MAX_WASTE_SIZE ((size_t)1024)
-
-#if ALIGN_DOUBLE
-#define ALIGN_SZ (sizeof(double))
-#else
-#define ALIGN_SZ (sizeof(int))
-#endif
-
-#define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
-#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p)))
-
-#if LOG_NDEBUG
-#define ADD_ALLOCATION(size)
-#define RM_ALLOCATION(size)
-#else
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-static size_t s_totalAllocations = 0;
-static nsecs_t s_nextLog = 0;
-static android::Mutex s_mutex;
-
-static void _logUsageLocked() {
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    if (now > s_nextLog) {
-        s_nextLog = now + milliseconds_to_nanoseconds(10);
-        ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024);
-    }
-}
-
-static void _addAllocation(size_t size) {
-    android::AutoMutex lock(s_mutex);
-    s_totalAllocations += size;
-    _logUsageLocked();
-}
-
-#define ADD_ALLOCATION(size) _addAllocation(size);
-#define RM_ALLOCATION(size) _addAllocation(-size);
-#endif
-
-#define min(x,y) (((x) < (y)) ? (x) : (y))
-
-namespace android {
-
-class LinearAllocator::Page {
-public:
-    Page* next() { return mNextPage; }
-    void setNext(Page* next) { mNextPage = next; }
-
-    Page()
-        : mNextPage(0)
-    {}
-
-    void* operator new(size_t /*size*/, void* buf) { return buf; }
-
-    void* start() {
-        return (void*) (((size_t)this) + sizeof(Page));
-    }
-
-    void* end(int pageSize) {
-        return (void*) (((size_t)start()) + pageSize);
-    }
-
-private:
-    Page(const Page& /*other*/) {}
-    Page* mNextPage;
-};
-
-LinearAllocator::LinearAllocator()
-    : mPageSize(INITIAL_PAGE_SIZE)
-    , mMaxAllocSize(MAX_WASTE_SIZE)
-    , mNext(0)
-    , mCurrentPage(0)
-    , mPages(0)
-    , mTotalAllocated(0)
-    , mWastedSpace(0)
-    , mPageCount(0)
-    , mDedicatedPageCount(0) {}
-
-LinearAllocator::~LinearAllocator(void) {
-    Page* p = mPages;
-    while (p) {
-        Page* next = p->next();
-        p->~Page();
-        free(p);
-        RM_ALLOCATION(mPageSize);
-        p = next;
-    }
-}
-
-void* LinearAllocator::start(Page* p) {
-    return ALIGN_PTR(((size_t*)p) + sizeof(Page));
-}
-
-void* LinearAllocator::end(Page* p) {
-    return ((char*)p) + mPageSize;
-}
-
-bool LinearAllocator::fitsInCurrentPage(size_t size) {
-    return mNext && ((char*)mNext + size) <= end(mCurrentPage);
-}
-
-void LinearAllocator::ensureNext(size_t size) {
-    if (fitsInCurrentPage(size)) return;
-
-    if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
-        mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
-        mPageSize = ALIGN(mPageSize);
-    }
-    mWastedSpace += mPageSize;
-    Page* p = newPage(mPageSize);
-    if (mCurrentPage) {
-        mCurrentPage->setNext(p);
-    }
-    mCurrentPage = p;
-    if (!mPages) {
-        mPages = mCurrentPage;
-    }
-    mNext = start(mCurrentPage);
-}
-
-void* LinearAllocator::alloc(size_t size) {
-    size = ALIGN(size);
-    if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
-        ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
-        // Allocation is too large, create a dedicated page for the allocation
-        Page* page = newPage(size);
-        mDedicatedPageCount++;
-        page->setNext(mPages);
-        mPages = page;
-        if (!mCurrentPage)
-            mCurrentPage = mPages;
-        return start(page);
-    }
-    ensureNext(size);
-    void* ptr = mNext;
-    mNext = ((char*)mNext) + size;
-    mWastedSpace -= size;
-    return ptr;
-}
-
-void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) {
-    // Don't bother rewinding across pages
-    allocSize = ALIGN(allocSize);
-    if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
-            && ptr == ((char*)mNext - allocSize)) {
-        mTotalAllocated -= allocSize;
-        mWastedSpace += allocSize;
-        mNext = ptr;
-    }
-}
-
-LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) {
-    pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page));
-    ADD_ALLOCATION(pageSize);
-    mTotalAllocated += pageSize;
-    mPageCount++;
-    void* buf = malloc(pageSize);
-    return new (buf) Page();
-}
-
-static const char* toSize(size_t value, float& result) {
-    if (value < 2000) {
-        result = value;
-        return "B";
-    }
-    if (value < 2000000) {
-        result = value / 1024.0f;
-        return "KB";
-    }
-    result = value / 1048576.0f;
-    return "MB";
-}
-
-void LinearAllocator::dumpMemoryStats(const char* prefix) {
-    float prettySize;
-    const char* prettySuffix;
-    prettySuffix = toSize(mTotalAllocated, prettySize);
-    ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
-    prettySuffix = toSize(mWastedSpace, prettySize);
-    ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
-          (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
-    ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
-}
-
-}; // namespace android
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1859461..1dced11 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -247,7 +247,7 @@
     uint64_t getKey() { return value; }
 };
 
-struct LogBufferElementEntry {
+class LogBufferElementEntry {
     const uint64_t key;
     LogBufferElement *last;
 
@@ -259,8 +259,9 @@
     LogBufferElement *getLast() { return last; }
 };
 
-struct LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> {
+class LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> {
 
+public:
     bool merge(LogBufferElement *e, unsigned short dropped) {
         LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
         android::hash_t hash = android::hash_type(key.getKey());
@@ -286,6 +287,21 @@
             add(hash, LogBufferElementEntry(key.getKey(), e));
     }
 
+    inline void clear() {
+        android::BasicHashtable<uint64_t, LogBufferElementEntry>::clear();
+    }
+
+    void clear(LogBufferElement *e) {
+        uint64_t current = e->getRealTime().nsec() - NS_PER_SEC;
+        ssize_t index = -1;
+        while((index = next(index)) >= 0) {
+            if (current > editEntryAt(index).getLast()->getRealTime().nsec()) {
+                removeAt(index);
+                index = -1;
+            }
+        }
+    }
+
 };
 
 // prune "pruneRows" of type "id" from the buffer.
@@ -349,9 +365,16 @@
 
             if (sorted.get()) {
                 if (sorted[0] && sorted[1]) {
-                    worst = sorted[0]->getKey();
                     worst_sizes = sorted[0]->getSizes();
-                    second_worst_sizes = sorted[1]->getSizes();
+                    // Calculate threshold as 12.5% of available storage
+                    size_t threshold = log_buffer_size(id) / 8;
+                    if (worst_sizes > threshold) {
+                        worst = sorted[0]->getKey();
+                        second_worst_sizes = sorted[1]->getSizes();
+                        if (second_worst_sizes < threshold) {
+                            second_worst_sizes = threshold;
+                        }
+                    }
                 }
             }
         }
@@ -395,7 +418,7 @@
             leading = false;
 
             if (hasBlacklist && mPrune.naughty(e)) {
-                last.clear();
+                last.clear(e);
                 it = erase(it);
                 if (dropped) {
                     continue;
@@ -423,7 +446,7 @@
             }
 
             if (e->getUid() != worst) {
-                last.clear();
+                last.clear(e);
                 ++it;
                 continue;
             }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 0801fe8..eadc4dd 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -328,22 +328,32 @@
             }
 
             if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
                 if (uid == AID_ROOT) {
-                    output.appendFormat(
-                        "\n\nChattiest UIDs in %s:\n",
+                    name.appendFormat(
+                        "Chattiest UIDs in %s log buffer:",
                         android_log_id_to_name(id));
                 } else {
-                    output.appendFormat(
-                        "\n\nLogging for your UID in %s:\n",
+                    name.appendFormat(
+                        "Logging for your UID in %s log buffer:",
                         android_log_id_to_name(id));
                 }
-                android::String8 name("UID");
                 android::String8 size("Size");
                 android::String8 pruned("Pruned");
                 if (!worstUidEnabledForLogid(id)) {
                     pruned.setTo("");
                 }
                 format_line(output, name, size, pruned);
+
+                name.setTo("UID   PACKAGE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                if (!worstUidEnabledForLogid(id)) {
+                    pruned.setTo("");
+                }
+                format_line(output, name, size, pruned);
+
                 headerPrinted = true;
             }
 
@@ -380,15 +390,22 @@
             }
 
             if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("");
                 if (uid == AID_ROOT) {
-                    output.appendFormat("\n\nChattiest PIDs:\n");
+                    name.appendFormat("Chattiest PIDs:");
                 } else {
-                    output.appendFormat("\n\nLogging for this PID:\n");
+                    name.appendFormat("Logging for this PID:");
                 }
-                android::String8 name("  PID/UID");
                 android::String8 size("Size");
                 android::String8 pruned("Pruned");
                 format_line(output, name, size, pruned);
+
+                name.setTo("  PID/UID   COMMAND LINE");
+                size.setTo("BYTES");
+                pruned.setTo("LINES");
+                format_line(output, name, size, pruned);
+
                 headerPrinted = true;
             }
 
diff --git a/rootdir/etc/mountd.conf b/rootdir/etc/mountd.conf
deleted file mode 100644
index 094a2c7..0000000
--- a/rootdir/etc/mountd.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-## mountd configuration file
-
-## add a mount entry for each mount point to be managed by mountd
-mount {
-    ## root block device with partition map or raw FAT file system
-    block_device    /dev/block/mmcblk0
-        
-    ## mount point for block device
-    mount_point     /sdcard
-    
-    ## true if this mount point can be shared via USB mass storage
-    enable_ums      true
-    
-    ## path to the UMS driver file for specifying the block device path  
-    ## use this for the mass_storage function driver
-    driver_store_path   /sys/devices/platform/usb_mass_storage/lun0/file
-    ## use this for android_usb composite gadget driver
-    ##driver_store_path   /sys/devices/platform/msm_hsusb/gadget/lun0/file
-}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2be6580..87e4f5d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -14,13 +14,6 @@
     # Set init and its forked children's oom_adj.
     write /proc/1/oom_score_adj -1000
 
-    # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
-    write /sys/fs/selinux/checkreqprot 0
-
-    # Set the security context for the init process.
-    # This should occur before anything else (e.g. ueventd) is started.
-    setcon u:r:init:s0
-
     # Set the security context of /adb_keys if present.
     restorecon /adb_keys
 
@@ -165,6 +158,7 @@
 # Load properties from /system/ + /factory after fs mount.
 on load_all_props_action
     load_all_props
+    start logd
     start logd-reinit
 
 # Indicate to fw loaders that the relevant mounts are up.
@@ -460,6 +454,7 @@
 
 on property:vold.decrypt=trigger_load_persist_props
     load_persist_props
+    start logd
     start logd-reinit
 
 on property:vold.decrypt=trigger_post_fs_data
@@ -505,7 +500,6 @@
     socket logdw dgram 0222 logd logd
 
 service logd-reinit /system/bin/logd --reinit
-    start logd
     oneshot
     disabled
 
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 4712e90..f8b23a3 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -1866,7 +1866,7 @@
     struct fuse fuse;
 
     /* cleanup from previous instance, if necessary */
-    umount2(dest_path, 2);
+    umount2(dest_path, MNT_DETACH);
 
     fd = open("/dev/fuse", O_RDWR);
     if (fd < 0){