Merge "Improve "adb help" output."
diff --git a/adf/libadfhwc/Android.bp b/adf/libadfhwc/Android.bp
index 86f0c9c..57a8d76 100644
--- a/adf/libadfhwc/Android.bp
+++ b/adf/libadfhwc/Android.bp
@@ -21,7 +21,7 @@
         "libutils",
     ],
     cflags: [
-        "-DLOG_TAG=\\\"adfhwc\\\"",
+        "-DLOG_TAG=\"adfhwc\"",
         "-Werror",
     ],
     local_include_dirs: ["include"],
diff --git a/include/cutils/native_handle.h b/include/cutils/native_handle.h
index 268c5d3..31695cb 100644
--- a/include/cutils/native_handle.h
+++ b/include/cutils/native_handle.h
@@ -26,7 +26,14 @@
     int version;        /* sizeof(native_handle_t) */
     int numFds;         /* number of file-descriptors at &data[0] */
     int numInts;        /* number of ints at &data[numFds] */
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#endif
     int data[0];        /* numFds + numInts ints */
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
 } native_handle_t;
 
 /*
diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h
index c37ac60..22b811a 100644
--- a/include/utils/Flattenable.h
+++ b/include/utils/Flattenable.h
@@ -31,32 +31,32 @@
 
 class FlattenableUtils {
 public:
-    template<int N>
+    template<size_t N>
     static size_t align(size_t size) {
         COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
         return (size + (N-1)) & ~(N-1);
     }
 
-    template<int N>
+    template<size_t N>
     static size_t align(void const*& buffer) {
         COMPILE_TIME_ASSERT_FUNCTION_SCOPE( !(N & (N-1)) );
-        intptr_t b = intptr_t(buffer);
-        buffer = (void*)((intptr_t(buffer) + (N-1)) & ~(N-1));
-        return size_t(intptr_t(buffer) - b);
+        uintptr_t b = uintptr_t(buffer);
+        buffer = reinterpret_cast<void*>((uintptr_t(buffer) + (N-1)) & ~(N-1));
+        return size_t(uintptr_t(buffer) - b);
     }
 
-    template<int N>
+    template<size_t N>
     static size_t align(void*& buffer) {
         return align<N>( const_cast<void const*&>(buffer) );
     }
 
     static void advance(void*& buffer, size_t& size, size_t offset) {
-        buffer = reinterpret_cast<void*>( intptr_t(buffer) + offset );
+        buffer = reinterpret_cast<void*>( uintptr_t(buffer) + offset );
         size -= offset;
     }
 
     static void advance(void const*& buffer, size_t& size, size_t offset) {
-        buffer = reinterpret_cast<void const*>( intptr_t(buffer) + offset );
+        buffer = reinterpret_cast<void const*>( uintptr_t(buffer) + offset );
         size -= offset;
     }
 
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index e3d19e1..92579e2 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -157,7 +157,7 @@
 VALUE& KeyedVector<KEY,VALUE>::editValueFor(const KEY& key) {
     ssize_t i = this->indexOfKey(key);
     LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
-    return mVector.editItemAt(i).value;
+    return mVector.editItemAt(static_cast<size_t>(i)).value;
 }
 
 template<typename KEY, typename VALUE> inline
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index c6466d3..36016cd 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -206,17 +206,29 @@
 
 // ---------------------------------------------------------------------------
 
+// RefererenceRenamer is pure abstract, there is no virtual method
+// implementation to put in a translation unit in order to silence the
+// weak vtables warning.
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
 class ReferenceRenamer {
 protected:
     // destructor is purposedly not virtual so we avoid code overhead from
     // subclasses; we have to make it protected to guarantee that it
     // cannot be called from this base class (and to make strict compilers
     // happy).
-    ~ReferenceRenamer();
+    ~ReferenceRenamer() { }
 public:
     virtual void operator()(size_t i) const = 0;
 };
 
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
 // ---------------------------------------------------------------------------
 
 class RefBase
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index 6275793..2a25227 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -151,16 +151,21 @@
     }
 }
 
-template<typename TYPE> inline
-void copy_type(TYPE* d, const TYPE* s, size_t n) {
-    if (!traits<TYPE>::has_trivial_copy) {
-        while (n > 0) {
-            n--;
-            new(d) TYPE(*s);
-            d++, s++;
-        }
-    } else {
-        memcpy(d,s,n*sizeof(TYPE));
+template<typename TYPE>
+typename std::enable_if<traits<TYPE>::has_trivial_copy>::type
+inline
+copy_type(TYPE* d, const TYPE* s, size_t n) {
+    memcpy(d,s,n*sizeof(TYPE));
+}
+
+template<typename TYPE>
+typename std::enable_if<!traits<TYPE>::has_trivial_copy>::type
+inline
+copy_type(TYPE* d, const TYPE* s, size_t n) {
+    while (n > 0) {
+        n--;
+        new(d) TYPE(*s);
+        d++, s++;
     }
 }
 
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index 81ac9c7..b6d5686 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -194,7 +194,7 @@
      inline void push_back(const TYPE& item)  { insertAt(item, size(), 1); }
      inline void push_front(const TYPE& item) { insertAt(item, 0, 1); }
      inline iterator erase(iterator pos) {
-         ssize_t index = removeItemsAt(pos-array());
+         ssize_t index = removeItemsAt(static_cast<size_t>(pos-array()));
          return begin() + index;
      }
 
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index ada7d5f..06d0e28 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -19,6 +19,7 @@
     target: {
         android: {
             srcs: [
+                "AshmemTest.cpp",
                 "MemsetTest.cpp",
                 "PropertiesTest.cpp",
                 "sched_policy_test.cpp",
diff --git a/libcutils/tests/AshmemTest.cpp b/libcutils/tests/AshmemTest.cpp
new file mode 100644
index 0000000..51c679f
--- /dev/null
+++ b/libcutils/tests/AshmemTest.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 <sys/mman.h>
+#include <cutils/ashmem.h>
+#include <gtest/gtest.h>
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+void TestCreateRegion(size_t size, unique_fd &fd, int prot) {
+    fd = unique_fd(ashmem_create_region(nullptr, size));
+    ASSERT_TRUE(fd >= 0);
+    ASSERT_TRUE(ashmem_valid(fd));
+    ASSERT_EQ(size, static_cast<size_t>(ashmem_get_size_region(fd)));
+    ASSERT_EQ(0, ashmem_set_prot_region(fd, prot));
+}
+
+void TestMmap(const unique_fd &fd, size_t size, int prot, void **region) {
+    *region = mmap(nullptr, size, prot, MAP_SHARED, fd, 0);
+    ASSERT_NE(MAP_FAILED, *region);
+}
+
+void TestProtDenied(const unique_fd &fd, size_t size, int prot) {
+    EXPECT_EQ(MAP_FAILED, mmap(nullptr, size, prot, MAP_SHARED, fd, 0));
+}
+
+void FillData(uint8_t* data, size_t dataLen) {
+    for (size_t i = 0; i < dataLen; i++) {
+        data[i] = i & 0xFF;
+    }
+}
+
+TEST(AshmemTest, BasicTest) {
+    constexpr size_t size = PAGE_SIZE;
+    uint8_t data[size];
+    FillData(data, size);
+
+    unique_fd fd;
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+
+    void *region1;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region1));
+
+    memcpy(region1, &data, size);
+    ASSERT_EQ(0, memcmp(region1, &data, size));
+
+    EXPECT_EQ(0, munmap(region1, size));
+
+    void *region2;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, &region2));
+    ASSERT_EQ(0, memcmp(region2, &data, size));
+    EXPECT_EQ(0, munmap(region2, size));
+}
+
+TEST(AshmemTest, ForkTest) {
+    constexpr size_t size = PAGE_SIZE;
+    uint8_t data[size];
+    FillData(data, size);
+
+    unique_fd fd;
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+
+    void *region1;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region1));
+
+    memcpy(region1, &data, size);
+    ASSERT_EQ(0, memcmp(region1, &data, size));
+    EXPECT_EQ(0, munmap(region1, size));
+
+    ASSERT_EXIT({
+        void *region2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+        if (region2 == MAP_FAILED) {
+            _exit(1);
+        }
+        if (memcmp(region2, &data, size) != 0) {
+            _exit(2);
+        }
+        memset(region2, 0, size);
+        munmap(region2, size);
+        _exit(0);
+    }, ::testing::ExitedWithCode(0),"");
+
+    memset(&data, 0, size);
+    void *region2;
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ | PROT_WRITE, &region2));
+    ASSERT_EQ(0, memcmp(region2, &data, size));
+    EXPECT_EQ(0, munmap(region2, size));
+}
+
+TEST(AshmemTest, ProtTest) {
+    unique_fd fd;
+    constexpr size_t size = PAGE_SIZE;
+    void *region;
+
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ));
+    TestProtDenied(fd, size, PROT_WRITE);
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_READ, &region));
+    EXPECT_EQ(0, munmap(region, size));
+
+    ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_WRITE));
+    TestProtDenied(fd, size, PROT_READ);
+    ASSERT_NO_FATAL_FAILURE(TestMmap(fd, size, PROT_WRITE, &region));
+    EXPECT_EQ(0, munmap(region, size));
+}
+
+TEST(AshmemTest, ForkProtTest) {
+    unique_fd fd;
+    constexpr size_t size = PAGE_SIZE;
+
+    int protFlags[] = { PROT_READ, PROT_WRITE };
+    for (int i = 0; i < 2; i++) {
+        ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd, PROT_READ | PROT_WRITE));
+        ASSERT_EXIT({
+            if (ashmem_set_prot_region(fd, protFlags[i]) >= 0) {
+                _exit(0);
+            } else {
+                _exit(1);
+            }
+        }, ::testing::ExitedWithCode(0), "");
+        ASSERT_NO_FATAL_FAILURE(TestProtDenied(fd, size, protFlags[1-i]));
+    }
+}
+
+TEST(AshmemTest, ForkMultiRegionTest) {
+    constexpr size_t size = PAGE_SIZE;
+    uint8_t data[size];
+    FillData(data, size);
+
+    constexpr int nRegions = 16;
+    unique_fd fd[nRegions];
+    for (int i = 0; i < nRegions; i++) {
+        ASSERT_NO_FATAL_FAILURE(TestCreateRegion(size, fd[i], PROT_READ | PROT_WRITE));
+        void *region;
+        ASSERT_NO_FATAL_FAILURE(TestMmap(fd[i], size, PROT_READ | PROT_WRITE, &region));
+        memcpy(region, &data, size);
+        ASSERT_EQ(0, memcmp(region, &data, size));
+        EXPECT_EQ(0, munmap(region, size));
+    }
+
+    ASSERT_EXIT({
+        for (int i = 0; i < nRegions; i++) {
+            void *region = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd[i], 0);
+            if (region == MAP_FAILED) {
+                _exit(1);
+            }
+            if (memcmp(region, &data, size) != 0) {
+                munmap(region, size);
+                _exit(2);
+            }
+            memset(region, 0, size);
+            munmap(region, size);
+        }
+        _exit(0);
+    }, ::testing::ExitedWithCode(0), "");
+
+    memset(&data, 0, size);
+    for (int i = 0; i < nRegions; i++) {
+        void *region;
+        ASSERT_NO_FATAL_FAILURE(TestMmap(fd[i], size, PROT_READ | PROT_WRITE, &region));
+        ASSERT_EQ(0, memcmp(region, &data, size));
+        EXPECT_EQ(0, munmap(region, size));
+    }
+}
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 65bbc1e..7c15429 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -203,9 +203,8 @@
 {
     std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path), closedir);
     if (uid != NULL) {
-        struct dirent cur;
-        struct dirent *dir;
-        while ((readdir_r(uid.get(), &cur, &dir) == 0) && dir) {
+        dirent* dir;
+        while ((dir = readdir(uid.get())) != nullptr) {
             char path[PROCESSGROUP_MAX_PATH_LEN];
 
             if (dir->d_type != DT_DIR) {
@@ -231,9 +230,8 @@
     if (root == NULL) {
         PLOG(ERROR) << "failed to open " << cgroup_root_path;
     } else {
-        struct dirent cur;
-        struct dirent *dir;
-        while ((readdir_r(root.get(), &cur, &dir) == 0) && dir) {
+        dirent* dir;
+        while ((dir = readdir(root.get())) != nullptr) {
             char path[PROCESSGROUP_MAX_PATH_LEN];
 
             if (dir->d_type != DT_DIR) {
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index 4e87a98..73ed4eb 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -131,9 +131,6 @@
 }
 
 void ProcessCallStack::update() {
-    struct dirent *ep;
-    struct dirent entry;
-
     std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(PATH_SELF_TASK), closedir);
     if (dp == NULL) {
         ALOGE("%s: Failed to update the process's call stacks: %s",
@@ -158,8 +155,8 @@
      * Each tid is a directory inside of /proc/self/task
      * - Read every file in directory => get every tid
      */
-    int code;
-    while ((code = readdir_r(dp.get(), &entry, &ep)) == 0 && ep != NULL) {
+    dirent* ep;
+    while ((ep = readdir(dp.get())) != NULL) {
         pid_t tid = -1;
         sscanf(ep->d_name, "%d", &tid);
 
@@ -194,10 +191,6 @@
         ALOGV("%s: Got call stack for tid %d (size %zu)",
               __FUNCTION__, tid, threadInfo.callStack.size());
     }
-    if (code != 0) { // returns positive error value on error
-        ALOGE("%s: Failed to readdir from %s: %s",
-              __FUNCTION__, PATH_SELF_TASK, strerror(code));
-    }
 }
 
 void ProcessCallStack::log(const char* logtag, android_LogPriority priority,
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index ba1aaee..1f8395b 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -770,8 +770,6 @@
     ref->mRefs->renameWeakRefId(old_id, new_id);
 }
 
-ReferenceRenamer::~ReferenceRenamer() {}
-
 VirtualLightRefBase::~VirtualLightRefBase() {}
 
 }; // namespace android