Merge "Convert half4 color to float array for buffer copy"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index a48dab9..0bdca2d 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -130,6 +130,14 @@
         { REQ,      "events/irq/enable" },
         { OPT,      "events/ipi/enable" },
     } },
+    { "irqoff",     "IRQ-disabled code section tracing", 0, {
+        { REQ,      "events/preemptirq/irq_enable/enable" },
+        { REQ,      "events/preemptirq/irq_disable/enable" },
+    } },
+    { "preemptoff", "Preempt-disabled code section tracing", 0, {
+        { REQ,      "events/preemptirq/preempt_enable/enable" },
+        { REQ,      "events/preemptirq/preempt_disable/enable" },
+    } },
     { "i2c",        "I2C Events",   0, {
         { REQ,      "events/i2c/enable" },
         { REQ,      "events/i2c/i2c_read/enable" },
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index e866b8b..ea7109b 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -103,6 +103,12 @@
     return *this;
 }
 
+CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() {
+    if (!PropertiesHelper::IsUserBuild())
+        values.account_mode_ = SU_ROOT;
+    return *this;
+}
+
 CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::DropRoot() {
     values.account_mode_ = DROP_ROOT;
     return *this;
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 5a8ce5b..698ceff 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -89,6 +89,8 @@
         CommandOptionsBuilder& Always();
         /* Sets the command's PrivilegeMode as `SU_ROOT` */
         CommandOptionsBuilder& AsRoot();
+        /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */
+        CommandOptionsBuilder& AsRootIfAvailable();
         /* Sets the command's PrivilegeMode as `DROP_ROOT` */
         CommandOptionsBuilder& DropRoot();
         /* Sets the command's OutputMode as `REDIRECT_TO_STDERR` */
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c41edf5..b6b34fb 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1069,14 +1069,15 @@
         RunCommand(
                 "HARDWARE HALS",
                 {"lshal", std::string("--debug=") + kLsHalDebugPath},
-                CommandOptions::AS_ROOT);
+                CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
 
         ds.AddZipEntry("lshal-debug.txt", kLsHalDebugPath);
 
         unlink(kLsHalDebugPath.c_str());
     } else {
         RunCommand(
-                "HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::AS_ROOT);
+                "HARDWARE HALS", {"lshal", "--debug"},
+                CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
     }
 
     RunCommand("PRINTENV", {"printenv"});
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index a94cf99..92b0c0d 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -477,6 +477,48 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
+        return;
+    }
+    if (!PropertiesHelper::IsUserBuild()) {
+        // Emulates user build if necessarily.
+        SetBuildType("user");
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
+        return;
+    }
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+        return;
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("0\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
 TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
     EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
     EXPECT_THAT(out,
@@ -1053,6 +1095,51 @@
     EXPECT_THAT(err, StrEq("stderr\n"));
 }
 
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnUserBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnUserBuild() on test suite\n")
+        return;
+    }
+    CreateFd("RunCommandAsRootIfAvailableOnUserBuild.txt");
+    if (!PropertiesHelper::IsUserBuild()) {
+        // Emulates user build if necessarily.
+        SetBuildType("user");
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
+TEST_F(DumpstateUtilTest, RunCommandAsRootIfAvailableOnDebugBuild) {
+    if (!IsStandalone()) {
+        // TODO: temporarily disabled because it might cause other tests to fail after dropping
+        // to Shell - need to refactor tests to avoid this problem)
+        MYLOGE("Skipping DumpstateUtilTest.RunCommandAsRootIfAvailableOnDebugBuild() on test suite\n")
+        return;
+    }
+    CreateFd("RunCommandAsRootIfAvailableOnDebugBuild.txt");
+    if (PropertiesHelper::IsUserBuild()) {
+        ALOGI("Skipping RunCommandAsRootNonUserBuild on user builds\n");
+        return;
+    }
+
+    DropRoot();
+
+    EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+                            CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+    EXPECT_THAT(out, StrEq("0\nstdout\n"));
+    EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
 TEST_F(DumpstateUtilTest, RunCommandDropRoot) {
     if (!IsStandalone()) {
         // TODO: temporarily disabled because it might cause other tests to fail after dropping
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a72be59..4246536 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -525,6 +525,9 @@
         if (access(path.c_str(), F_OK) == 0) {
             if (delete_dir_contents(path) != 0) {
                 res = error("Failed to delete contents of " + path);
+            } else if ((flags & (FLAG_CLEAR_CACHE_ONLY | FLAG_CLEAR_CODE_CACHE_ONLY)) == 0) {
+                remove_path_xattr(path, kXattrInodeCache);
+                remove_path_xattr(path, kXattrInodeCodeCache);
             }
         }
     }
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c25b2ce..c21fae5 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -724,6 +724,12 @@
     }
 }
 
+void remove_path_xattr(const std::string& path, const char* inode_xattr) {
+    if (removexattr(path.c_str(), inode_xattr) && errno != ENODATA) {
+        PLOG(ERROR) << "Failed to remove xattr " << inode_xattr << " at " << path;
+    }
+}
+
 /**
  * Validate that the path is valid in the context of the provided directory.
  * The path is allowed to have at most one subdirectory and no indirections
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5af5756..3e04af9 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -110,6 +110,7 @@
 
 int write_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
 std::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
+void remove_path_xattr(const std::string& path, const char* inode_xattr);
 
 int validate_system_app_path(const char* path);
 bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
diff --git a/data/etc/android.hardware.wifi.rtt.xml b/data/etc/android.hardware.wifi.rtt.xml
new file mode 100644
index 0000000..60529ea
--- /dev/null
+++ b/data/etc/android.hardware.wifi.rtt.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+
+<!-- This is the standard feature indicating that the device supports WiFi RTT (IEEE 802.11mc). -->
+<permissions>
+    <feature name="android.hardware.wifi.rtt" />
+</permissions>
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 455f2c4..bf41e0b 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -215,7 +215,7 @@
         int target = cs_pair ? num % server_count : rand() % workers.size();
         int sz = payload_size;
 
-        while (sz > sizeof(uint32_t)) {
+        while (sz >= sizeof(uint32_t)) {
             data.writeInt32(0);
             sz -= sizeof(uint32_t);
         }
@@ -381,6 +381,7 @@
             // No need to run training round in this case.
             if (atoi(argv[i+1]) > 0) {
                 max_time_bucket = strtoull(argv[i+1], (char **)NULL, 10) * 1000;
+                time_per_bucket = max_time_bucket / num_buckets;
                 i++;
             } else {
                 cout << "Max latency -m must be positive." << endl;
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index e1b9a8a..77f06bb 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -426,7 +426,13 @@
 
     std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
 
-    mCallbacks[descriptor] = {callbackData, pointer};
+    if (pointer != nullptr) {
+        mCallbacks[descriptor] = {callbackData, pointer};
+    } else {
+        ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
+        mCallbacks.erase(descriptor);
+        return Error::None;
+    }
 
     bool hasPendingInvalidate = false;
     std::vector<hwc2_display_t> displayIds;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index f5b896b..e54f147 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -1082,11 +1082,15 @@
  * Note that approach 2) is sensitive to the proper ordering of the data in time, since
  * the boundary condition must be applied to the oldest sample to be accurate.
  */
+static float kineticEnergyToVelocity(float work) {
+    static constexpr float sqrt2 = 1.41421356237;
+    return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2;
+}
+
 static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) {
     // The input should be in reversed time order (most recent sample at index i=0)
     // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function
     static constexpr float NANOS_PER_SECOND = 1E-9;
-    static constexpr float sqrt2 = 1.41421356237;
 
     if (count < 2) {
         return 0; // if 0 or 1 points, velocity is zero
@@ -1103,21 +1107,19 @@
     }
     // Guaranteed to have at least 3 points here
     float work = 0;
-    float vprev, vcurr; // v[i-1] and v[i], respectively
-    vprev = 0;
     for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time
         if (t[i] == t[i-1]) {
             ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]);
             continue;
         }
-        vcurr = (x[i] - x[i-1]) / (NANOS_PER_SECOND * (t[i] - t[i-1]));
+        float vprev = kineticEnergyToVelocity(work); // v[i-1]
+        float vcurr = (x[i] - x[i-1]) / (NANOS_PER_SECOND * (t[i] - t[i-1])); // v[i]
         work += (vcurr - vprev) * fabsf(vcurr);
         if (i == count - 1) {
             work *= 0.5; // initial condition, case 2) above
         }
-        vprev = vcurr;
     }
-    return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2;
+    return kineticEnergyToVelocity(work);
 }
 
 bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index eb2e858..a2664f1 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -71,6 +71,7 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
         "libbase",
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 0eb08e5..1f746a2 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -39,9 +39,15 @@
 Mapper::Mapper()
 {
     mMapper = IMapper::getService();
-    if (mMapper == nullptr || mMapper->isRemote()) {
+    if (mMapper == nullptr) {
+        LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+    }
+    if (mMapper->isRemote()) {
         LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
     }
+
+    // IMapper 2.1 is optional
+    mMapperV2_1 = hardware::graphics::mapper::V2_1::IMapper::castFrom(mMapper);
 }
 
 Error Mapper::createDescriptor(
@@ -91,6 +97,50 @@
             buffer, error);
 }
 
+Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
+        const IMapper::BufferDescriptorInfo& descriptorInfo,
+        uint32_t stride) const
+{
+    if (mMapperV2_1 == nullptr) {
+        return Error::NONE;
+    }
+
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
+
+    return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+}
+
+void Mapper::getTransportSize(buffer_handle_t bufferHandle,
+        uint32_t* outNumFds, uint32_t* outNumInts) const
+{
+    *outNumFds = uint32_t(bufferHandle->numFds);
+    *outNumInts = uint32_t(bufferHandle->numInts);
+
+    if (mMapperV2_1 == nullptr) {
+        return;
+    }
+
+    Error error;
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+    auto ret = mMapperV2_1->getTransportSize(buffer,
+            [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) {
+                error = tmpError;
+                if (error != Error::NONE) {
+                    return;
+                }
+
+                *outNumFds = tmpNumFds;
+                *outNumInts = tmpNumInts;
+            });
+
+    if (!ret.isOk()) {
+        error = kTransactionError;
+    }
+    ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
+            buffer, error);
+}
+
 Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
         const IMapper::Rect& accessRegion,
         int acquireFence, void** outData) const
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c880500..4ed2aa4 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -170,6 +170,8 @@
             inUsage, &handle, &outStride, mId,
             std::move(requestorName));
     if (err == NO_ERROR) {
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+
         width = static_cast<int>(inWidth);
         height = static_cast<int>(inHeight);
         format = inFormat;
@@ -199,7 +201,8 @@
 
     if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, width, height,
+                layerCount, format, usage, stride, &importedHandle);
         if (err != NO_ERROR) {
             initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
 
@@ -212,6 +215,7 @@
         }
 
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     ANativeWindowBuffer::handle = handle;
@@ -323,11 +327,11 @@
 }
 
 size_t GraphicBuffer::getFlattenedSize() const {
-    return static_cast<size_t>(13 + (handle ? handle->numInts : 0)) * sizeof(int);
+    return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
 }
 
 size_t GraphicBuffer::getFdCount() const {
-    return static_cast<size_t>(handle ? handle->numFds : 0);
+    return static_cast<size_t>(handle ? mTransportNumFds : 0);
 }
 
 status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
@@ -353,18 +357,18 @@
     buf[12] = int(usage >> 32); // high 32-bits
 
     if (handle) {
-        buf[10] = handle->numFds;
-        buf[11] = handle->numInts;
-        memcpy(fds, handle->data, static_cast<size_t>(handle->numFds) * sizeof(int));
+        buf[10] = int32_t(mTransportNumFds);
+        buf[11] = int32_t(mTransportNumInts);
+        memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
         memcpy(buf + 13, handle->data + handle->numFds,
-                static_cast<size_t>(handle->numInts) * sizeof(int));
+                static_cast<size_t>(mTransportNumInts) * sizeof(int));
     }
 
     buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
     size -= sizeNeeded;
     if (handle) {
-        fds += handle->numFds;
-        count -= static_cast<size_t>(handle->numFds);
+        fds += mTransportNumFds;
+        count -= static_cast<size_t>(mTransportNumFds);
     }
 
     return NO_ERROR;
@@ -457,7 +461,8 @@
 
     if (handle != 0) {
         buffer_handle_t importedHandle;
-        status_t err = mBufferMapper.importBuffer(handle, &importedHandle);
+        status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
+                uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
         if (err != NO_ERROR) {
             width = height = stride = format = usage_deprecated = 0;
             layerCount = 0;
@@ -470,6 +475,7 @@
         native_handle_close(handle);
         native_handle_delete(const_cast<native_handle_t*>(handle));
         handle = importedHandle;
+        mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
     }
 
     buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 1634328..672dc36 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -52,17 +52,42 @@
 }
 
 status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
+        uint32_t width, uint32_t height, uint32_t layerCount,
+        PixelFormat format, uint64_t usage, uint32_t stride,
         buffer_handle_t* outHandle)
 {
     ATRACE_CALL();
 
+    buffer_handle_t bufferHandle;
     Gralloc2::Error error = mMapper->importBuffer(
-            hardware::hidl_handle(rawHandle), outHandle);
+            hardware::hidl_handle(rawHandle), &bufferHandle);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
+        return static_cast<status_t>(error);
+    }
 
-    ALOGW_IF(error != Gralloc2::Error::NONE, "importBuffer(%p) failed: %d",
-            rawHandle, error);
+    Gralloc2::IMapper::BufferDescriptorInfo info = {};
+    info.width = width;
+    info.height = height;
+    info.layerCount = layerCount;
+    info.format = static_cast<Gralloc2::PixelFormat>(format);
+    info.usage = usage;
+    error = mMapper->validateBufferSize(bufferHandle, info, stride);
+    if (error != Gralloc2::Error::NONE) {
+        ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
+        freeBuffer(bufferHandle);
+        return static_cast<status_t>(error);
+    }
 
-    return static_cast<status_t>(error);
+    *outHandle = bufferHandle;
+
+    return NO_ERROR;
+}
+
+void GraphicBufferMapper::getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts)
+{
+    mMapper->getTransportSize(handle, outTransportNumFds, outTransportNumInts);
 }
 
 status_t GraphicBufferMapper::freeBuffer(buffer_handle_t handle)
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 8aee160..69c35f7 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -21,6 +21,7 @@
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -55,6 +56,13 @@
 
     void freeBuffer(buffer_handle_t bufferHandle) const;
 
+    Error validateBufferSize(buffer_handle_t bufferHandle,
+            const IMapper::BufferDescriptorInfo& descriptorInfo,
+            uint32_t stride) const;
+
+    void getTransportSize(buffer_handle_t bufferHandle,
+            uint32_t* outNumFds, uint32_t* outNumInts) const;
+
     // The ownership of acquireFence is always transferred to the callee, even
     // on errors.
     Error lock(buffer_handle_t bufferHandle, uint64_t usage,
@@ -73,6 +81,7 @@
 
 private:
     sp<IMapper> mMapper;
+    sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
 };
 
 // A wrapper to IAllocator
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 95c2d22..e794462 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -230,6 +230,10 @@
     GraphicBufferMapper& mBufferMapper;
     ssize_t mInitCheck;
 
+    // numbers of fds/ints in native_handle_t to flatten
+    uint32_t mTransportNumFds;
+    uint32_t mTransportNumInts;
+
     uint64_t mId;
 
     // Stores the generation number of this buffer. If this number does not
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 06961b1..7cf003d 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -22,6 +22,7 @@
 
 #include <memory>
 
+#include <ui/PixelFormat.h>
 #include <utils/Singleton.h>
 
 
@@ -49,10 +50,15 @@
     // The imported outHandle must be freed with freeBuffer when no longer
     // needed. rawHandle is owned by the caller.
     status_t importBuffer(buffer_handle_t rawHandle,
+            uint32_t width, uint32_t height, uint32_t layerCount,
+            PixelFormat format, uint64_t usage, uint32_t stride,
             buffer_handle_t* outHandle);
 
     status_t freeBuffer(buffer_handle_t handle);
 
+    void getTransportSize(buffer_handle_t handle,
+            uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
+
     status_t lock(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, void** vaddr);
 
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 8d381b1..a7f3a52 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -14,6 +14,7 @@
         "RecentEventLogger.cpp",
         "RotationVectorSensor.cpp",
         "SensorDevice.cpp",
+        "SensorDeviceUtils.cpp",
         "SensorDirectConnection.cpp",
         "SensorEventConnection.cpp",
         "SensorFusion.cpp",
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index da3b275..fdb69d3 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -26,11 +26,10 @@
 #include <cinttypes>
 #include <thread>
 
-using android::hardware::hidl_vec;
-
 using namespace android::hardware::sensors::V1_0;
 using namespace android::hardware::sensors::V1_0::implementation;
-
+using android::hardware::hidl_vec;
+using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -52,7 +51,8 @@
     }
 }
 
-SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
+SensorDevice::SensorDevice()
+        : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
     if (!connectHidlService()) {
         return;
     }
@@ -87,35 +87,29 @@
 }
 
 bool SensorDevice::connectHidlService() {
-    // SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
-    constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
+    // SensorDevice will wait for HAL service to start if HAL is declared in device manifest.
     size_t retry = 10;
 
-    while (true) {
-        int initStep = 0;
+    while (retry-- > 0) {
         mSensors = ISensors::getService();
-        if (mSensors != nullptr) {
-            ++initStep;
-            // Poke ISensor service. If it has lingering connection from previous generation of
-            // system server, it will kill itself. There is no intention to handle the poll result,
-            // which will be done since the size is 0.
-            if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
-                // ok to continue
-                break;
-            }
-            // hidl service is restarting, pointer is invalid.
-            mSensors = nullptr;
-        }
-
-        if (--retry <= 0) {
-            ALOGE("Cannot connect to ISensors hidl service!");
+        if (mSensors == nullptr) {
+            // no sensor hidl service found
             break;
         }
-        // Delay 100ms before retry, hidl service is expected to come up in short time after
-        // crash.
-        ALOGI("%s unsuccessful, try again soon (remaining retry %zu).",
-                (initStep == 0) ? "getService()" : "poll() check", retry);
-        std::this_thread::sleep_for(RETRY_DELAY);
+
+        mRestartWaiter->reset();
+        // Poke ISensor service. If it has lingering connection from previous generation of
+        // system server, it will kill itself. There is no intention to handle the poll result,
+        // which will be done since the size is 0.
+        if(mSensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
+            // ok to continue
+            break;
+        }
+
+        // hidl service is restarting, pointer is invalid.
+        mSensors = nullptr;
+        ALOGI("%s unsuccessful, remaining retry %zu.", __FUNCTION__, retry);
+        mRestartWaiter->wait();
     }
     return (mSensors != nullptr);
 }
@@ -173,7 +167,7 @@
 }
 
 status_t SensorDevice::initCheck() const {
-    return mSensors != NULL ? NO_ERROR : NO_INIT;
+    return mSensors != nullptr ? NO_ERROR : NO_INIT;
 }
 
 ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index fd6cee6..6d75051 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_SENSOR_DEVICE_H
 #define ANDROID_SENSOR_DEVICE_H
 
+#include "SensorDeviceUtils.h"
 #include "SensorServiceUtils.h"
 
 #include <sensor/Sensor.h>
@@ -39,12 +40,9 @@
 namespace android {
 
 // ---------------------------------------------------------------------------
-using SensorServiceUtil::Dumpable;
-using hardware::Return;
 
-class SensorDevice : public Singleton<SensorDevice>, public Dumpable {
+class SensorDevice : public Singleton<SensorDevice>, public SensorServiceUtil::Dumpable {
 public:
-
     class HidlTransportErrorLog {
      public:
 
@@ -105,7 +103,7 @@
 private:
     friend class Singleton<SensorDevice>;
 
-    sp<android::hardware::sensors::V1_0::ISensors> mSensors;
+    sp<hardware::sensors::V1_0::ISensors> mSensors;
     Vector<sensor_t> mSensorList;
     std::unordered_map<int32_t, sensor_t*> mConnectedDynamicSensors;
 
@@ -174,6 +172,8 @@
         }
         return std::move(ret);
     }
+    //TODO(b/67425500): remove waiter after bug is resolved.
+    sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
 
     bool isClientDisabled(void* ident);
     bool isClientDisabledLocked(void* ident);
diff --git a/services/sensorservice/SensorDeviceUtils.cpp b/services/sensorservice/SensorDeviceUtils.cpp
new file mode 100644
index 0000000..b1344be
--- /dev/null
+++ b/services/sensorservice/SensorDeviceUtils.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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 "SensorDeviceUtils.h"
+
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <thread>
+
+using ::android::hardware::Void;
+using namespace android::hardware::sensors::V1_0;
+
+namespace android {
+namespace SensorDeviceUtils {
+
+HidlServiceRegistrationWaiter::HidlServiceRegistrationWaiter()
+        : mRegistered(ISensors::registerForNotifications("default", this)) {
+}
+
+Return<void> HidlServiceRegistrationWaiter::onRegistration(
+        const hidl_string &fqName, const hidl_string &name, bool preexisting) {
+    ALOGV("onRegistration fqName %s, name %s, preexisting %d",
+          fqName.c_str(), name.c_str(), preexisting);
+
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        mRestartObserved = true;
+    }
+    mCondition.notify_all();
+    return Void();
+}
+
+void HidlServiceRegistrationWaiter::reset() {
+    std::lock_guard<std::mutex> lk(mLock);
+    mRestartObserved = false;
+}
+
+bool HidlServiceRegistrationWaiter::wait() {
+    constexpr int DEFAULT_WAIT_MS = 100;
+    constexpr int TIMEOUT_MS = 1000;
+
+    if (!mRegistered) {
+        ALOGW("Cannot register service notification, use default wait(%d ms)", DEFAULT_WAIT_MS);
+        std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_WAIT_MS));
+        // not sure if service is actually restarted
+        return false;
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+    return mCondition.wait_for(lk, std::chrono::milliseconds(TIMEOUT_MS),
+            [this]{return mRestartObserved;});
+}
+
+} // namespace SensorDeviceUtils
+} // namespace android
diff --git a/services/sensorservice/SensorDeviceUtils.h b/services/sensorservice/SensorDeviceUtils.h
new file mode 100644
index 0000000..da36928
--- /dev/null
+++ b/services/sensorservice/SensorDeviceUtils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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_SENSOR_DEVICE_UTIL
+#define ANDROID_SENSOR_DEVICE_UTIL
+
+#include <android/hidl/manager/1.0/IServiceNotification.h>
+
+#include <condition_variable>
+#include <thread>
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+
+namespace android {
+namespace SensorDeviceUtils {
+
+class HidlServiceRegistrationWaiter : public IServiceNotification {
+public:
+
+    HidlServiceRegistrationWaiter();
+
+    Return<void> onRegistration(const hidl_string &fqName,
+                                const hidl_string &name,
+                                bool preexisting) override;
+
+    void reset();
+
+    /**
+     * Wait for service restart
+     *
+     * @return true if service is restart since last reset(); false otherwise.
+     */
+    bool wait();
+private:
+    const bool mRegistered;
+
+    std::mutex mLock;
+    std::condition_variable mCondition;
+    bool mRestartObserved;
+};
+
+} // namespace SensorDeviceUtils
+} // namespace android;
+
+#endif // ANDROID_SENSOR_SERVICE_UTIL
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
new file mode 100644
index 0000000..4673491
--- /dev/null
+++ b/services/utils/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 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.
+
+//
+// Static library used in testing and executables
+//
+cc_library_static {
+    name: "libserviceutils",
+
+    cflags: [
+        "-Wall",
+        "-Wno-unused-parameter",
+        "-Werror",
+    ],
+
+    srcs: [
+        "PriorityDumper.cpp",
+    ],
+
+    clang: true,
+    export_include_dirs: ["include"],
+}
+
+subdirs = ["tests"]
diff --git a/services/utils/PriorityDumper.cpp b/services/utils/PriorityDumper.cpp
new file mode 100644
index 0000000..555cf03
--- /dev/null
+++ b/services/utils/PriorityDumper.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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 "include/PriorityDumper.h"
+
+namespace android {
+
+static void getStrippedArgs(Vector<String16>& dest, const Vector<String16>& source,
+                            std::size_t numArgsToStrip) {
+    for (auto it = source.begin() + numArgsToStrip; it != source.end(); it++) {
+        dest.add(*it);
+    }
+}
+
+void priorityDump(PriorityDumper& dumper, int fd, const Vector<String16>& args) {
+    if (args.size() >= 2 && args[0] == PRIORITY_ARG) {
+        String16 priority = args[1];
+        Vector<String16> strippedArgs;
+        getStrippedArgs(strippedArgs, args, 2);
+        if (priority == PRIORITY_ARG_CRITICAL) {
+            dumper.dumpCritical(fd, strippedArgs);
+        } else if (priority == PRIORITY_ARG_HIGH) {
+            dumper.dumpHigh(fd, strippedArgs);
+        } else if (priority == PRIORITY_ARG_NORMAL) {
+            dumper.dumpNormal(fd, strippedArgs);
+        } else {
+            dumper.dump(fd, args);
+        }
+    } else {
+        dumper.dump(fd, args);
+    }
+}
+} // namespace android
\ No newline at end of file
diff --git a/services/utils/include/PriorityDumper.h b/services/utils/include/PriorityDumper.h
new file mode 100644
index 0000000..23e900d
--- /dev/null
+++ b/services/utils/include/PriorityDumper.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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_UTILS_PRIORITYDUMP_H
+#define ANDROID_UTILS_PRIORITYDUMP_H
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+constexpr const char16_t PRIORITY_ARG[] = u"--dump-priority";
+constexpr const char16_t PRIORITY_ARG_CRITICAL[] = u"CRITICAL";
+constexpr const char16_t PRIORITY_ARG_HIGH[] = u"HIGH";
+constexpr const char16_t PRIORITY_ARG_NORMAL[] = u"NORMAL";
+
+// Helper class to split dumps into various priority buckets.
+class PriorityDumper {
+public:
+    // Dumps CRITICAL priority sections.
+    virtual void dumpCritical(int fd, const Vector<String16>& args) {}
+
+    // Dumps HIGH priority sections.
+    virtual void dumpHigh(int fd, const Vector<String16>& args) {}
+
+    // Dumps normal priority sections.
+    virtual void dumpNormal(int fd, const Vector<String16>& args) {}
+
+    // Dumps all sections.
+    // This method is called when priorityDump is called without priority
+    // arguments. By default, it calls all three dump methods.
+    virtual void dump(int fd, const Vector<String16>& args) {
+        dumpCritical(fd, args);
+        dumpHigh(fd, args);
+        dumpNormal(fd, args);
+    }
+    virtual ~PriorityDumper() = default;
+};
+
+// Parses the argument list checking if the first argument is --dump_priority and
+// the second argument is the priority type (HIGH, CRITICAL or NORMAL). If the
+// arguments are found, they are stripped and the appropriate PriorityDumper
+// method is called.
+// If --dump_priority argument is not passed, all supported sections are dumped.
+void priorityDump(PriorityDumper& dumper, int fd, const Vector<String16>& args);
+
+}; // namespace android
+
+#endif // ANDROID_UTILS_PRIORITYDUMP_H
diff --git a/services/utils/tests/Android.bp b/services/utils/tests/Android.bp
new file mode 100644
index 0000000..5a9dc0a
--- /dev/null
+++ b/services/utils/tests/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 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.
+
+// Build unit tests.
+
+cc_test {
+    name: "prioritydumper_test",
+    test_suites: ["device-tests"],
+    srcs: [ "PriorityDumper_test.cpp"],
+    shared_libs: [
+        "libutils",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+    static_libs = [
+        "libgmock",
+        "libserviceutils"
+    ],
+    clang: true,
+}
\ No newline at end of file
diff --git a/services/utils/tests/AndroidTest.xml b/services/utils/tests/AndroidTest.xml
new file mode 100644
index 0000000..83c890d
--- /dev/null
+++ b/services/utils/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for prioritydumper_test">
+  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <option name="cleanup" value="true" />
+    <option name="push" value="prioritydumper_test->/data/local/tmp/prioritydumper_test" />
+  </target_preparer>
+  <option name="test-suite-tag" value="apct" />
+  <test class="com.android.tradefed.testtype.GTest" >
+    <option name="native-test-device-path" value="/data/local/tmp" />
+    <option name="module-name" value="prioritydumper_test" />
+  </test>
+</configuration>
\ No newline at end of file
diff --git a/services/utils/tests/PriorityDumper_test.cpp b/services/utils/tests/PriorityDumper_test.cpp
new file mode 100644
index 0000000..c5a121e
--- /dev/null
+++ b/services/utils/tests/PriorityDumper_test.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 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 "PriorityDumper.h"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+using ::testing::ElementsAreArray;
+using ::testing::Mock;
+using ::testing::Test;
+
+class PriorityDumperMock : public PriorityDumper {
+public:
+    MOCK_METHOD2(dumpCritical, void(int, const Vector<String16>&));
+    MOCK_METHOD2(dumpHigh, void(int, const Vector<String16>&));
+    MOCK_METHOD2(dumpNormal, void(int, const Vector<String16>&));
+    MOCK_METHOD2(dump, void(int, const Vector<String16>&));
+};
+
+class DumpAllMock : public PriorityDumper {
+public:
+    MOCK_METHOD2(dumpCritical, void(int, const Vector<String16>&));
+    MOCK_METHOD2(dumpHigh, void(int, const Vector<String16>&));
+    MOCK_METHOD2(dumpNormal, void(int, const Vector<String16>&));
+};
+
+class PriorityDumperTest : public Test {
+public:
+    PriorityDumperTest() : dumper_(), dumpAlldumper_(), fd(1) {}
+    PriorityDumperMock dumper_;
+    DumpAllMock dumpAlldumper_;
+    int fd;
+};
+
+static void addAll(Vector<String16>& av, const std::vector<std::string>& v) {
+    for (auto element : v) {
+        av.add(String16(element.c_str()));
+    }
+}
+
+TEST_F(PriorityDumperTest, noArgsPassed) {
+    Vector<String16> args;
+    EXPECT_CALL(dumper_, dump(fd, ElementsAreArray(args)));
+    priorityDump(dumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, noPriorityArgsPassed) {
+    Vector<String16> args;
+    addAll(args, {"bunch", "of", "args"});
+    EXPECT_CALL(dumper_, dump(fd, ElementsAreArray(args)));
+    priorityDump(dumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgsOnly) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "CRITICAL"});
+    Vector<String16> strippedArgs;
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+
+    priorityDump(dumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpCritical) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "CRITICAL", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpCritical(fd, ElementsAreArray(strippedArgs)));
+    priorityDump(dumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpHigh) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "HIGH", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpHigh(fd, ElementsAreArray(strippedArgs)));
+    priorityDump(dumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpNormal) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "NORMAL", "args", "left", "behind"});
+    Vector<String16> strippedArgs;
+    addAll(strippedArgs, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumper_, dumpNormal(fd, ElementsAreArray(strippedArgs)));
+    priorityDump(dumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, dumpAll) {
+    Vector<String16> args;
+    addAll(args, {"args", "left", "behind"});
+
+    EXPECT_CALL(dumpAlldumper_, dumpCritical(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumpAlldumper_, dumpHigh(fd, ElementsAreArray(args)));
+    EXPECT_CALL(dumpAlldumper_, dumpNormal(fd, ElementsAreArray(args)));
+
+    priorityDump(dumpAlldumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithPriorityMissing) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority"});
+    EXPECT_CALL(dumper_, dump(fd, ElementsAreArray(args)));
+
+    priorityDump(dumper_, fd, args);
+}
+
+TEST_F(PriorityDumperTest, priorityArgWithInvalidPriority) {
+    Vector<String16> args;
+    addAll(args, {"--dump-priority", "REALLY_HIGH"});
+    EXPECT_CALL(dumper_, dump(fd, ElementsAreArray(args)));
+
+    priorityDump(dumper_, fd, args);
+}
\ No newline at end of file