Merge "Give wifi_hal_legacy access to netlink" am: 6fc7eaaad0 am: c3d7cb95cc am: 9fef925542
am: a0a91241af

Change-Id: I1bbf05f3a8b11a3d363413ef4104bfbd31da15df
diff --git a/base/Android.bp b/base/Android.bp
index e260412..88d8ad1 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -39,7 +39,10 @@
     shared_libs: ["liblog"],
     target: {
         android: {
-            srcs: ["errors_unix.cpp"],
+            srcs: [
+                "errors_unix.cpp",
+                "properties.cpp",
+            ],
             cppflags: ["-Wexit-time-destructors"],
         },
         darwin: {
@@ -78,6 +81,9 @@
         "test_main.cpp",
     ],
     target: {
+        android: {
+            srcs: ["properties_test.cpp"],
+        },
         windows: {
             srcs: ["utf8_test.cpp"],
             enabled: true,
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
new file mode 100644
index 0000000..95d1b6a
--- /dev/null
+++ b/base/include/android-base/properties.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BASE_PROPERTIES_H
+#define ANDROID_BASE_PROPERTIES_H
+
+#include <sys/cdefs.h>
+
+#if !defined(__BIONIC__)
+#error Only bionic supports system properties.
+#endif
+
+#include <limits>
+#include <string>
+
+namespace android {
+namespace base {
+
+// Returns the current value of the system property `key`,
+// or `default_value` if the property is empty or doesn't exist.
+std::string GetProperty(const std::string& key, const std::string& default_value);
+
+// Returns true if the system property `key` has the value "1", "y", "yes", "on", or "true",
+// false for "0", "n", "no", "off", or "false", or `default_value` otherwise.
+bool GetBoolProperty(const std::string& key, bool default_value);
+
+// Returns the signed integer corresponding to the system property `key`.
+// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
+// the optional bounds, returns `default_value`.
+template <typename T> T GetIntProperty(const std::string& key,
+                                       T default_value,
+                                       T min = std::numeric_limits<T>::min(),
+                                       T max = std::numeric_limits<T>::max());
+
+// Returns the unsigned integer corresponding to the system property `key`.
+// If the property is empty, doesn't exist, doesn't have an integer value, or is outside
+// the optional bound, returns `default_value`.
+template <typename T> T GetUintProperty(const std::string& key,
+                                        T default_value,
+                                        T max = std::numeric_limits<T>::max());
+
+// Sets the system property `key` to `value`.
+// Note that system property setting is inherently asynchronous so a return value of `true`
+// isn't particularly meaningful, and immediately reading back the value won't necessarily
+// tell you whether or not your call succeeded. A `false` return value definitely means failure.
+bool SetProperty(const std::string& key, const std::string& value);
+
+} // namespace base
+} // namespace android
+
+#endif  // ANDROID_BASE_MEMORY_H
diff --git a/base/properties.cpp b/base/properties.cpp
new file mode 100644
index 0000000..fab3005
--- /dev/null
+++ b/base/properties.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/properties.h"
+
+#include <sys/system_properties.h>
+
+#include <string>
+
+#include <android-base/parseint.h>
+
+namespace android {
+namespace base {
+
+std::string GetProperty(const std::string& key, const std::string& default_value) {
+  const prop_info* pi = __system_property_find(key.c_str());
+  if (pi == nullptr) return default_value;
+
+  char buf[PROP_VALUE_MAX];
+  if (__system_property_read(pi, nullptr, buf) > 0) return buf;
+
+  // If the property exists but is empty, also return the default value.
+  // Since we can't remove system properties, "empty" is traditionally
+  // the same as "missing" (this was true for cutils' property_get).
+  return default_value;
+}
+
+bool GetBoolProperty(const std::string& key, bool default_value) {
+  std::string value = GetProperty(key, "");
+  if (value == "1" || value == "y" || value == "yes" || value == "on" || value == "true") {
+    return true;
+  } else if (value == "0" || value == "n" || value == "no" || value == "off" || value == "false") {
+    return false;
+  }
+  return default_value;
+}
+
+template <typename T>
+T GetIntProperty(const std::string& key, T default_value, T min, T max) {
+  T result;
+  std::string value = GetProperty(key, "");
+  if (!value.empty() && android::base::ParseInt(value.c_str(), &result, min, max)) return result;
+  return default_value;
+}
+
+template <typename T>
+T GetUintProperty(const std::string& key, T default_value, T max) {
+  T result;
+  std::string value = GetProperty(key, "");
+  if (!value.empty() && android::base::ParseUint(value.c_str(), &result, max)) return result;
+  return default_value;
+}
+
+template int8_t GetIntProperty(const std::string&, int8_t, int8_t, int8_t);
+template int16_t GetIntProperty(const std::string&, int16_t, int16_t, int16_t);
+template int32_t GetIntProperty(const std::string&, int32_t, int32_t, int32_t);
+template int64_t GetIntProperty(const std::string&, int64_t, int64_t, int64_t);
+
+template uint8_t GetUintProperty(const std::string&, uint8_t, uint8_t);
+template uint16_t GetUintProperty(const std::string&, uint16_t, uint16_t);
+template uint32_t GetUintProperty(const std::string&, uint32_t, uint32_t);
+template uint64_t GetUintProperty(const std::string&, uint64_t, uint64_t);
+
+bool SetProperty(const std::string& key, const std::string& value) {
+  return (__system_property_set(key.c_str(), value.c_str()) == 0);
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
new file mode 100644
index 0000000..da89ec5
--- /dev/null
+++ b/base/properties_test.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "android-base/properties.h"
+
+#include <gtest/gtest.h>
+
+#include <string>
+
+TEST(properties, smoke) {
+  android::base::SetProperty("debug.libbase.property_test", "hello");
+
+  std::string s = android::base::GetProperty("debug.libbase.property_test", "");
+  ASSERT_EQ("hello", s);
+
+  android::base::SetProperty("debug.libbase.property_test", "world");
+  s = android::base::GetProperty("debug.libbase.property_test", "");
+  ASSERT_EQ("world", s);
+
+  s = android::base::GetProperty("this.property.does.not.exist", "");
+  ASSERT_EQ("", s);
+
+  s = android::base::GetProperty("this.property.does.not.exist", "default");
+  ASSERT_EQ("default", s);
+}
+
+TEST(properties, empty) {
+  // Because you can't delete a property, people "delete" them by
+  // setting them to the empty string. In that case we'd want to
+  // keep the default value (like cutils' property_get did).
+  android::base::SetProperty("debug.libbase.property_test", "");
+  std::string s = android::base::GetProperty("debug.libbase.property_test", "default");
+  ASSERT_EQ("default", s);
+}
+
+static void CheckGetBoolProperty(bool expected, const std::string& value, bool default_value) {
+  android::base::SetProperty("debug.libbase.property_test", value.c_str());
+  ASSERT_EQ(expected, android::base::GetBoolProperty("debug.libbase.property_test", default_value));
+}
+
+TEST(properties, GetBoolProperty_true) {
+  CheckGetBoolProperty(true, "1", false);
+  CheckGetBoolProperty(true, "y", false);
+  CheckGetBoolProperty(true, "yes", false);
+  CheckGetBoolProperty(true, "on", false);
+  CheckGetBoolProperty(true, "true", false);
+}
+
+TEST(properties, GetBoolProperty_false) {
+  CheckGetBoolProperty(false, "0", true);
+  CheckGetBoolProperty(false, "n", true);
+  CheckGetBoolProperty(false, "no", true);
+  CheckGetBoolProperty(false, "off", true);
+  CheckGetBoolProperty(false, "false", true);
+}
+
+TEST(properties, GetBoolProperty_default) {
+  CheckGetBoolProperty(true, "burp", true);
+  CheckGetBoolProperty(false, "burp", false);
+}
+
+template <typename T> void CheckGetIntProperty() {
+  // Positive and negative.
+  android::base::SetProperty("debug.libbase.property_test", "-12");
+  EXPECT_EQ(T(-12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(12), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
+
+  // Default value.
+  android::base::SetProperty("debug.libbase.property_test", "");
+  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45));
+
+  // Bounds checks.
+  android::base::SetProperty("debug.libbase.property_test", "0");
+  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+  android::base::SetProperty("debug.libbase.property_test", "1");
+  EXPECT_EQ(T(1), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+  android::base::SetProperty("debug.libbase.property_test", "2");
+  EXPECT_EQ(T(2), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+  android::base::SetProperty("debug.libbase.property_test", "3");
+  EXPECT_EQ(T(45), android::base::GetIntProperty<T>("debug.libbase.property_test", 45, 1, 2));
+}
+
+template <typename T> void CheckGetUintProperty() {
+  // Positive.
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
+
+  // Default value.
+  android::base::SetProperty("debug.libbase.property_test", "");
+  EXPECT_EQ(T(45), android::base::GetUintProperty<T>("debug.libbase.property_test", 45));
+
+  // Bounds checks.
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(12), android::base::GetUintProperty<T>("debug.libbase.property_test", 33, 22));
+  android::base::SetProperty("debug.libbase.property_test", "12");
+  EXPECT_EQ(T(5), android::base::GetUintProperty<T>("debug.libbase.property_test", 5, 10));
+}
+
+TEST(properties, GetIntProperty_int8_t) { CheckGetIntProperty<int8_t>(); }
+TEST(properties, GetIntProperty_int16_t) { CheckGetIntProperty<int16_t>(); }
+TEST(properties, GetIntProperty_int32_t) { CheckGetIntProperty<int32_t>(); }
+TEST(properties, GetIntProperty_int64_t) { CheckGetIntProperty<int64_t>(); }
+
+TEST(properties, GetUintProperty_uint8_t) { CheckGetUintProperty<uint8_t>(); }
+TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
+TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
+TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index ea0f82c..e6b3573 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -38,18 +38,18 @@
 
 public:
             typedef TYPE    value_type;
-    
-    /*! 
+
+    /*!
      * Constructors and destructors
      */
-    
+
                             SortedVector();
                             SortedVector(const SortedVector<TYPE>& rhs);
     virtual                 ~SortedVector();
 
     /*! copy operator */
-    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;    
-    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);    
+    const SortedVector<TYPE>&   operator = (const SortedVector<TYPE>& rhs) const;
+    SortedVector<TYPE>&         operator = (const SortedVector<TYPE>& rhs);
 
     /*
      * empty the vector
@@ -57,7 +57,7 @@
 
     inline  void            clear()             { VectorImpl::clear(); }
 
-    /*! 
+    /*!
      * vector stats
      */
 
@@ -70,11 +70,11 @@
     //! sets the capacity. capacity can never be reduced less than size()
     inline  ssize_t         setCapacity(size_t size)    { return VectorImpl::setCapacity(size); }
 
-    /*! 
+    /*!
      * C-style array access
      */
-     
-    //! read-only C-style access 
+
+    //! read-only C-style access
     inline  const TYPE*     array() const;
 
     //! read-write C-style access. BE VERY CAREFUL when modifying the array
@@ -83,12 +83,12 @@
 
             //! finds the index of an item
             ssize_t         indexOf(const TYPE& item) const;
-            
+
             //! finds where this item should be inserted
             size_t          orderOf(const TYPE& item) const;
-            
-    
-    /*! 
+
+
+    /*!
      * accessors
      */
 
@@ -105,7 +105,7 @@
 
             //! add an item in the right place (and replace the one that is there)
             ssize_t         add(const TYPE& item);
-            
+
             //! editItemAt() MUST NOT change the order of this item
             TYPE&           editItemAt(size_t index) {
                 return *( static_cast<TYPE *>(VectorImpl::editItemLocation(index)) );
@@ -114,7 +114,7 @@
             //! merges a vector into this one
             ssize_t         merge(const Vector<TYPE>& vector);
             ssize_t         merge(const SortedVector<TYPE>& vector);
-            
+
             //! removes an item
             ssize_t         remove(const TYPE&);
 
@@ -122,7 +122,24 @@
     inline  ssize_t         removeItemsAt(size_t index, size_t count = 1);
     //! remove one item
     inline  ssize_t         removeAt(size_t index)  { return removeItemsAt(index); }
-            
+
+    /*
+     * these inlines add some level of compatibility with STL.
+     */
+    typedef TYPE* iterator;
+    typedef TYPE const* const_iterator;
+
+    inline iterator begin() { return editArray(); }
+    inline iterator end()   { return editArray() + size(); }
+    inline const_iterator begin() const { return array(); }
+    inline const_iterator end() const   { return array() + size(); }
+    inline void reserve(size_t n) { setCapacity(n); }
+    inline bool empty() const{ return isEmpty(); }
+    inline iterator erase(iterator pos) {
+        ssize_t index = removeItemsAt(pos-array());
+        return begin() + index;
+    }
+
 protected:
     virtual void    do_construct(void* storage, size_t num) const;
     virtual void    do_destroy(void* storage, size_t num) const;
@@ -160,13 +177,13 @@
 template<class TYPE> inline
 SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
     SortedVectorImpl::operator = (rhs);
-    return *this; 
+    return *this;
 }
 
 template<class TYPE> inline
 const SortedVector<TYPE>& SortedVector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
     SortedVectorImpl::operator = (rhs);
-    return *this; 
+    return *this;
 }
 
 template<class TYPE> inline
diff --git a/init/init.cpp b/init/init.cpp
index 957527b..7a0e114 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,6 +18,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <fstream>
 #include <libgen.h>
 #include <paths.h>
 #include <signal.h>
@@ -248,6 +249,113 @@
     return result;
 }
 
+static void security_failure() {
+    LOG(ERROR) << "Security failure; rebooting into recovery mode...";
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (true) { pause(); }  // never reached
+}
+
+#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
+#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
+
+/* __attribute__((unused)) due to lack of mips support: see mips block
+ * in set_mmap_rnd_bits_action */
+static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
+    std::string path;
+    if (compat) {
+        path = MMAP_RND_COMPAT_PATH;
+    } else {
+        path = MMAP_RND_PATH;
+    }
+    std::ifstream inf(path, std::fstream::in);
+    if (!inf) {
+        LOG(ERROR) << "Cannot open for reading: " << path;
+        return false;
+    }
+    while (start >= min) {
+        // try to write out new value
+        std::string str_val = std::to_string(start);
+        std::ofstream of(path, std::fstream::out);
+        if (!of) {
+            LOG(ERROR) << "Cannot open for writing: " << path;
+            return false;
+        }
+        of << str_val << std::endl;
+        of.close();
+
+        // check to make sure it was recorded
+        inf.seekg(0);
+        std::string str_rec;
+        inf >> str_rec;
+        if (str_val.compare(str_rec) == 0) {
+            break;
+        }
+        start--;
+    }
+    inf.close();
+    if (start < min) {
+        LOG(ERROR) << "Unable to set minimum required entropy " << min << " in " << path;
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Set /proc/sys/vm/mmap_rnd_bits and potentially
+ * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
+ * Returns -1 if unable to set these to an acceptable value.
+ *
+ * To support this sysctl, the following upstream commits are needed:
+ *
+ * d07e22597d1d mm: mmap: add new /proc tunable for mmap_base ASLR
+ * e0c25d958f78 arm: mm: support ARCH_MMAP_RND_BITS
+ * 8f0d3aa9de57 arm64: mm: support ARCH_MMAP_RND_BITS
+ * 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
+ * ec9ee4acd97c drivers: char: random: add get_random_long()
+ * 5ef11c35ce86 mm: ASLR: use get_random_long()
+ */
+static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
+{
+    int ret = -1;
+
+    /* values are arch-dependent */
+#if defined(__aarch64__)
+    /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
+    if (set_mmap_rnd_bits_min(33, 24, false)
+            && set_mmap_rnd_bits_min(16, 16, true)) {
+        ret = 0;
+    }
+#elif defined(__x86_64__)
+    /* x86_64 supports 28 - 32 bits */
+    if (set_mmap_rnd_bits_min(32, 32, false)
+            && set_mmap_rnd_bits_min(16, 16, true)) {
+        ret = 0;
+    }
+#elif defined(__arm__) || defined(__i386__)
+    /* check to see if we're running on 64-bit kernel */
+    bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
+    /* supported 32-bit architecture must have 16 bits set */
+    if (set_mmap_rnd_bits_min(16, 16, h64)) {
+        ret = 0;
+    }
+#elif defined(__mips__) || defined(__mips64__)
+    // TODO: add mips support b/27788820
+    ret = 0;
+#else
+    ERROR("Unknown architecture\n");
+#endif
+
+#ifdef __BRILLO__
+    // TODO: b/27794137
+    ret = 0;
+#endif
+    if (ret == -1) {
+        LOG(ERROR) << "Unable to set adequate mmap entropy value!";
+        security_failure();
+    }
+    return ret;
+}
+
 static int keychord_init_action(const std::vector<std::string>& args)
 {
     keychord_init();
@@ -401,12 +509,6 @@
     return 0;
 }
 
-static void security_failure() {
-    LOG(ERROR) << "Security failure; rebooting into recovery mode...";
-    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
-    while (true) { pause(); }  // never reached
-}
-
 static void selinux_initialize(bool in_kernel_domain) {
     Timer t;
 
@@ -674,6 +776,7 @@
     am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
     // ... so that we can start queuing up actions that require stuff from /dev.
     am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
+    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
     am.QueueBuiltinAction(keychord_init_action, "keychord_init");
     am.QueueBuiltinAction(console_init_action, "console_init");
 
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index adb0f8d..024c5ee 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -84,6 +84,7 @@
 
 Looper::~Looper() {
     close(mWakeEventFd);
+    mWakeEventFd = -1;
     if (mEpollFd >= 0) {
         close(mEpollFd);
     }
@@ -413,7 +414,8 @@
     ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd, &inc, sizeof(uint64_t)));
     if (nWrite != sizeof(uint64_t)) {
         if (errno != EAGAIN) {
-            ALOGW("Could not write wake signal: %s", strerror(errno));
+            LOG_ALWAYS_FATAL("Could not write wake signal to fd %d: %s",
+                    mWakeEventFd, strerror(errno));
         }
     }
 }
diff --git a/libutils/SharedBuffer.cpp b/libutils/SharedBuffer.cpp
index 6c8c7d3..d4fb3f9 100644
--- a/libutils/SharedBuffer.cpp
+++ b/libutils/SharedBuffer.cpp
@@ -111,16 +111,26 @@
 
 int32_t SharedBuffer::release(uint32_t flags) const
 {
-    int32_t prev = 1;
-    if (onlyOwner()
-            || (((prev = mRefs.fetch_sub(1, std::memory_order_release)) == 1)
-                && (atomic_thread_fence(std::memory_order_acquire), true))) {
+    const bool useDealloc = ((flags & eKeepStorage) == 0);
+    if (onlyOwner()) {
+        // Since we're the only owner, our reference count goes to zero.
         mRefs.store(0, std::memory_order_relaxed);
-        if ((flags & eKeepStorage) == 0) {
-            free(const_cast<SharedBuffer*>(this));
+        if (useDealloc) {
+            dealloc(this);
+        }
+        // As the only owner, our previous reference count was 1.
+        return 1;
+    }
+    // There's multiple owners, we need to use an atomic decrement.
+    int32_t prevRefCount = mRefs.fetch_sub(1, std::memory_order_release);
+    if (prevRefCount == 1) {
+        // We're the last reference, we need the acquire fence.
+        atomic_thread_fence(std::memory_order_acquire);
+        if (useDealloc) {
+            dealloc(this);
         }
     }
-    return prev;
+    return prevRefCount;
 }
 
 
diff --git a/libziparchive/testdata/crash.apk b/libziparchive/testdata/crash.apk
new file mode 100644
index 0000000..d6dd52d
--- /dev/null
+++ b/libziparchive/testdata/crash.apk
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 4649a75..45f6f0f 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -270,9 +270,14 @@
    * Grab the CD offset and size, and the number of entries in the
    * archive and verify that they look reasonable.
    */
-  if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
+  if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
     ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
         eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
+#if defined(__ANDROID__)
+    if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
+      android_errorWriteLog(0x534e4554, "31251826");
+    }
+#endif
     return kInvalidOffset;
   }
   if (eocd->num_records == 0) {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 6aee1bb..42eb5ee 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -36,6 +36,7 @@
 static const std::string kValidZip = "valid.zip";
 static const std::string kLargeZip = "large.zip";
 static const std::string kBadCrcZip = "bad_crc.zip";
+static const std::string kCrashApk = "crash.apk";
 
 static const std::vector<uint8_t> kATxtContents {
   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
@@ -84,6 +85,12 @@
   CloseArchive(handle);
 }
 
+TEST(ziparchive, OutOfBound) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
+  CloseArchive(handle);
+}
+
 TEST(ziparchive, OpenMissing) {
   ZipArchiveHandle handle;
   ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 86860b1..498216d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -302,7 +302,8 @@
     # Mount shared so changes propagate into child namespaces
     mount rootfs rootfs / shared rec
     # Mount default storage into root namespace
-    mount none /mnt/runtime/default /storage slave bind rec
+    mount none /mnt/runtime/default /storage bind rec
+    mount none none /storage slave rec
 
     # Make sure /sys/kernel/debug (if present) is labeled properly
     restorecon_recursive /sys/kernel/debug
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 7e13df9..8725113 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -19,6 +19,7 @@
 /dev/hw_random            0440   root       system
 /dev/ashmem               0666   root       root
 /dev/binder               0666   root       root
+/dev/hwbinder             0666   root       root
 
 # Anyone can read the logs, but if they're not in the "logs"
 # group, then they'll only see log entries for their UID.