Merge "Also tell HALs that tracing stopped" into qt-dev
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c20c2f3..9c311a3 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -886,7 +886,7 @@
         item.mFence = acquireFence;
         item.mFenceTime = acquireFenceTime;
         item.mIsDroppable = mCore->mAsyncMode ||
-                (!mCore->mLegacyBufferDrop && mConsumerIsSurfaceFlinger) ||
+                (mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) ||
                 (mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) ||
                 (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot);
         item.mSurfaceDamage = surfaceDamage;
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 9c0ee99..690a85f 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -233,7 +233,8 @@
 
     // mLegacyBufferDrop indicates whether mQueueBufferCanDrop is in effect.
     // If this flag is set mQueueBufferCanDrop is working as explained. If not
-    // queueBuffer will not drop buffers unless consumer is SurfaceFlinger.
+    // queueBuffer will not drop buffers unless consumer is SurfaceFlinger and
+    // mQueueBufferCanDrop is set.
     bool mLegacyBufferDrop;
 
     // mDefaultBufferFormat can be set so it will override the buffer format
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index fcd4f29..717f317 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -45,7 +45,9 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
 
-static status_t StatusFromResult(Result result) {
+namespace {
+
+status_t statusFromResult(Result result) {
     switch (result) {
         case Result::OK:
             return OK;
@@ -71,6 +73,8 @@
     INTERNAL_WAKE =  1 << 16,
 };
 
+}  // anonymous namespace
+
 void SensorsHalDeathReceivier::serviceDied(
         uint64_t /* cookie */,
         const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
@@ -105,7 +109,7 @@
     initializeSensorList();
 
     mIsDirectReportSupported =
-           (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+            (checkReturnAndGetStatus(mSensors->unregisterDirectChannel(-1)) != INVALID_OPERATION);
 }
 
 void SensorDevice::initializeSensorList() {
@@ -122,7 +126,7 @@
                     convertToSensor(list[i], &sensor);
                     // Sanity check and clamp power if it is 0 (or close)
                     if (sensor.power < minPowerMa) {
-                        ALOGE("Reported power %f not deemed sane, clamping to %f",
+                        ALOGI("Reported power %f not deemed sane, clamping to %f",
                               sensor.power, minPowerMa);
                         sensor.power = minPowerMa;
                     }
@@ -217,10 +221,10 @@
                 mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
                 mWakeLockQueueFlag != nullptr);
 
-        status_t status = StatusFromResult(checkReturn(mSensors->initialize(
+        status_t status = checkReturnAndGetStatus(mSensors->initialize(
                 *mEventQueue->getDesc(),
                 *mWakeLockQueue->getDesc(),
-                new SensorsCallback())));
+                new SensorsCallback()));
 
         if (status != NO_ERROR) {
             connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
@@ -270,6 +274,8 @@
     bool didChange = false;
 
     if (oldSensorList.size() != newSensorList.size()) {
+        ALOGI("Sensor list size changed from %zu to %zu", oldSensorList.size(),
+              newSensorList.size());
         didChange = true;
     }
 
@@ -281,6 +287,7 @@
             if (prevSensor.handle == newSensor.handle) {
                 found = true;
                 if (!sensorIsEquivalent(prevSensor, newSensor)) {
+                    ALOGI("Sensor %s not equivalent to previous version", newSensor.name);
                     didChange = true;
                 }
             }
@@ -289,6 +296,7 @@
         if (!found) {
             // Could not find the new sensor in the old list of sensors, the lists must
             // have changed.
+            ALOGI("Sensor %s (handle %d) did not exist before", newSensor.name, newSensor.handle);
             didChange = true;
         }
     }
@@ -423,7 +431,7 @@
                         convertToSensorEvents(events, dynamicSensorsAdded, buffer);
                         err = (ssize_t)events.size();
                     } else {
-                        err = StatusFromResult(result);
+                        err = statusFromResult(result);
                     }
                 });
 
@@ -621,7 +629,7 @@
     if (actuateHardware) {
         ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
                  enabled);
-        err = StatusFromResult(checkReturn(mSensors->activate(handle, enabled)));
+        err = checkReturnAndGetStatus(mSensors->activate(handle, enabled));
         ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
                  strerror(-err));
 
@@ -694,9 +702,8 @@
     if (prevBestBatchParams != info.bestBatchParams) {
         ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH 0x%08x %" PRId64 " %" PRId64, handle,
                  info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
-        err = StatusFromResult(
-                checkReturn(mSensors->batch(
-                    handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch)));
+        err = checkReturnAndGetStatus(mSensors->batch(
+                handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch));
         if (err != NO_ERROR) {
             ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s",
                   mSensors.get(), handle, info.bestBatchParams.mTSample,
@@ -720,7 +727,7 @@
     if (mSensors == nullptr) return NO_INIT;
     if (isClientDisabled(ident)) return INVALID_OPERATION;
     ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
-    return StatusFromResult(checkReturn(mSensors->flush(handle)));
+    return checkReturnAndGetStatus(mSensors->flush(handle));
 }
 
 bool SensorDevice::isClientDisabled(void* ident) {
@@ -753,16 +760,14 @@
         const int sensor_handle = mActivationCount.keyAt(i);
         ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
                    sensor_handle);
-        status_t err = StatusFromResult(
-                checkReturn(mSensors->batch(
-                    sensor_handle,
-                    info.bestBatchParams.mTSample,
-                    info.bestBatchParams.mTBatch)));
+        status_t err = checkReturnAndGetStatus(mSensors->batch(
+                sensor_handle,
+                info.bestBatchParams.mTSample,
+                info.bestBatchParams.mTBatch));
         ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
 
         if (err == NO_ERROR) {
-            err = StatusFromResult(
-                    checkReturn(mSensors->activate(sensor_handle, 1 /* enabled */)));
+            err = checkReturnAndGetStatus(mSensors->activate(sensor_handle, 1 /* enabled */));
             ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
         }
 
@@ -810,14 +815,13 @@
     Event ev;
     convertFromSensorEvent(*injected_sensor_event, &ev);
 
-    return StatusFromResult(checkReturn(mSensors->injectSensorData(ev)));
+    return checkReturnAndGetStatus(mSensors->injectSensorData(ev));
 }
 
 status_t SensorDevice::setMode(uint32_t mode) {
     if (mSensors == nullptr) return NO_INIT;
-    return StatusFromResult(
-            checkReturn(mSensors->setOperationMode(
-                    static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+    return checkReturnAndGetStatus(mSensors->setOperationMode(
+            static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
 }
 
 int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
@@ -855,7 +859,7 @@
                 if (result == Result::OK) {
                     ret = channelHandle;
                 } else {
-                    ret = StatusFromResult(result);
+                    ret = statusFromResult(result);
                 }
             }));
     return ret;
@@ -894,12 +898,12 @@
     checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
             [&ret, rate] (auto result, auto token) {
                 if (rate == RateLevel::STOP) {
-                    ret = StatusFromResult(result);
+                    ret = statusFromResult(result);
                 } else {
                     if (result == Result::OK) {
                         ret = token;
                     } else {
-                        ret = StatusFromResult(result);
+                        ret = statusFromResult(result);
                     }
                 }
             }));
@@ -1008,7 +1012,7 @@
 }
 
 void SensorDevice::handleHidlDeath(const std::string & detail) {
-    if (!SensorDevice::getInstance().mSensors->supportsMessageQueues()) {
+    if (!mSensors->supportsMessageQueues()) {
         // restart is the only option at present.
         LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
     } else {
@@ -1016,5 +1020,10 @@
     }
 }
 
+status_t SensorDevice::checkReturnAndGetStatus(const Return<Result>& ret) {
+    checkReturn(ret);
+    return (!ret.isOk()) ? DEAD_OBJECT : statusFromResult(ret);
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index e8685c2..d2c6994 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -211,14 +211,14 @@
     status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
                          int64_t maxBatchReportLatencyNs);
 
-    static void handleHidlDeath(const std::string &detail);
+    void handleHidlDeath(const std::string &detail);
     template<typename T>
-    static Return<T> checkReturn(Return<T> &&ret) {
+    void checkReturn(const Return<T>& ret) {
         if (!ret.isOk()) {
             handleHidlDeath(ret.description());
         }
-        return std::move(ret);
     }
+    status_t checkReturnAndGetStatus(const Return<Result>& ret);
     //TODO(b/67425500): remove waiter after bug is resolved.
     sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 3012ed8..c463c4e 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -261,22 +261,6 @@
         mId(id),
         mIsConnected(false),
         mType(type) {
-    std::vector<Hwc2::DisplayCapability> tmpCapabilities;
-    auto error = static_cast<Error>(mComposer.getDisplayCapabilities(mId, &tmpCapabilities));
-    if (error == Error::None) {
-        for (auto capability : tmpCapabilities) {
-            mDisplayCapabilities.emplace(static_cast<DisplayCapability>(capability));
-        }
-    } else if (error == Error::Unsupported) {
-        if (capabilities.count(Capability::SkipClientColorTransform)) {
-            mDisplayCapabilities.emplace(DisplayCapability::SkipClientColorTransform);
-        }
-        bool dozeSupport = false;
-        error = static_cast<Error>(mComposer.getDozeSupport(mId, &dozeSupport));
-        if (error == Error::None && dozeSupport) {
-            mDisplayCapabilities.emplace(DisplayCapability::Doze);
-        }
-    }
     ALOGV("Created display %" PRIu64, id);
 }
 
@@ -660,6 +644,29 @@
 {
     auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode);
     auto intError = mComposer.setPowerMode(mId, intMode);
+
+    if (mode == PowerMode::On) {
+        std::call_once(mDisplayCapabilityQueryFlag, [this]() {
+            std::vector<Hwc2::DisplayCapability> tmpCapabilities;
+            auto error =
+                    static_cast<Error>(mComposer.getDisplayCapabilities(mId, &tmpCapabilities));
+            if (error == Error::None) {
+                for (auto capability : tmpCapabilities) {
+                    mDisplayCapabilities.emplace(static_cast<DisplayCapability>(capability));
+                }
+            } else if (error == Error::Unsupported) {
+                if (mCapabilities.count(Capability::SkipClientColorTransform)) {
+                    mDisplayCapabilities.emplace(DisplayCapability::SkipClientColorTransform);
+                }
+                bool dozeSupport = false;
+                error = static_cast<Error>(mComposer.getDozeSupport(mId, &dozeSupport));
+                if (error == Error::None && dozeSupport) {
+                    mDisplayCapabilities.emplace(DisplayCapability::Doze);
+                }
+            }
+        });
+    }
+
     return static_cast<Error>(intError);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e0a5ef1..b7cdf7f 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -356,6 +356,7 @@
     DisplayType mType;
     std::unordered_map<hwc2_layer_t, std::unique_ptr<Layer>> mLayers;
     std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
+    std::once_flag mDisplayCapabilityQueryFlag;
     std::unordered_set<DisplayCapability> mDisplayCapabilities;
 };
 } // namespace impl
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 3684260..7fa33f5 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -26,6 +26,8 @@
 #include <utils/Trace.h>
 #include <string>
 
+#include <compositionengine/Display.h>
+#include <compositionengine/impl/OutputCompositionState.h>
 #include "DisplayDevice.h"
 #include "Layer.h"
 #include "SurfaceFlinger.h"
@@ -264,7 +266,22 @@
 }
 } // anonymous namespace
 
-float sampleArea(const uint32_t* data, int32_t stride, const Rect& area) {
+float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride,
+                 uint32_t orientation, const Rect& sample_area) {
+    if (!sample_area.isValid() || (sample_area.getWidth() > width) ||
+        (sample_area.getHeight() > height)) {
+        ALOGE("invalid sampling region requested");
+        return 0.0f;
+    }
+
+    // (b/133849373) ROT_90 screencap images produced upside down
+    auto area = sample_area;
+    if (orientation & ui::Transform::ROT_90) {
+        area.top = height - area.top;
+        area.bottom = height - area.bottom;
+        std::swap(area.top, area.bottom);
+    }
+
     std::array<int32_t, 256> brightnessBuckets = {};
     const int32_t majoritySampleNum = area.getWidth() * area.getHeight() / 2;
 
@@ -293,18 +310,21 @@
 
 std::vector<float> RegionSamplingThread::sampleBuffer(
         const sp<GraphicBuffer>& buffer, const Point& leftTop,
-        const std::vector<RegionSamplingThread::Descriptor>& descriptors) {
+        const std::vector<RegionSamplingThread::Descriptor>& descriptors, uint32_t orientation) {
     void* data_raw = nullptr;
     buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &data_raw);
     std::shared_ptr<uint32_t> data(reinterpret_cast<uint32_t*>(data_raw),
                                    [&buffer](auto) { buffer->unlock(); });
     if (!data) return {};
 
+    const int32_t width = buffer->getWidth();
+    const int32_t height = buffer->getHeight();
     const int32_t stride = buffer->getStride();
     std::vector<float> lumas(descriptors.size());
     std::transform(descriptors.begin(), descriptors.end(), lumas.begin(),
                    [&](auto const& descriptor) {
-                       return sampleArea(data.get(), stride, descriptor.area - leftTop);
+                       return sampleArea(data.get(), width, height, stride, orientation,
+                                         descriptor.area - leftTop);
                    });
     return lumas;
 }
@@ -317,6 +337,11 @@
         return;
     }
 
+    const auto device = mFlinger.getDefaultDisplayDevice();
+    const auto display = device->getCompositionDisplay();
+    const auto state = display->getState();
+    const auto orientation = static_cast<ui::Transform::orientation_flags>(state.orientation);
+
     std::vector<RegionSamplingThread::Descriptor> descriptors;
     Region sampleRegion;
     for (const auto& [listener, descriptor] : mDescriptors) {
@@ -326,10 +351,28 @@
 
     const Rect sampledArea = sampleRegion.bounds();
 
-    sp<const DisplayDevice> device = mFlinger.getDefaultDisplayDevice();
-    DisplayRenderArea renderArea(device, sampledArea, sampledArea.getWidth(),
-                                 sampledArea.getHeight(), ui::Dataspace::V0_SRGB,
-                                 ui::Transform::ROT_0);
+    auto dx = 0;
+    auto dy = 0;
+    switch (orientation) {
+        case ui::Transform::ROT_90:
+            dx = device->getWidth();
+            break;
+        case ui::Transform::ROT_180:
+            dx = device->getWidth();
+            dy = device->getHeight();
+            break;
+        case ui::Transform::ROT_270:
+            dy = device->getHeight();
+            break;
+        default:
+            break;
+    }
+
+    ui::Transform t(orientation);
+    auto screencapRegion = t.transform(sampleRegion);
+    screencapRegion = screencapRegion.translate(dx, dy);
+    DisplayRenderArea renderArea(device, screencapRegion.bounds(), sampledArea.getWidth(),
+                                 sampledArea.getHeight(), ui::Dataspace::V0_SRGB, orientation);
 
     std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
 
@@ -395,8 +438,8 @@
     }
 
     ALOGV("Sampling %zu descriptors", activeDescriptors.size());
-    std::vector<float> lumas = sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors);
-
+    std::vector<float> lumas =
+            sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors, orientation);
     if (lumas.size() != activeDescriptors.size()) {
         ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),
               activeDescriptors.size());
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 08134e6..3c6fcf3 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -37,7 +37,8 @@
 class SurfaceFlinger;
 struct SamplingOffsetCallback;
 
-float sampleArea(const uint32_t* data, int32_t stride, const Rect& area);
+float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride,
+                 uint32_t orientation, const Rect& area);
 
 class RegionSamplingThread : public IBinder::DeathRecipient {
 public:
@@ -94,7 +95,7 @@
     };
     std::vector<float> sampleBuffer(
             const sp<GraphicBuffer>& buffer, const Point& leftTop,
-            const std::vector<RegionSamplingThread::Descriptor>& descriptors);
+            const std::vector<RegionSamplingThread::Descriptor>& descriptors, uint32_t orientation);
 
     void doSample();
     void binderDied(const wp<IBinder>& who) override;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index b1bf4e2..5cf8eb1 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -219,6 +219,7 @@
 
     while (mKeepRunning) {
         mConditionVariable.wait(mMutex);
+        std::vector<ListenerStats> completedListenerStats;
 
         // For each listener
         auto completedTransactionsItr = mCompletedTransactions.begin();
@@ -264,11 +265,27 @@
             } else {
                 completedTransactionsItr++;
             }
+
+            completedListenerStats.push_back(std::move(listenerStats));
         }
 
         if (mPresentFence) {
             mPresentFence.clear();
         }
+
+        // If everyone else has dropped their reference to a layer and its listener is dead,
+        // we are about to cause the layer to be deleted. If this happens at the wrong time and
+        // we are holding mMutex, we will cause a deadlock.
+        //
+        // The deadlock happens because this thread is holding on to mMutex and when we delete
+        // the layer, it grabs SF's mStateLock. A different SF binder thread grabs mStateLock,
+        // then call's TransactionCompletedThread::run() which tries to grab mMutex.
+        //
+        // To avoid this deadlock, we need to unlock mMutex when dropping our last reference to
+        // to the layer.
+        mMutex.unlock();
+        completedListenerStats.clear();
+        mMutex.lock();
     }
 }
 
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 7c0ecb3..4f8ed1a 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -253,13 +253,16 @@
     static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
 
     static void setupPreconditions(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
-                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    setPowerMode(HWC_DISPLAY,
+                                 static_cast<Hwc2::IComposerClient::PowerMode>(
+                                         Derived::INIT_POWER_MODE)))
+                .WillOnce(Return(Error::NONE));
 
         FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
                                true /* isPrimary */)
                 .setCapabilities(&test->mDefaultCapabilities)
+                .setPowerMode(Derived::INIT_POWER_MODE)
                 .inject(&test->mFlinger, test->mComposer);
         Mock::VerifyAndClear(test->mComposer);
 
@@ -282,6 +285,13 @@
     }
 
     template <typename Case>
+    static void setupPreconditionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+                                Return(Error::NONE)));
+    }
+
+    template <typename Case>
     static void setupCommonCompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mComposer,
                     setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
@@ -393,6 +403,9 @@
     static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
 
     template <typename Case>
+    static void setupPreconditionCallExpectations(CompositionTest*) {}
+
+    template <typename Case>
     static void setupCommonCompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
 
@@ -1022,6 +1035,7 @@
     using CompositionResult = CompositionResultCase;
 
     static void setupCommon(CompositionTest* test) {
+        Display::template setupPreconditionCallExpectations<ThisCase>(test);
         Display::setupPreconditions(test);
 
         auto layer = Layer::createLayer(test);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 97f9e6a..5f58e7d 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -410,6 +410,7 @@
 
     // The HWC active configuration id
     static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
+    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
 
     static void injectPendingHotplugEvent(DisplayTransactionTest* test,
                                           HWC2::Connection connection) {
@@ -427,6 +428,7 @@
                 .setWidth(DisplayVariant::WIDTH)
                 .setHeight(DisplayVariant::HEIGHT)
                 .setActiveConfig(HWC_ACTIVE_CONFIG_ID)
+                .setPowerMode(INIT_POWER_MODE)
                 .inject(&test->mFlinger, test->mComposer);
     }
 
@@ -435,6 +437,10 @@
         EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
                 .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
                                 Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    setPowerMode(HWC_DISPLAY_ID,
+                                 static_cast<Hwc2::IComposerClient::PowerMode>(INIT_POWER_MODE)))
+                .WillOnce(Return(Error::NONE));
         injectHwcDisplayWithNoDefaultCapabilities(test);
     }
 
@@ -467,9 +473,6 @@
                     getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
                                         IComposerClient::Attribute::DPI_Y, _))
                 .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
-                                Return(Error::NONE)));
 
         if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
             EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -1891,10 +1894,6 @@
     Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
     Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
 
-    EXPECT_CALL(*mComposer, getDisplayCapabilities(Case::Display::HWC_DISPLAY_ID, _))
-            .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
-                            Return(Error::NONE)));
-
     EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
             .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
     EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
index 51d6d7e..160f041 100644
--- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
@@ -17,6 +17,8 @@
 #undef LOG_TAG
 #define LOG_TAG "RegionSamplingTest"
 
+#include <ui/Transform.h>
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <array>
@@ -33,18 +35,21 @@
     static int constexpr kWidth = 98;
     static int constexpr kStride = 100;
     static int constexpr kHeight = 29;
+    static int constexpr kOrientation = ui::Transform::ROT_0;
     std::array<uint32_t, kHeight * kStride> buffer;
     Rect const whole_area{0, 0, kWidth, kHeight};
 };
 
 TEST_F(RegionSamplingTest, calculate_mean_white) {
     std::fill(buffer.begin(), buffer.end(), kWhite);
-    EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatEq(1.0f));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
+                testing::FloatEq(1.0f));
 }
 
 TEST_F(RegionSamplingTest, calculate_mean_black) {
     std::fill(buffer.begin(), buffer.end(), kBlack);
-    EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatEq(0.0f));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
+                testing::FloatEq(0.0f));
 }
 
 TEST_F(RegionSamplingTest, calculate_mean_partial_region) {
@@ -54,7 +59,8 @@
                                  whole_area.top + halfway_down};
     std::fill(buffer.begin(), buffer.begin() + half, 0);
     std::fill(buffer.begin() + half, buffer.end(), kWhite);
-    EXPECT_THAT(sampleArea(buffer.data(), kStride, partial_region), testing::FloatEq(0.0f));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, partial_region),
+                testing::FloatEq(0.0f));
 }
 
 TEST_F(RegionSamplingTest, calculate_mean_mixed_values) {
@@ -63,15 +69,71 @@
         n++;
         return pixel;
     });
-    EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatNear(0.083f, 0.01f));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
+                testing::FloatNear(0.083f, 0.01f));
 }
 
 TEST_F(RegionSamplingTest, bimodal_tiebreaker) {
     std::generate(buffer.begin(), buffer.end(),
                   [n = 0]() mutable { return (n++ % 2) ? kBlack : kWhite; });
     // presently there's no tiebreaking strategy in place, accept either of the means
-    EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area),
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
                 testing::AnyOf(testing::FloatEq(1.0), testing::FloatEq(0.0f)));
 }
 
+TEST_F(RegionSamplingTest, bounds_checking) {
+    std::generate(buffer.begin(), buffer.end(),
+                  [n = 0]() mutable { return (n++ > (kStride * kHeight >> 1)) ? kBlack : kWhite; });
+
+    Rect invalid_region{0, 0, 4, kHeight + 1};
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+                testing::Eq(0.0));
+
+    invalid_region = Rect{0, 0, -4, kHeight};
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+                testing::Eq(0.0));
+
+    invalid_region = Rect{3, 0, 2, 0};
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+                testing::Eq(0.0));
+
+    invalid_region = Rect{0, 3, 0, 2};
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+                testing::Eq(0.0));
+}
+
+// workaround for b/133849373
+TEST_F(RegionSamplingTest, orientation_90) {
+    std::generate(buffer.begin(), buffer.end(),
+                  [n = 0]() mutable { return (n++ > (kStride * kHeight >> 1)) ? kBlack : kWhite; });
+
+    Rect tl_region{0, 0, 4, 4};
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0,
+                           tl_region),
+                testing::Eq(1.0));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180,
+                           tl_region),
+                testing::Eq(1.0));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90,
+                           tl_region),
+                testing::Eq(0.0));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270,
+                           tl_region),
+                testing::Eq(0.0));
+
+    Rect br_region{kWidth - 4, kHeight - 4, kWidth, kHeight};
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0,
+                           br_region),
+                testing::Eq(0.0));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180,
+                           br_region),
+                testing::Eq(0.0));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90,
+                           br_region),
+                testing::Eq(1.0));
+    EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270,
+                           br_region),
+                testing::Eq(1.0));
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index df14e7e..64d34ee 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -386,6 +386,7 @@
         static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
         static constexpr int32_t DEFAULT_DPI = 320;
         static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
+        static constexpr int32_t DEFAULT_POWER_MODE = 2;
 
         FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
                                bool isPrimary)
@@ -431,6 +432,11 @@
             return *this;
         }
 
+        auto& setPowerMode(int mode) {
+            mPowerMode = mode;
+            return *this;
+        }
+
         void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
             static const std::unordered_set<HWC2::Capability> defaultCapabilities;
             if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
@@ -450,6 +456,7 @@
             config.setDpiY(mDpiY);
             display->mutableConfigs().emplace(mActiveConfig, config.build());
             display->mutableIsConnected() = true;
+            display->setPowerMode(static_cast<HWC2::PowerMode>(mPowerMode));
 
             flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
 
@@ -474,6 +481,7 @@
         int32_t mDpiX = DEFAULT_DPI;
         int32_t mDpiY = DEFAULT_DPI;
         int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
+        int32_t mPowerMode = DEFAULT_POWER_MODE;
         const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
     };