Merge "[VTS] Update RenderEngine dependencies."
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 7bafd2c..bc9b94d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -422,6 +422,17 @@
                                             .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
                 .initialValue = {.int32Values = {0}}  // Will be used for all areas.
         },
+        {
+                .config = {.prop = toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON),
+                           .access = VehiclePropertyAccess::READ_WRITE,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                           .areaConfigs =
+                                   {VehicleAreaConfig{
+                                            .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
+                                    VehicleAreaConfig{
+                                            .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
+                .initialValue = {.int32Values = {0}}  // Will be used for all areas.
+        },
 
         {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
                     .access = VehiclePropertyAccess::READ_WRITE,
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index f6ebcdd..6232dd5 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -799,7 +799,7 @@
         | VehicleArea:SEAT),
 
     /**
-     * On/off defrost for designated window
+     * Fan-based defrost for designated window.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
@@ -1076,6 +1076,7 @@
      *
      * @change_mode VehiclePropertyChangeMode:STATIC
      * @access VehiclePropertyAccess:READ
+     * @data_enum VehicleHvacFanDirection
      */
     HVAC_FAN_DIRECTION_AVAILABLE = (
         0x0511
@@ -1118,6 +1119,18 @@
         | VehiclePropertyType:INT32
         | VehicleArea:SEAT),
 
+    /**
+     * Electric defrosters' status
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    HVAC_ELECTRIC_DEFROSTER_ON = (
+        0x0514
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:WINDOW),
+
    /**
      * Distance units for display
      *
@@ -2458,9 +2471,19 @@
  * Bit flags for fan direction
  */
 enum VehicleHvacFanDirection : int32_t {
+    UNKNOWN = 0x0,
+
     FACE = 0x1,
     FLOOR = 0x2,
+    /**
+     * FACE_AND_FLOOR = FACE | FLOOR
+     */
+    FACE_AND_FLOOR = 0X3,
     DEFROST = 0x4,
+    /**
+     * DEFROST_AND_FLOOR = DEFROST | FLOOR
+     */
+    DEFROST_AND_FLOOR = 0x06,
 };
 
 enum VehicleOilLevel : int32_t {
@@ -2723,6 +2746,8 @@
  * Various gears which can be selected by user and chosen in system.
  */
 enum VehicleGear : int32_t {
+    GEAR_UNKNOWN = 0x0000,
+
     GEAR_NEUTRAL = 0x0001,
     GEAR_REVERSE = 0x0002,
     GEAR_PARK = 0x0004,
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 444797d..7bb992b 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -24,7 +24,10 @@
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
         "VtsHalSensorsTargetTestUtils",
     ],
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index 98f0eac..4765fa2 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -24,7 +24,10 @@
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
         "libfmq",
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 6ff393d..8364ba9 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -176,19 +176,21 @@
     // Helper functions
     void activateAllSensors(bool enable);
     std::vector<SensorInfo> getNonOneShotSensors();
+    std::vector<SensorInfo> getNonOneShotAndNonSpecialSensors();
     std::vector<SensorInfo> getOneShotSensors();
     std::vector<SensorInfo> getInjectEventSensors();
     int32_t getInvalidSensorHandle();
     bool getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, RateLevel* rate);
     void verifyDirectChannel(SharedMemType memType);
-    void verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                     std::shared_ptr<SensorsTestSharedMemory> mem,
-                                     int32_t* directChannelHandle);
+    void verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
+                                     int32_t* directChannelHandle, bool supportsSharedMemType,
+                                     bool supportsAnyDirectChannel);
     void verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
-                         int32_t directChannelHandle);
-    void verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                       int32_t directChannelHandle);
+                         int32_t directChannelHandle, bool directChannelSupported);
+    void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported);
     void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
+    void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                   bool* supportsAnyDirectChannel);
 };
 
 Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -257,6 +259,18 @@
     return sensors;
 }
 
+std::vector<SensorInfo> SensorsHidlTest::getNonOneShotAndNonSpecialSensors() {
+    std::vector<SensorInfo> sensors;
+    for (const SensorInfo& info : getSensorsList()) {
+        SensorFlagBits reportMode = extractReportMode(info.flags);
+        if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
+            reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
 std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() {
     std::vector<SensorInfo> sensors;
     for (const SensorInfo& info : getSensorsList()) {
@@ -777,7 +791,12 @@
     activateAllSensors(false /* enable */);
     for (const SensorInfo& sensor : getSensorsList()) {
         // Call batch on inactive sensor
-        ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+        // One shot sensors have minDelay set to -1 which is an invalid
+        // parameter. Use 0 instead to avoid errors.
+        int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE
+                                           ? 0
+                                           : sensor.minDelay;
+        ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */),
                   Result::OK);
 
         // Activate the sensor
@@ -830,9 +849,10 @@
     EventCallback callback;
     getEnvironment()->registerCallback(&callback);
 
-    const std::vector<SensorInfo> sensors = getSensorsList();
+    // This test is not valid for one-shot or special-report-mode sensors
+    const std::vector<SensorInfo> sensors = getNonOneShotAndNonSpecialSensors();
     milliseconds maxMinDelay(0);
-    for (const SensorInfo& sensor : getSensorsList()) {
+    for (const SensorInfo& sensor : sensors) {
         milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
         maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
     }
@@ -849,9 +869,14 @@
     // Save the last received event for each sensor
     std::map<int32_t, int64_t> lastEventTimestampMap;
     for (const SensorInfo& sensor : sensors) {
-        ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
-        lastEventTimestampMap[sensor.sensorHandle] =
-            callback.getEvents(sensor.sensorHandle).back().timestamp;
+        // Some on-change sensors may not report an event without stimulus
+        if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
+            ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
+        }
+        if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
+            lastEventTimestampMap[sensor.sensorHandle] =
+                    callback.getEvents(sensor.sensorHandle).back().timestamp;
+        }
     }
 
     // Allow some time to pass, reset the callback, then reactivate the sensors
@@ -862,6 +887,14 @@
     activateAllSensors(false);
 
     for (const SensorInfo& sensor : sensors) {
+        // Skip sensors that did not previously report an event
+        if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
+            continue;
+        }
+        // Skip on-change sensors that do not consistently report an initial event
+        if (callback.getEvents(sensor.sensorHandle).size() < 1) {
+            continue;
+        }
         // Ensure that the first event received is not stale by ensuring that its timestamp is
         // sufficiently different from the previous event
         const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
@@ -878,21 +911,43 @@
                        [&](Result result, int32_t reportToken) {
                            if (isDirectReportRateSupported(sensor, rateLevel)) {
                                ASSERT_EQ(result, Result::OK);
-                               ASSERT_GT(reportToken, 0);
+                               if (rateLevel != RateLevel::STOP) {
+                                   ASSERT_GT(reportToken, 0);
+                               }
                            } else {
                                ASSERT_EQ(result, Result::BAD_VALUE);
                            }
                        });
 }
 
-void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                                  std::shared_ptr<SensorsTestSharedMemory> mem,
-                                                  int32_t* directChannelHandle) {
+void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                                bool* supportsAnyDirectChannel) {
+    *supportsSharedMemType = false;
+    *supportsAnyDirectChannel = false;
+    for (const SensorInfo& curSensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(curSensor, memType)) {
+            *supportsSharedMemType = true;
+        }
+        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) ||
+            isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
+            *supportsAnyDirectChannel = true;
+        }
+
+        if (*supportsSharedMemType && *supportsAnyDirectChannel) {
+            break;
+        }
+    }
+}
+
+void SensorsHidlTest::verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
+                                                  int32_t* directChannelHandle,
+                                                  bool supportsSharedMemType,
+                                                  bool supportsAnyDirectChannel) {
     char* buffer = mem->getBuffer();
     memset(buffer, 0xff, mem->getSize());
 
     registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
-        if (isDirectChannelTypeSupported(sensor, memType)) {
+        if (supportsSharedMemType) {
             ASSERT_EQ(result, Result::OK);
             ASSERT_GT(channelHandle, 0);
 
@@ -901,7 +956,9 @@
                 ASSERT_EQ(buffer[i], 0x00);
             }
         } else {
-            ASSERT_EQ(result, Result::INVALID_OPERATION);
+            Result expectedResult =
+                    supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
+            ASSERT_EQ(result, expectedResult);
             ASSERT_EQ(channelHandle, -1);
         }
         *directChannelHandle = channelHandle;
@@ -909,7 +966,7 @@
 }
 
 void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
-                                      int32_t directChannelHandle) {
+                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
     if (isDirectChannelTypeSupported(sensor, memType)) {
         // Verify that each rate level is properly supported
         checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
@@ -925,22 +982,22 @@
             -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
             [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
     } else {
-        // Direct channel is not supported for this SharedMemType
+        // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
+        // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
+        // channel is not supported at all
+        Result expectedResult =
+                supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
         configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
-                           [](Result result, int32_t /* reportToken */) {
-                               ASSERT_EQ(result, Result::INVALID_OPERATION);
+                           [expectedResult](Result result, int32_t /* reportToken */) {
+                               ASSERT_EQ(result, expectedResult);
                            });
     }
 }
 
-void SensorsHidlTest::verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                                    int32_t directChannelHandle) {
-    Result result = unregisterDirectChannel(directChannelHandle);
-    if (isDirectChannelTypeSupported(sensor, memType)) {
-        ASSERT_EQ(result, Result::OK);
-    } else {
-        ASSERT_EQ(result, Result::INVALID_OPERATION);
-    }
+void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle,
+                                                    bool supportsAnyDirectChannel) {
+    Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION;
+    ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult);
 }
 
 void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
@@ -951,11 +1008,16 @@
         SensorsTestSharedMemory::create(memType, kMemSize));
     ASSERT_NE(mem, nullptr);
 
+    bool supportsSharedMemType;
+    bool supportsAnyDirectChannel;
+    queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
+
     for (const SensorInfo& sensor : getSensorsList()) {
         int32_t directChannelHandle = 0;
-        verifyRegisterDirectChannel(sensor, memType, mem, &directChannelHandle);
-        verifyConfigure(sensor, memType, directChannelHandle);
-        verifyUnregisterDirectChannel(sensor, memType, directChannelHandle);
+        verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
+                                    supportsAnyDirectChannel);
+        verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
+        verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel);
     }
 }
 
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 8da554a..02dc608 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -31,7 +31,10 @@
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
         "VtsHalHidlTargetTestBase",
     ],
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index 222ef96..1cad913 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -16,206 +16,262 @@
 
 #include "GrallocWrapper.h"
 
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+
 #include <utils/Log.h>
 
+#include <cinttypes>
+#include <type_traits>
+
+using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
+using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
+using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
+using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
+
+using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
+using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
+
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+// This is a typedef to the same underlying type across v2.0 and v3.0
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
 namespace android {
 
-GrallocWrapper::GrallocWrapper() {
-    init();
+// Since we use the same APIs across allocator/mapper HALs but they have major
+// version differences (meaning they are not related through inheritance), we
+// create a common interface abstraction for the IAllocator + IMapper combination
+// (major versions need to match in the current HALs, e.g. IAllocator 3.0 needs to
+// be paired with IMapper 3.0, so these are tied together)
+class IGrallocHalWrapper {
+  public:
+    virtual ~IGrallocHalWrapper() = default;
+
+    // IAllocator
+    virtual std::string dumpDebugInfo() = 0;
+    virtual native_handle_t* allocate(uint32_t size) = 0;
+    virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
+
+    // IMapper
+    virtual void* lock(native_handle_t* bufferHandle) = 0;
+    virtual void unlock(native_handle_t* bufferHandle) = 0;
+};
+
+namespace {
+
+bool failed(Error2 error) {
+    return (error != Error2::NONE);
+}
+bool failed(Error3 error) {
+    return (error != Error3::NONE);
 }
 
-void GrallocWrapper::init() {
-    mAllocator = allocator2::IAllocator::getService();
-    if (mAllocator == nullptr) {
-        ALOGE("Failed to get allocator service");
-    }
-
-    mMapper = mapper2::IMapper::getService();
-    if (mMapper == nullptr) {
-        ALOGE("Failed to get mapper service");
-    } else if (mMapper->isRemote()) {
-        ALOGE("Mapper is not in passthrough mode");
-    }
-}
-
-GrallocWrapper::~GrallocWrapper() {
-    for (auto bufferHandle : mClonedBuffers) {
-        auto buffer = const_cast<native_handle_t*>(bufferHandle);
-        native_handle_close(buffer);
-        native_handle_delete(buffer);
-    }
-    mClonedBuffers.clear();
-
-    for (auto bufferHandle : mImportedBuffers) {
-        auto buffer = const_cast<native_handle_t*>(bufferHandle);
-        if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) {
-            ALOGE("Failed to free buffer %p", buffer);
+// Since all the type and function names are the same for the things we use across the major HAL
+// versions, we use template magic to avoid repeating ourselves.
+template <typename AllocatorT, typename MapperT>
+class GrallocHalWrapper : public IGrallocHalWrapper {
+  public:
+    GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper)
+        : mAllocator(allocator), mMapper(mapper) {
+        if (mapper->isRemote()) {
+            ALOGE("Mapper is in passthrough mode");
         }
     }
-    mImportedBuffers.clear();
-}
 
-sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const {
-    return mAllocator;
-}
+    virtual std::string dumpDebugInfo() override;
+    virtual native_handle_t* allocate(uint32_t size) override;
+    virtual void freeBuffer(native_handle_t* bufferHandle) override;
 
-std::string GrallocWrapper::dumpDebugInfo() {
+    virtual void* lock(native_handle_t* bufferHandle) override;
+    virtual void unlock(native_handle_t* bufferHandle) override;
+
+  private:
+    static constexpr uint64_t kBufferUsage =
+            static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
+    sp<AllocatorT> mAllocator;
+    sp<MapperT> mMapper;
+
+    BufferDescriptor getDescriptor(uint32_t size);
+    native_handle_t* importBuffer(const hidl_handle& rawHandle);
+};
+
+template <typename AllocatorT, typename MapperT>
+std::string GrallocHalWrapper<AllocatorT, MapperT>::dumpDebugInfo() {
     std::string debugInfo;
-    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
+    mAllocator->dumpDebugInfo([&](const hidl_string& tmpDebugInfo) { debugInfo = tmpDebugInfo; });
     return debugInfo;
 }
 
-const native_handle_t* GrallocWrapper::cloneBuffer(const hardware::hidl_handle& rawHandle) {
-    const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+template <typename AllocatorT, typename MapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
+    constexpr uint32_t kBufferCount = 1;
+    BufferDescriptor descriptor = getDescriptor(size);
+    native_handle_t* bufferHandle = nullptr;
 
-    if (bufferHandle) {
-        mClonedBuffers.insert(bufferHandle);
-    }
+    auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
+        if (failed(error)) {
+            ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
+        } else if (buffers.size() != kBufferCount) {
+            ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", buffers.size(),
+                  kBufferCount);
+        } else {
+            bufferHandle = importBuffer(buffers[0]);
+        }
+    };
+
+    mAllocator->allocate(descriptor, kBufferCount, callback);
     return bufferHandle;
 }
 
-std::vector<const native_handle_t*> GrallocWrapper::allocate(
-    const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, uint32_t* outStride) {
-    std::vector<const native_handle_t*> bufferHandles;
-    bufferHandles.reserve(count);
-    mAllocator->allocate(descriptor, count,
-                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-                             if (mapper2::Error::NONE != tmpError) {
-                                 ALOGE("Failed to allocate buffers");
-                             }
-                             if (count != tmpBuffers.size()) {
-                                 ALOGE("Invalid buffer array");
-                             }
-
-                             for (uint32_t i = 0; i < count; i++) {
-                                 if (import) {
-                                     bufferHandles.push_back(importBuffer(tmpBuffers[i]));
-                                 } else {
-                                     bufferHandles.push_back(cloneBuffer(tmpBuffers[i]));
-                                 }
-                             }
-
-                             if (outStride) {
-                                 *outStride = tmpStride;
-                             }
-                         });
-
-    return bufferHandles;
+template <typename AllocatorT, typename MapperT>
+void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) {
+    auto error = mMapper->freeBuffer(bufferHandle);
+    if (!error.isOk() || failed(error)) {
+        ALOGE("Failed to free buffer %p", bufferHandle);
+    }
 }
 
-const native_handle_t* GrallocWrapper::allocate(
-    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
-    uint32_t* outStride) {
-    mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo);
-    auto buffers = allocate(descriptor, 1, import, outStride);
-    return buffers[0];
-}
+template <typename AllocatorT, typename MapperT>
+BufferDescriptor GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
+    typename MapperT::BufferDescriptorInfo descriptorInfo = {
+            .width = size,
+            .height = 1,
+            .layerCount = 1,
+            .usage = kBufferUsage,
+            .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
+    };
 
-sp<mapper2::IMapper> GrallocWrapper::getMapper() const {
-    return mMapper;
-}
-
-mapper2::BufferDescriptor GrallocWrapper::createDescriptor(
-    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) {
-    mapper2::BufferDescriptor descriptor;
-    mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
-        if (tmpError != mapper2::Error::NONE) {
-            ALOGE("Failed to create descriptor");
+    BufferDescriptor descriptor;
+    auto callback = [&](auto error, const BufferDescriptor& tmpDescriptor) {
+        if (failed(error)) {
+            ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
+        } else {
+            descriptor = tmpDescriptor;
         }
-        descriptor = tmpDescriptor;
-    });
+    };
 
+    mMapper->createDescriptor(descriptorInfo, callback);
     return descriptor;
 }
 
-const native_handle_t* GrallocWrapper::importBuffer(const hardware::hidl_handle& rawHandle) {
-    const native_handle_t* bufferHandle = nullptr;
-    mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
-        if (tmpError != mapper2::Error::NONE) {
-            ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle());
-        }
-        bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
-    });
+template <typename AllocatorT, typename MapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer(
+        const hidl_handle& rawHandle) {
+    native_handle_t* bufferHandle = nullptr;
 
-    if (bufferHandle) {
-        mImportedBuffers.insert(bufferHandle);
-    }
+    mMapper->importBuffer(rawHandle, [&](auto error, void* tmpBuffer) {
+        if (failed(error)) {
+            ALOGE("Failed to import buffer %p: %" PRId32, rawHandle.getNativeHandle(),
+                  static_cast<int32_t>(error));
+        } else {
+            bufferHandle = static_cast<native_handle_t*>(tmpBuffer);
+        }
+    });
 
     return bufferHandle;
 }
 
-void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    if (mImportedBuffers.erase(bufferHandle)) {
-        mapper2::Error error = mMapper->freeBuffer(buffer);
-        if (error != mapper2::Error::NONE) {
-            ALOGE("Failed to free %p", buffer);
-        }
-    } else {
-        mClonedBuffers.erase(bufferHandle);
-        native_handle_close(buffer);
-        native_handle_delete(buffer);
-    }
-}
-
-void* GrallocWrapper::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                           const mapper2::IMapper::Rect& accessRegion, int acquireFence) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
-    hardware::hidl_handle acquireFenceHandle;
-    if (acquireFence >= 0) {
-        auto h = native_handle_init(acquireFenceStorage, 1, 0);
-        h->data[0] = acquireFence;
-        acquireFenceHandle = h;
-    }
+template <typename AllocatorT, typename MapperT>
+void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) {
+    // Per the HAL, all-zeros Rect means the entire buffer
+    typename MapperT::Rect accessRegion = {};
+    hidl_handle acquireFenceHandle;  // No fence needed, already safe to lock
 
     void* data = nullptr;
-    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                  [&](const auto& tmpError, const auto& tmpData) {
-                      if (tmpError != mapper2::Error::NONE) {
-                          ALOGE("Failed to lock buffer %p", buffer);
+    mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
+                  [&](auto error, void* tmpData, ...) {  // V3_0 passes extra args we don't use
+                      if (failed(error)) {
+                          ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
+                                static_cast<int32_t>(error));
+                      } else {
+                          data = tmpData;
                       }
-                      data = tmpData;
                   });
 
-    if (acquireFence >= 0) {
-        close(acquireFence);
-    }
-
     return data;
 }
 
-int GrallocWrapper::unlock(const native_handle_t* bufferHandle) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    int releaseFence = -1;
-    mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
-        if (tmpError != mapper2::Error::NONE) {
-            ALOGE("Failed to unlock buffer %p", buffer);
-        }
-
-        auto fenceHandle = tmpReleaseFence.getNativeHandle();
-        if (fenceHandle) {
-            if (fenceHandle->numInts != 0) {
-                ALOGE("Invalid fence handle %p", fenceHandle);
-            }
-            if (fenceHandle->numFds == 1) {
-                releaseFence = dup(fenceHandle->data[0]);
-                if (releaseFence < 0) {
-                    ALOGE("Failed to dup fence fd");
-                }
-            } else {
-                if (fenceHandle->numFds != 0) {
-                    ALOGE("Invalid fence handle %p", fenceHandle);
-                }
-            }
+template <typename AllocatorT, typename MapperT>
+void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) {
+    mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
+        if (failed(error)) {
+            ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
+                  static_cast<int32_t>(error));
         }
     });
+}
 
-    return releaseFence;
+}  // anonymous namespace
+
+GrallocWrapper::GrallocWrapper() {
+    sp<IAllocator3> allocator3 = IAllocator3::getService();
+    sp<IMapper3> mapper3 = IMapper3::getService();
+
+    if (allocator3 != nullptr && mapper3 != nullptr) {
+        mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+                new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
+    } else {
+        ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
+              (allocator3 != nullptr), (mapper3 != nullptr));
+
+        sp<IAllocator2> allocator2 = IAllocator2::getService();
+        sp<IMapper2> mapper2 = IMapper2_1::getService();
+        if (mapper2 == nullptr) {
+            mapper2 = IMapper2::getService();
+        }
+
+        if (allocator2 != nullptr && mapper2 != nullptr) {
+            mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+                    new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
+        } else {
+            ALOGE("Couldn't open 2.x/3.0 graphics HALs (2.x allocator %d mapper %d)",
+                  (allocator2 != nullptr), (mapper2 != nullptr));
+        }
+    }
+}
+
+GrallocWrapper::~GrallocWrapper() {
+    for (auto bufferHandle : mAllocatedBuffers) {
+        mGrallocHal->unlock(bufferHandle);
+        mGrallocHal->freeBuffer(bufferHandle);
+    }
+    mAllocatedBuffers.clear();
+}
+
+std::string GrallocWrapper::dumpDebugInfo() {
+    return mGrallocHal->dumpDebugInfo();
+}
+
+std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
+    native_handle_t* bufferHandle = mGrallocHal->allocate(size);
+    void* buffer = nullptr;
+    if (bufferHandle) {
+        buffer = mGrallocHal->lock(bufferHandle);
+        if (buffer) {
+            mAllocatedBuffers.insert(bufferHandle);
+        } else {
+            mGrallocHal->freeBuffer(bufferHandle);
+            bufferHandle = nullptr;
+        }
+    }
+    return std::make_pair<>(bufferHandle, buffer);
+}
+
+void GrallocWrapper::freeBuffer(native_handle_t* bufferHandle) {
+    if (mAllocatedBuffers.erase(bufferHandle)) {
+        mGrallocHal->unlock(bufferHandle);
+        mGrallocHal->freeBuffer(bufferHandle);
+    }
 }
 
 }  // namespace android
diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
index 819e297..3b068bd 100644
--- a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
+++ b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
@@ -119,32 +119,13 @@
         }
         case SharedMemType::GRALLOC: {
             mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
-            if (mGrallocWrapper->getAllocator() == nullptr ||
-                mGrallocWrapper->getMapper() == nullptr) {
+            if (!mGrallocWrapper->isInitialized()) {
                 break;
             }
-            using android::hardware::graphics::common::V1_0::BufferUsage;
-            using android::hardware::graphics::common::V1_0::PixelFormat;
-            mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
-                .width = static_cast<uint32_t>(size),
-                .height = 1,
-                .layerCount = 1,
-                .usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA |
-                                               BufferUsage::CPU_READ_OFTEN),
-                .format = PixelFormat::BLOB};
 
-            handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info));
-            if (handle != nullptr) {
-                mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width),
-                                              static_cast<int32_t>(buf_desc_info.height)};
-                buffer = static_cast<char*>(
-                    mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
-                if (buffer != nullptr) {
-                    break;
-                }
-                mGrallocWrapper->freeBuffer(handle);
-                handle = nullptr;
-            }
+            std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
+            handle = buf.first;
+            buffer = static_cast<char*>(buf.second);
             break;
         }
         default:
@@ -175,9 +156,7 @@
         }
         case SharedMemType::GRALLOC: {
             if (mSize != 0) {
-                mGrallocWrapper->unlock(mNativeHandle);
                 mGrallocWrapper->freeBuffer(mNativeHandle);
-
                 mNativeHandle = nullptr;
                 mSize = 0;
             }
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
index 3bd73c3..41e6334 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
@@ -14,66 +14,47 @@
  * limitations under the License.
  */
 
-#ifndef GRALLO_WRAPPER_H_
-#define GRALLO_WRAPPER_H_
+#pragma once
 
+#include <utils/NativeHandle.h>
+
+#include <memory>
+#include <string>
 #include <unordered_set>
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-
-namespace allocator2 = ::android::hardware::graphics::allocator::V2_0;
-namespace mapper2 = ::android::hardware::graphics::mapper::V2_0;
+#include <utility>
 
 namespace android {
 
-// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/
+class IGrallocHalWrapper;
+
+// Reference: hardware/interfaces/graphics/mapper/2.0/vts/functional/
 class GrallocWrapper {
    public:
     GrallocWrapper();
     ~GrallocWrapper();
 
-    sp<allocator2::IAllocator> getAllocator() const;
-    sp<mapper2::IMapper> getMapper() const;
+    // After constructing this object, this function must be called to check the result. If it
+    // returns false, other methods are not safe to call.
+    bool isInitialized() const { return (mGrallocHal != nullptr); };
 
     std::string dumpDebugInfo();
 
-    // When import is false, this simply calls IAllocator::allocate. When import
-    // is true, the returned buffers are also imported into the mapper.
-    //
-    // Either case, the returned buffers must be freed with freeBuffer.
-    std::vector<const native_handle_t*> allocate(const mapper2::BufferDescriptor& descriptor,
-                                                 uint32_t count, bool import = true,
-                                                 uint32_t* outStride = nullptr);
-    const native_handle_t* allocate(const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo,
-                                    bool import = true, uint32_t* outStride = nullptr);
+    // Allocates a gralloc buffer suitable for direct channel sensors usage with the given size.
+    // The buffer should be freed using freeBuffer when it's not needed anymore; otherwise it'll
+    // be freed when this object is destroyed.
+    // Returns a handle to the buffer, and a CPU-accessible pointer for reading. On failure, both
+    // will be set to nullptr.
+    std::pair<native_handle_t*, void*> allocate(uint32_t size);
 
-    mapper2::BufferDescriptor createDescriptor(
-        const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo);
+    // Releases a gralloc buffer previously returned by allocate()
+    void freeBuffer(native_handle_t* bufferHandle);
 
-    const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle);
-    void freeBuffer(const native_handle_t* bufferHandle);
-
-    // We use fd instead of hardware::hidl_handle in these functions to pass fences
-    // in and out of the mapper.  The ownership of the fd is always transferred
-    // with each of these functions.
-    void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-               const mapper2::IMapper::Rect& accessRegion, int acquireFence);
-
-    int unlock(const native_handle_t* bufferHandle);
-
-   private:
-    void init();
-    const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle);
-
-    sp<allocator2::IAllocator> mAllocator;
-    sp<mapper2::IMapper> mMapper;
+  private:
+    std::unique_ptr<IGrallocHalWrapper> mGrallocHal;
 
     // Keep track of all cloned and imported handles.  When a test fails with
     // ASSERT_*, the destructor will free the handles for the test.
-    std::unordered_set<const native_handle_t*> mClonedBuffers;
-    std::unordered_set<const native_handle_t*> mImportedBuffers;
+    std::unordered_set<native_handle_t*> mAllocatedBuffers;
 };
 
 }  // namespace android
-#endif  // GRALLO_WRAPPER_H_