Merge changes I977507a8,I3f2670c7 into rvc-dev

* changes:
  SurfaceFlinger: fix buffer usage bits of RefreshRateOverlay
  SurfaceFlinger: expected present time directly from VSyncReactor
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 9e89c57..d67ce15 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -997,7 +997,11 @@
     if (err >= NO_ERROR) {
         if (bwr.write_consumed > 0) {
             if (bwr.write_consumed < mOut.dataSize())
-                LOG_ALWAYS_FATAL("Driver did not consume write buffer");
+                LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
+                                 "err: %s consumed: %zu of %zu",
+                                 statusToString(err).c_str(),
+                                 (size_t)bwr.write_consumed,
+                                 mOut.dataSize());
             else {
                 mOut.setDataSize(0);
                 processPostWriteDerefs();
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index beab270..9642a87 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -987,12 +987,22 @@
 
 status_t Parcel::writeString8(const String8& str)
 {
-    status_t err = writeInt32(str.bytes());
-    // only write string if its length is more than zero characters,
-    // as readString8 will only read if the length field is non-zero.
-    // this is slightly different from how writeString16 works.
-    if (str.bytes() > 0 && err == NO_ERROR) {
-        err = write(str.string(), str.bytes()+1);
+    return writeString8(str.string(), str.size());
+}
+
+status_t Parcel::writeString8(const char* str, size_t len)
+{
+    if (str == nullptr) return writeInt32(-1);
+
+    status_t err = writeInt32(len);
+    if (err == NO_ERROR) {
+        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char));
+        if (data) {
+            memcpy(data, str, len);
+            *reinterpret_cast<char*>(data+len) = 0;
+            return NO_ERROR;
+        }
+        err = mError;
     }
     return err;
 }
@@ -1832,37 +1842,39 @@
 
 String8 Parcel::readString8() const
 {
-    String8 retString;
-    status_t status = readString8(&retString);
-    if (status != OK) {
-        // We don't care about errors here, so just return an empty string.
-        return String8();
-    }
-    return retString;
+    size_t len;
+    const char* str = readString8Inplace(&len);
+    if (str) return String8(str, len);
+    ALOGE("Reading a NULL string not supported here.");
+    return String8();
 }
 
 status_t Parcel::readString8(String8* pArg) const
 {
-    int32_t size;
-    status_t status = readInt32(&size);
-    if (status != OK) {
-        return status;
-    }
-    // watch for potential int overflow from size+1
-    if (size < 0 || size >= INT32_MAX) {
-        return BAD_VALUE;
-    }
-    // |writeString8| writes nothing for empty string.
-    if (size == 0) {
+    size_t len;
+    const char* str = readString8Inplace(&len);
+    if (str) {
+        pArg->setTo(str, len);
+        return 0;
+    } else {
         *pArg = String8();
-        return OK;
+        return UNEXPECTED_NULL;
     }
-    const char* str = (const char*)readInplace(size + 1);
-    if (str == nullptr) {
-        return BAD_VALUE;
+}
+
+const char* Parcel::readString8Inplace(size_t* outLen) const
+{
+    int32_t size = readInt32();
+    // watch for potential int overflow from size+1
+    if (size >= 0 && size < INT32_MAX) {
+        *outLen = size;
+        const char* str = (const char*)readInplace(size+1);
+        if (str != nullptr) {
+            return str;
+        }
     }
-    pArg->setTo(str, size);
-    return OK;
+    *outLen = 0;
+    return nullptr;
 }
 
 String16 Parcel::readString16() const
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 4b1a758..c1f64fb 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -119,6 +119,7 @@
     status_t            writeDouble(double val);
     status_t            writeCString(const char* str);
     status_t            writeString8(const String8& str);
+    status_t            writeString8(const char* str, size_t len);
     status_t            writeString16(const String16& str);
     status_t            writeString16(const std::unique_ptr<String16>& str);
     status_t            writeString16(const char16_t* str, size_t len);
@@ -283,6 +284,7 @@
     const char*         readCString() const;
     String8             readString8() const;
     status_t            readString8(String8* pArg) const;
+    const char*         readString8Inplace(size_t* outLen) const;
     String16            readString16() const;
     status_t            readString16(String16* pArg) const;
     status_t            readString16(std::unique_ptr<String16>* pArg) const;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 520d0be..a7cf39a 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1121,8 +1121,9 @@
         mCore->mFreeBuffers.push_back(slot);
     }
 
-    if (mCore->mConsumerListener != nullptr) {
-        mCore->mConsumerListener->onFrameCancelled(mSlots[slot].mGraphicBuffer->getId());
+    auto gb = mSlots[slot].mGraphicBuffer;
+    if (mCore->mConsumerListener != nullptr && gb != nullptr) {
+        mCore->mConsumerListener->onFrameCancelled(gb->getId());
     }
     mSlots[slot].mFence = fence;
     mCore->mDequeueCondition.notify_all();
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index dbd4ef9..6746b0a 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -240,6 +240,19 @@
     float const luma_gray = 0.50;
 };
 
+TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) {
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    // Passing in composer service as the layer handle should not crash, we'll
+    // treat it as a layer that no longer exists and silently allow sampling to
+    // occur.
+    status_t status = composer->addRegionSamplingListener(sampleArea,
+                                                          IInterface::asBinder(composer), listener);
+    ASSERT_EQ(NO_ERROR, status);
+    composer->removeRegionSamplingListener(listener);
+}
+
 TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) {
     fill_render(rgba_green);
 
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 5c24dee..b0b4f6c 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -869,13 +869,32 @@
     return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
 }
 
-void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /*framebuffer*/) {
     ATRACE_CALL();
 
     // back to main framebuffer
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
+bool GLESRenderEngine::cleanupPostRender() {
+    ATRACE_CALL();
+
+    if (mPriorResourcesCleaned ||
+        (mLastDrawFence != nullptr && mLastDrawFence->getStatus() != Fence::Status::Signaled)) {
+        // If we don't have a prior frame needing cleanup, then don't do anything.
+        return false;
+    }
+
+    // Bind the texture to dummy data so that backing image data can be freed.
+    GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(getFramebufferForDrawing());
+    glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer);
+    // Release the cached fence here, so that we don't churn reallocations when
+    // we could no-op repeated calls of this method instead.
+    mLastDrawFence = nullptr;
+    mPriorResourcesCleaned = true;
+    return true;
+}
+
 void GLESRenderEngine::checkErrors() const {
     checkErrors(nullptr);
 }
@@ -1161,7 +1180,13 @@
             // us bad parameters, or we messed up our shader generation).
             return INVALID_OPERATION;
         }
+        mLastDrawFence = nullptr;
+    } else {
+        // The caller takes ownership of drawFence, so we need to duplicate the
+        // fd here.
+        mLastDrawFence = new Fence(dup(drawFence->get()));
     }
+    mPriorResourcesCleaned = false;
 
     checkErrors();
     return NO_ERROR;
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 32dbad1..42b8537 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -17,7 +17,6 @@
 #ifndef SF_GLESRENDERENGINE_H_
 #define SF_GLESRENDERENGINE_H_
 
-#include <stdint.h>
 #include <condition_variable>
 #include <deque>
 #include <mutex>
@@ -76,6 +75,7 @@
                         const std::vector<const LayerSettings*>& layers,
                         ANativeWindowBuffer* buffer, const bool useFramebufferCache,
                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
+    bool cleanupPostRender() override;
 
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     // Creates an output image for rendering to
@@ -231,6 +231,17 @@
     std::mutex mRenderingMutex;
 
     std::unique_ptr<Framebuffer> mDrawingBuffer;
+    // this is a 1x1 RGB buffer, but over-allocate in case a driver wants more
+    // memory or if it needs to satisfy alignment requirements. In this case:
+    // assume that each channel requires 4 bytes, and add 3 additional bytes to
+    // ensure that we align on a word. Allocating 16 bytes will provide a
+    // guarantee that we don't clobber memory.
+    uint32_t mPlaceholderDrawBuffer[4];
+    sp<Fence> mLastDrawFence;
+    // Store a separate boolean checking if prior resources were cleaned up, as
+    // devices that don't support native sync fences can't rely on a last draw
+    // fence that doesn't exist.
+    bool mPriorResourcesCleaned = true;
 
     // Blur effect processor, only instantiated when a layer requests it.
     BlurFilter* mBlurFilter = nullptr;
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index cb0d5cf..383486b 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -68,11 +68,11 @@
     return true;
 }
 
-void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height) {
+void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height, void* data) {
     ATRACE_CALL();
 
     glBindTexture(GL_TEXTURE_2D, mTextureName);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index b88da3b..6757695 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -39,7 +39,7 @@
 
     bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
                                const bool useFramebufferCache) override;
-    void allocateBuffers(uint32_t width, uint32_t height);
+    void allocateBuffers(uint32_t width, uint32_t height, void* data = nullptr);
     EGLImageKHR getEGLImage() const { return mEGLImage; }
     uint32_t getTextureName() const { return mTextureName; }
     uint32_t getFramebufferName() const { return mFramebufferName; }
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index 724877b..db55d17 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -261,15 +261,6 @@
     return shader;
 }
 
-void BlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const {
-    ATRACE_NAME("BlurFilter::blit");
-    read.bindAsReadBuffer();
-    draw.bindAsDrawBuffer();
-    glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0,
-                      draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT,
-                      GL_LINEAR);
-}
-
 } // namespace gl
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
index 7e0819f..9d3fc60 100644
--- a/libs/renderengine/gl/filters/BlurFilter.h
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -56,7 +56,6 @@
 private:
     uint32_t mRadius;
     void drawMesh(GLuint uv, GLuint position);
-    void blit(GLFramebuffer& read, GLFramebuffer& draw) const;
     string getVertexShader() const;
     string getFragmentShader() const;
     string getMixFragShader() const;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 46f3fc6..e06e128 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -111,6 +111,14 @@
     // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
     virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
     virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
+    // Clean-up method that should be called on the main thread after the
+    // drawFence returned by drawLayers fires. This method will free up
+    // resources used by the most recently drawn frame. If the frame is still
+    // being drawn, then this call is silently ignored.
+    //
+    // Returns true if resources were cleaned up, and false if we didn't need to
+    // do any work.
+    virtual bool cleanupPostRender() = 0;
 
     // queries
     virtual size_t getMaxTextureSize() const = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 3358c69..df0f17a 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -22,6 +22,7 @@
 #include <renderengine/Mesh.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/Texture.h>
+#include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/Region.h>
 
@@ -55,6 +56,7 @@
     MOCK_CONST_METHOD0(isProtected, bool());
     MOCK_CONST_METHOD0(supportsProtectedContent, bool());
     MOCK_METHOD1(useProtectedContext, bool(bool));
+    MOCK_METHOD0(cleanupPostRender, bool());
     MOCK_METHOD6(drawLayers,
                  status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
                           ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f5bf014..16a8a0d 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1241,12 +1241,12 @@
     EXPECT_EQ(NO_ERROR, barrier->result);
 }
 
-TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) {
+TEST_F(RenderEngineTest, bindExternalBuffer_withNullBuffer) {
     status_t result = sRE->bindExternalTextureBuffer(0, nullptr, nullptr);
     ASSERT_EQ(BAD_VALUE, result);
 }
 
-TEST_F(RenderEngineTest, drawLayers_bindExternalBufferCachesImages) {
+TEST_F(RenderEngineTest, bindExternalBuffer_cachesImages) {
     sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
     uint32_t texName;
     sRE->genTextures(1, &texName);
@@ -1266,7 +1266,7 @@
     EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
 }
 
-TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
+TEST_F(RenderEngineTest, cacheExternalBuffer_withNullBuffer) {
     std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
             sRE->cacheExternalTextureBufferForTesting(nullptr);
     std::lock_guard<std::mutex> lock(barrier->mutex);
@@ -1278,7 +1278,7 @@
     EXPECT_EQ(BAD_VALUE, barrier->result);
 }
 
-TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
+TEST_F(RenderEngineTest, cacheExternalBuffer_cachesImages) {
     sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
     uint64_t bufferId = buf->getId();
     std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
@@ -1401,6 +1401,35 @@
                       backgroundColor.a);
 }
 
+TEST_F(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<const renderengine::LayerSettings*> layers;
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = fullscreenRect().toFloatRect();
+    BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+    layer.alpha = 1.0;
+    layers.push_back(&layer);
+
+    base::unique_fd fenceOne;
+    sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, base::unique_fd(),
+                    &fenceOne);
+    base::unique_fd fenceTwo;
+    sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, std::move(fenceOne),
+                    &fenceTwo);
+
+    const int fd = fenceTwo.get();
+    if (fd >= 0) {
+        sync_wait(fd, -1);
+    }
+
+    // Only cleanup the first time.
+    EXPECT_TRUE(sRE->cleanupPostRender());
+    EXPECT_FALSE(sRE->cleanupPostRender());
+}
+
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index ecbfdba..9bc70ea 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -535,13 +535,13 @@
   *message = Message{info};
   auto* state = static_cast<MessageState*>(message->GetState());
   state->request = std::move(request);
-  if (request.send_len > 0 && !request.is_impulse) {
-    state->request_data.resize(request.send_len);
+  if (state->request.send_len > 0 && !state->request.is_impulse) {
+    state->request_data.resize(state->request.send_len);
     status = ReceiveData(channel_fd, state->request_data.data(),
                          state->request_data.size());
   }
 
-  if (status && request.is_impulse)
+  if (status && state->request.is_impulse)
     status = ReenableEpollEvent(channel_fd);
 
   if (!status) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 403e21d..6a45d58 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3280,9 +3280,8 @@
             KeyEntry* injectedEntry =
                     new KeyEntry(incomingKey.getId(), incomingKey.getEventTime(),
                                  VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
-                                 incomingKey.getDisplayId(), policyFlags, action, flags,
-                                 incomingKey.getKeyCode(), incomingKey.getScanCode(),
-                                 incomingKey.getMetaState(), incomingKey.getRepeatCount(),
+                                 incomingKey.getDisplayId(), policyFlags, action, flags, keyCode,
+                                 incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
                                  incomingKey.getDownTime());
             injectedEntries.push(injectedEntry);
             break;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 96d86b6..675b77b 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1748,7 +1748,8 @@
 
     virtual void SetUp() override {
         mFakePolicy = new FakeInputReaderPolicy();
-        mTestListener = new TestInputListener(50ms);
+        mTestListener = new TestInputListener(2000ms /*eventHappenedTimeout*/,
+                                              30ms /*eventDidNotHappenTimeout*/);
 
         mReader = new InputReader(std::make_shared<EventHub>(), mFakePolicy, mTestListener);
         ASSERT_EQ(mReader->start(), OK);
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 86ff3b1..9bff166 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -23,7 +23,10 @@
 
 // --- TestInputListener ---
 
-TestInputListener::TestInputListener(const std::chrono::milliseconds timeout) : mTimeout(timeout) {}
+TestInputListener::TestInputListener(std::chrono::milliseconds eventHappenedTimeout,
+                                     std::chrono::milliseconds eventDidNotHappenTimeout)
+      : mEventHappenedTimeout(eventHappenedTimeout),
+        mEventDidNotHappenTimeout(eventDidNotHappenTimeout) {}
 
 TestInputListener::~TestInputListener() { }
 
@@ -86,9 +89,9 @@
 
     std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
     if (queue.empty()) {
-        const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) {
-            return !queue.empty();
-        });
+        const bool eventReceived =
+                mCondition.wait_for(lock, mEventHappenedTimeout,
+                                    [&queue]() REQUIRES(mLock) { return !queue.empty(); });
         if (!eventReceived) {
             FAIL() << "Timed out waiting for event: " << message.c_str();
         }
@@ -105,9 +108,9 @@
     base::ScopedLockAssertion assumeLocked(mLock);
 
     std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
-    const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) {
-        return !queue.empty();
-    });
+    const bool eventReceived =
+            mCondition.wait_for(lock, mEventDidNotHappenTimeout,
+                                [&queue]() REQUIRES(mLock) { return !queue.empty(); });
     if (eventReceived) {
         FAIL() << "Unexpected event: " << message.c_str();
     }
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 4262f5a..d50c6bc 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -32,7 +32,8 @@
     virtual ~TestInputListener();
 
 public:
-    TestInputListener(const std::chrono::milliseconds timeout = 5ms);
+    TestInputListener(std::chrono::milliseconds eventHappenedTimeout = 0ms,
+                      std::chrono::milliseconds eventDidNotHappenTimeout = 0ms);
 
     void assertNotifyConfigurationChangedWasCalled(
             NotifyConfigurationChangedArgs* outEventArgs = nullptr);
@@ -75,7 +76,8 @@
 
     std::mutex mLock;
     std::condition_variable mCondition;
-    const std::chrono::milliseconds mTimeout;
+    const std::chrono::milliseconds mEventHappenedTimeout;
+    const std::chrono::milliseconds mEventDidNotHappenTimeout;
 
     std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
                std::vector<NotifyDeviceResetArgs>,          //
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index aa6f1b8..45e67f7 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -20,7 +20,6 @@
 #include "android/hardware/sensors/2.1/ISensorsCallback.h"
 #include "android/hardware/sensors/2.1/types.h"
 #include "convertV2_1.h"
-#include "SensorService.h"
 
 #include <android-base/logging.h>
 #include <android/util/ProtoOutputStream.h>
@@ -30,6 +29,7 @@
 #include <utils/Errors.h>
 #include <utils/Singleton.h>
 
+#include <cstddef>
 #include <chrono>
 #include <cinttypes>
 #include <thread>
@@ -144,11 +144,22 @@
                     sensor_t sensor;
                     convertToSensor(convertToOldSensorInfo(list[i]), &sensor);
 
-                    if (sensor.resolution == 0) {
-                        // Don't crash here or the device will go into a crashloop.
-                        ALOGE("%s must have a non-zero resolution", sensor.name);
-                        // For simple algos, map their resolution to 1 if it's not specified
-                        sensor.resolution = SensorDeviceUtils::defaultResolutionForType(sensor.type);
+                    if (sensor.type < static_cast<int>(SensorType::DEVICE_PRIVATE_BASE)) {
+                        if(sensor.resolution == 0) {
+                            // Don't crash here or the device will go into a crashloop.
+                            ALOGW("%s must have a non-zero resolution", sensor.name);
+                            // For simple algos, map their resolution to 1 if it's not specified
+                            sensor.resolution =
+                                    SensorDeviceUtils::defaultResolutionForType(sensor.type);
+                        }
+
+                        double promotedResolution = sensor.resolution;
+                        double promotedMaxRange = sensor.maxRange;
+                        if (fmod(promotedMaxRange, promotedResolution) != 0) {
+                            ALOGW("%s's max range %f is not a multiple of the resolution %f",
+                                    sensor.name, sensor.maxRange, sensor.resolution);
+                            SensorDeviceUtils::quantizeValue(&sensor.maxRange, promotedResolution);
+                        }
                     }
 
                     // Sanity check and clamp power if it is 0 (or close)
@@ -411,8 +422,8 @@
     if (mSensors == nullptr) return "HAL not initialized\n";
 
     String8 result;
-    result.appendFormat("Total %zu h/w sensors, %zu running:\n",
-                        mSensorList.size(), mActivationCount.size());
+    result.appendFormat("Total %zu h/w sensors, %zu running %zu disabled clients:\n",
+                        mSensorList.size(), mActivationCount.size(), mDisabledClients.size());
 
     Mutex::Autolock _l(mLock);
     for (const auto & s : mSensorList) {
@@ -425,16 +436,18 @@
         result.append("sampling_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams[j];
-            result.appendFormat("%.1f%s", params.mTSample / 1e6f,
-                j < info.batchParams.size() - 1 ? ", " : "");
+            result.appendFormat("%.1f%s%s", params.mTSample / 1e6f,
+                isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "",
+                (j < info.batchParams.size() - 1) ? ", " : "");
         }
         result.appendFormat("}, selected = %.2f ms; ", info.bestBatchParams.mTSample / 1e6f);
 
         result.append("batching_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams[j];
-            result.appendFormat("%.1f%s", params.mTBatch / 1e6f,
-                    j < info.batchParams.size() - 1 ? ", " : "");
+            result.appendFormat("%.1f%s%s", params.mTBatch / 1e6f,
+                    isClientDisabledLocked(info.batchParams.keyAt(j)) ? "(disabled)" : "",
+                    (j < info.batchParams.size() - 1) ? ", " : "");
         }
         result.appendFormat("}, selected = %.2f ms\n", info.bestBatchParams.mTBatch / 1e6f);
     }
@@ -651,7 +664,7 @@
 }
 
 status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) {
-    bool actuateHardware = false;
+    bool activateHardware = false;
 
     status_t err(NO_ERROR);
 
@@ -677,7 +690,7 @@
 
         if (info.batchParams.indexOfKey(ident) >= 0) {
             if (info.numActiveClients() > 0 && !info.isActive) {
-                actuateHardware = true;
+                activateHardware = true;
             }
         } else {
             // Log error. Every activate call should be preceded by a batch() call.
@@ -697,7 +710,7 @@
         if (info.removeBatchParamsForIdent(ident) >= 0) {
             if (info.numActiveClients() == 0) {
                 // This is the last connection, we need to de-activate the underlying h/w sensor.
-                actuateHardware = true;
+                activateHardware = true;
             } else {
                 // Call batch for this sensor with the previously calculated best effort
                 // batch_rate and timeout. One of the apps has unregistered for sensor
@@ -717,12 +730,8 @@
         }
     }
 
-    if (actuateHardware) {
-        ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
-                 enabled);
-        err = checkReturnAndGetStatus(mSensors->activate(handle, enabled));
-        ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
-                 strerror(-err));
+    if (activateHardware) {
+        err = doActivateHardwareLocked(handle, enabled);
 
         if (err != NO_ERROR && enabled) {
             // Failure when enabling the sensor. Clean up on failure.
@@ -738,6 +747,15 @@
     return err;
 }
 
+status_t SensorDevice::doActivateHardwareLocked(int handle, bool enabled) {
+    ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
+             enabled);
+    status_t err = checkReturnAndGetStatus(mSensors->activate(handle, enabled));
+    ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
+             strerror(-err));
+    return err;
+}
+
 status_t SensorDevice::batch(
         void* ident,
         int handle,
@@ -778,6 +796,18 @@
         info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs);
     }
 
+    status_t err =  updateBatchParamsLocked(handle, info);
+    if (err != NO_ERROR) {
+        ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s",
+              mSensors.get(), handle, info.bestBatchParams.mTSample,
+              info.bestBatchParams.mTBatch, strerror(-err));
+        info.removeBatchParamsForIdent(ident);
+    }
+
+    return err;
+}
+
+status_t SensorDevice::updateBatchParamsLocked(int handle, Info &info) {
     BatchParams prevBestBatchParams = info.bestBatchParams;
     // Find the minimum of all timeouts and batch_rates for this sensor.
     info.selectBatchParams();
@@ -795,13 +825,8 @@
                  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,
-                  info.bestBatchParams.mTBatch, strerror(-err));
-            info.removeBatchParamsForIdent(ident);
-        }
     }
+
     return err;
 }
 
@@ -821,13 +846,61 @@
     return checkReturnAndGetStatus(mSensors->flush(handle));
 }
 
-bool SensorDevice::isClientDisabled(void* ident) {
+bool SensorDevice::isClientDisabled(void* ident) const {
     Mutex::Autolock _l(mLock);
     return isClientDisabledLocked(ident);
 }
 
-bool SensorDevice::isClientDisabledLocked(void* ident) {
-    return mDisabledClients.indexOf(ident) >= 0;
+bool SensorDevice::isClientDisabledLocked(void* ident) const {
+    return mDisabledClients.count(ident) > 0;
+}
+
+std::vector<void *> SensorDevice::getDisabledClientsLocked() const {
+    std::vector<void *> vec;
+    for (const auto& it : mDisabledClients) {
+        vec.push_back(it.first);
+    }
+
+    return vec;
+}
+
+void SensorDevice::addDisabledReasonForIdentLocked(void* ident, DisabledReason reason) {
+    mDisabledClients[ident] |= 1 << reason;
+}
+
+void SensorDevice::removeDisabledReasonForIdentLocked(void* ident, DisabledReason reason) {
+    if (isClientDisabledLocked(ident)) {
+        mDisabledClients[ident] &= ~(1 << reason);
+        if (mDisabledClients[ident] == 0) {
+            mDisabledClients.erase(ident);
+        }
+    }
+}
+
+void SensorDevice::setUidStateForConnection(void* ident, SensorService::UidState state) {
+    Mutex::Autolock _l(mLock);
+    if (state == SensorService::UID_STATE_ACTIVE) {
+        removeDisabledReasonForIdentLocked(ident, DisabledReason::DISABLED_REASON_UID_IDLE);
+    } else {
+        addDisabledReasonForIdentLocked(ident, DisabledReason::DISABLED_REASON_UID_IDLE);
+    }
+
+    for (size_t i = 0; i< mActivationCount.size(); ++i) {
+        int handle = mActivationCount.keyAt(i);
+        Info& info = mActivationCount.editValueAt(i);
+
+        if (info.hasBatchParamsForIdent(ident)) {
+            if (updateBatchParamsLocked(handle, info) != NO_ERROR) {
+                bool enable = info.numActiveClients() == 0 && info.isActive;
+                bool disable = info.numActiveClients() > 0 && !info.isActive;
+
+                if ((enable || disable) &&
+                    doActivateHardwareLocked(handle, enable) == NO_ERROR) {
+                    info.isActive = enable;
+                }
+            }
+        }
+    }
 }
 
 bool SensorDevice::isSensorActive(int handle) const {
@@ -842,8 +915,12 @@
 void SensorDevice::enableAllSensors() {
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
-    mDisabledClients.clear();
-    ALOGI("cleared mDisabledClients");
+
+    for (void *client : getDisabledClientsLocked()) {
+        removeDisabledReasonForIdentLocked(
+            client, DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
+    }
+
     for (size_t i = 0; i< mActivationCount.size(); ++i) {
         Info& info = mActivationCount.editValueAt(i);
         if (info.batchParams.isEmpty()) continue;
@@ -883,7 +960,8 @@
            // Add all the connections that were registered for this sensor to the disabled
            // clients list.
            for (size_t j = 0; j < info.batchParams.size(); ++j) {
-               mDisabledClients.add(info.batchParams.keyAt(j));
+               addDisabledReasonForIdentLocked(
+                   info.batchParams.keyAt(j), DisabledReason::DISABLED_REASON_SERVICE_RESTRICTED);
                ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
            }
 
@@ -1058,7 +1136,7 @@
 
 void SensorDevice::notifyConnectionDestroyed(void* ident) {
     Mutex::Autolock _l(mLock);
-    mDisabledClients.remove(ident);
+    mDisabledClients.erase(ident);
 }
 
 bool SensorDevice::isDirectReportSupported() const {
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 04e6031..5e7d3da 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -18,6 +18,7 @@
 #define ANDROID_SENSOR_DEVICE_H
 
 #include "SensorDeviceUtils.h"
+#include "SensorService.h"
 #include "SensorServiceUtils.h"
 #include "ISensorsWrapper.h"
 
@@ -116,6 +117,8 @@
     hardware::Return<void> onDynamicSensorsDisconnected(
             const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
 
+    void setUidStateForConnection(void* ident, SensorService::UidState state);
+
     bool isReconnecting() const {
         return mReconnecting;
     }
@@ -179,6 +182,13 @@
         // the removed ident. If index >=0, ident is present and successfully removed.
         ssize_t removeBatchParamsForIdent(void* ident);
 
+        bool hasBatchParamsForIdent(void* ident) const {
+            return batchParams.indexOfKey(ident) >= 0;
+        }
+
+        /**
+         * @return The number of active clients of this sensor.
+         */
         int numActiveClients() const;
     };
     DefaultKeyedVector<int, Info> mActivationCount;
@@ -187,8 +197,26 @@
     SensorServiceUtil::RingBuffer<HidlTransportErrorLog> mHidlTransportErrors;
     int mTotalHidlTransportErrors;
 
-    // Use this vector to determine which client is activated or deactivated.
-    SortedVector<void *> mDisabledClients;
+    /**
+     * Enums describing the reason why a client was disabled.
+     */
+    enum DisabledReason : uint8_t {
+        // UID becomes idle (e.g. app goes to background).
+        DISABLED_REASON_UID_IDLE = 0,
+
+        // Sensors are restricted for all clients.
+        DISABLED_REASON_SERVICE_RESTRICTED,
+        DISABLED_REASON_MAX,
+    };
+
+    static_assert(DisabledReason::DISABLED_REASON_MAX < sizeof(uint8_t) * CHAR_BIT);
+
+    // Use this map to determine which client is activated or deactivated.
+    std::unordered_map<void *, uint8_t> mDisabledClients;
+
+    void addDisabledReasonForIdentLocked(void* ident, DisabledReason reason);
+    void removeDisabledReasonForIdentLocked(void* ident, DisabledReason reason);
+
     SensorDevice();
     bool connectHidlService();
     void initializeSensorList();
@@ -214,6 +242,9 @@
     status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
                          int64_t maxBatchReportLatencyNs);
 
+    status_t updateBatchParamsLocked(int handle, Info& info);
+    status_t doActivateHardwareLocked(int handle, bool enable);
+
     void handleHidlDeath(const std::string &detail);
     template<typename T>
     void checkReturn(const Return<T>& ret) {
@@ -225,8 +256,11 @@
     //TODO(b/67425500): remove waiter after bug is resolved.
     sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
 
-    bool isClientDisabled(void* ident);
-    bool isClientDisabledLocked(void* ident);
+    bool isClientDisabled(void* ident) const;
+    bool isClientDisabledLocked(void* ident) const;
+    std::vector<void *> getDisabledClientsLocked() const;
+
+    bool clientHasNoAccessLocked(void* ident) const;
 
     using Event = hardware::sensors::V2_1::Event;
     using SensorInfo = hardware::sensors::V2_1::SensorInfo;
diff --git a/services/sensorservice/SensorDeviceUtils.cpp b/services/sensorservice/SensorDeviceUtils.cpp
index 6bf62e4..0dcf8c0 100644
--- a/services/sensorservice/SensorDeviceUtils.cpp
+++ b/services/sensorservice/SensorDeviceUtils.cpp
@@ -21,7 +21,6 @@
 #include <utils/Log.h>
 
 #include <chrono>
-#include <cmath>
 #include <thread>
 
 using ::android::hardware::Void;
@@ -30,17 +29,6 @@
 
 namespace android {
 namespace SensorDeviceUtils {
-namespace {
-
-inline void quantizeValue(float *value, double resolution) {
-    // Increase the value of the sensor's nominal resolution to ensure that
-    // sensor accuracy improvements, like runtime calibration, are not masked
-    // during requantization.
-    double incRes = 0.25 * resolution;
-    *value = round(static_cast<double>(*value) / incRes) * incRes;
-}
-
-}  // namespace
 
 void quantizeSensorEventValues(sensors_event_t *event, float resolution) {
     LOG_FATAL_IF(resolution == 0, "Resolution must be specified for all sensors!");
diff --git a/services/sensorservice/SensorDeviceUtils.h b/services/sensorservice/SensorDeviceUtils.h
index b66542c..d7e621c 100644
--- a/services/sensorservice/SensorDeviceUtils.h
+++ b/services/sensorservice/SensorDeviceUtils.h
@@ -20,6 +20,7 @@
 #include <android/hidl/manager/1.0/IServiceNotification.h>
 #include <hardware/sensors.h>
 
+#include <cmath>
 #include <condition_variable>
 #include <thread>
 
@@ -30,6 +31,15 @@
 namespace android {
 namespace SensorDeviceUtils {
 
+// Quantizes a single value using a sensor's resolution.
+inline void quantizeValue(float *value, double resolution) {
+    // Increase the value of the sensor's nominal resolution to ensure that
+    // sensor accuracy improvements, like runtime calibration, are not masked
+    // during requantization.
+    double incRes = 0.25 * resolution;
+    *value = round(static_cast<double>(*value) / incRes) * incRes;
+}
+
 // Ensures a sensor event doesn't provide values finer grained than its sensor resolution allows.
 void quantizeSensorEventValues(sensors_event_t *event, float resolution);
 
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 106efd6..e4c33da 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -93,6 +93,18 @@
     return nullptr;
 }
 
+void SensorService::SensorDirectConnection::onSensorAccessChanged(bool hasAccess) {
+    if (!hasAccess) {
+        stopAll(true /* backupRecord */);
+    } else {
+        recoverAll();
+    }
+}
+
+bool SensorService::SensorDirectConnection::hasSensorAccess() const {
+    return mService->hasSensorAccess(mUid, mOpPackageName);
+}
+
 status_t SensorService::SensorDirectConnection::enableDisable(
         int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
         int reservedFlags) {
@@ -125,7 +137,7 @@
         return NO_ERROR;
     }
 
-    if (!mService->isOperationPermitted(mOpPackageName)) {
+    if (!hasSensorAccess()) {
         return PERMISSION_DENIED;
     }
 
@@ -169,12 +181,15 @@
 }
 
 void SensorService::SensorDirectConnection::stopAll(bool backupRecord) {
+    Mutex::Autolock _l(mConnectionLock);
+    stopAllLocked(backupRecord);
+}
 
+void SensorService::SensorDirectConnection::stopAllLocked(bool backupRecord) {
     struct sensors_direct_cfg_t config = {
         .rate_level = SENSOR_DIRECT_RATE_STOP
     };
 
-    Mutex::Autolock _l(mConnectionLock);
     SensorDevice& dev(SensorDevice::getInstance());
     for (auto &i : mActivated) {
         dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
@@ -187,21 +202,25 @@
 }
 
 void SensorService::SensorDirectConnection::recoverAll() {
-    stopAll(false);
-
     Mutex::Autolock _l(mConnectionLock);
-    SensorDevice& dev(SensorDevice::getInstance());
+    if (!mActivatedBackup.empty()) {
+        stopAllLocked(false);
 
-    // recover list of report from backup
-    mActivated = mActivatedBackup;
-    mActivatedBackup.clear();
+        SensorDevice& dev(SensorDevice::getInstance());
 
-    // re-enable them
-    for (auto &i : mActivated) {
-        struct sensors_direct_cfg_t config = {
-            .rate_level = i.second
-        };
-        dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+        // recover list of report from backup
+        ALOG_ASSERT(mActivated.empty(),
+                    "mActivated must be empty if mActivatedBackup was non-empty");
+        mActivated = mActivatedBackup;
+        mActivatedBackup.clear();
+
+        // re-enable them
+        for (auto &i : mActivated) {
+            struct sensors_direct_cfg_t config = {
+                .rate_level = i.second
+            };
+            dev.configureDirectChannel(i.first, getHalChannelHandle(), &config);
+        }
     }
 }
 
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index ead08d3..4181b65 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -42,17 +42,14 @@
     void dump(String8& result) const;
     void dump(util::ProtoOutputStream* proto) const;
     uid_t getUid() const { return mUid; }
+    const String16& getOpPackageName() const { return mOpPackageName; }
     int32_t getHalChannelHandle() const;
     bool isEquivalent(const sensors_direct_mem_t *mem) const;
 
-    // stop all active sensor report. if backupRecord is set to false,
-    // those report can be recovered by recoverAll
-    // called by SensorService when enter restricted mode
-    void stopAll(bool backupRecord = false);
-
-    // recover sensor reports previously stopped by stopAll(true)
-    // called by SensorService when return to NORMAL mode.
-    void recoverAll();
+    // Invoked when access to sensors for this connection has changed, e.g. lost or
+    // regained due to changes in the sensor restricted/privacy mode or the
+    // app changed to idle/active status.
+    void onSensorAccessChanged(bool hasAccess);
 
 protected:
     virtual ~SensorDirectConnection();
@@ -66,6 +63,25 @@
     virtual int32_t configureChannel(int handle, int rateLevel);
     virtual void destroy();
 private:
+    bool hasSensorAccess() const;
+
+    // Stops all active sensor direct report requests.
+    //
+    // If backupRecord is true, stopped requests can be recovered
+    // by a subsequent recoverAll() call (e.g. when temporarily stopping
+    // sensors for sensor privacy/restrict mode or when an app becomes
+    // idle).
+    void stopAll(bool backupRecord = false);
+    // Same as stopAll() but with mConnectionLock held.
+    void stopAllLocked(bool backupRecord);
+
+    // Recover sensor requests previously stopped by stopAll(true).
+    // This method can be called when a sensor access resumes (e.g.
+    // sensor privacy/restrict mode lifted or app becomes active).
+    //
+    // If no requests are backed up by stopAll(), this method is no-op.
+    void recoverAll();
+
     const sp<SensorService> mService;
     const uid_t mUid;
     const sensors_direct_mem_t mMem;
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index e799372..ccf05d9 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -31,12 +31,11 @@
 
 SensorService::SensorEventConnection::SensorEventConnection(
         const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
-        const String16& opPackageName, bool hasSensorAccess)
+        const String16& opPackageName)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
       mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
       mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
-      mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false),
-      mHasSensorAccess(hasSensorAccess) {
+      mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false) {
     mChannel = new BitTube(mService->mSocketBufferSize);
 #if DEBUG_CONNECTIONS
     mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -431,13 +430,9 @@
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
-void SensorService::SensorEventConnection::setSensorAccess(const bool hasAccess) {
-    Mutex::Autolock _l(mConnectionLock);
-    mHasSensorAccess = hasAccess;
-}
-
 bool SensorService::SensorEventConnection::hasSensorAccess() {
-    return mHasSensorAccess && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
+    return mService->isUidActive(mUid)
+        && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
 }
 
 bool SensorService::SensorEventConnection::noteOpIfRequired(const sensors_event_t& event) {
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 1ca35c0..13cee6f 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -49,8 +49,7 @@
 
 public:
     SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
-                          bool isDataInjectionMode, const String16& opPackageName,
-                          bool hasSensorAccess);
+                          bool isDataInjectionMode, const String16& opPackageName);
 
     status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
                         wp<const SensorEventConnection> const * mapFlushEventsToConnections = nullptr);
@@ -69,8 +68,6 @@
 
     uid_t getUid() const { return mUid; }
 
-    void setSensorAccess(const bool hasAccess);
-
 private:
     virtual ~SensorEventConnection();
     virtual void onFirstRef();
@@ -185,7 +182,6 @@
 
     mutable Mutex mDestroyLock;
     bool mDestroyed;
-    bool mHasSensorAccess;
 
     // Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
     // valid mapping for sensors that require a permission in order to reduce the lookup time.
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 5fdc74f..ffcd0a0 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -299,13 +299,33 @@
     }
 }
 
-void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
+void SensorService::onUidStateChanged(uid_t uid, UidState state) {
+    SensorDevice& dev(SensorDevice::getInstance());
+
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
     for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
         if (conn->getUid() == uid) {
-            conn->setSensorAccess(hasAccess);
+            dev.setUidStateForConnection(conn.get(), state);
         }
     }
+
+    for (const sp<SensorDirectConnection>& conn : connLock.getDirectConnections()) {
+        if (conn->getUid() == uid) {
+            // Update sensor subscriptions if needed
+            bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
+            conn->onSensorAccessChanged(hasAccess);
+        }
+    }
+}
+
+bool SensorService::hasSensorAccess(uid_t uid, const String16& opPackageName) {
+    Mutex::Autolock _l(mLock);
+    return hasSensorAccessLocked(uid, opPackageName);
+}
+
+bool SensorService::hasSensorAccessLocked(uid_t uid, const String16& opPackageName) {
+    return !mSensorPrivacyPolicy->isSensorPrivacyEnabled()
+        && isUidActive(uid) && !isOperationRestrictedLocked(opPackageName);
 }
 
 const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) {
@@ -638,8 +658,9 @@
 
 void SensorService::disableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
     SensorDevice& dev(SensorDevice::getInstance());
-    for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
-        connection->stopAll(true /* backupRecord */);
+    for (const sp<SensorDirectConnection>& conn : connLock->getDirectConnections()) {
+        bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
+        conn->onSensorAccessChanged(hasAccess);
     }
     dev.disableAllSensors();
     // Clear all pending flush connections for all active sensors. If one of the active
@@ -666,8 +687,9 @@
     }
     SensorDevice& dev(SensorDevice::getInstance());
     dev.enableAllSensors();
-    for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
-        connection->recoverAll();
+    for (const sp<SensorDirectConnection>& conn : connLock->getDirectConnections()) {
+        bool hasAccess = hasSensorAccessLocked(conn->getUid(), conn->getOpPackageName());
+        conn->onSensorAccessChanged(hasAccess);
     }
 }
 
@@ -1234,9 +1256,8 @@
             (packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;
     String16 connOpPackageName =
             (opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
-    bool hasSensorAccess = mUidPolicy->isUidActive(uid);
     sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
-            requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));
+            requestedMode == DATA_INJECTION, connOpPackageName));
     if (requestedMode == DATA_INJECTION) {
         mConnectionHolder.addEventConnectionIfNotPresent(result);
         // Add the associated file descriptor to the Looper for polling whenever there is data to
@@ -1887,13 +1908,12 @@
     return (packageName.contains(mWhiteListedPackage.string()));
 }
 
-bool SensorService::isOperationPermitted(const String16& opPackageName) {
-    Mutex::Autolock _l(mLock);
+bool SensorService::isOperationRestrictedLocked(const String16& opPackageName) {
     if (mCurrentOperatingMode == RESTRICTED) {
         String8 package(opPackageName);
-        return isWhiteListedPackage(package);
+        return !isWhiteListedPackage(package);
     }
-    return true;
+    return false;
 }
 
 void SensorService::UidPolicy::registerSelf() {
@@ -1921,7 +1941,7 @@
     }
     sp<SensorService> service = mService.promote();
     if (service != nullptr) {
-        service->setSensorAccess(uid, true);
+        service->onUidStateChanged(uid, UID_STATE_ACTIVE);
     }
 }
 
@@ -1936,7 +1956,7 @@
     if (deleted) {
         sp<SensorService> service = mService.promote();
         if (service != nullptr) {
-            service->setSensorAccess(uid, false);
+            service->onUidStateChanged(uid, UID_STATE_IDLE);
         }
     }
 }
@@ -1964,7 +1984,7 @@
     if (wasActive != isActive) {
         sp<SensorService> service = mService.promote();
         if (service != nullptr) {
-            service->setSensorAccess(uid, isActive);
+            service->onUidStateChanged(uid, isActive ? UID_STATE_ACTIVE : UID_STATE_IDLE);
         }
     }
 }
@@ -1990,6 +2010,10 @@
     return mActiveUids.find(uid) != mActiveUids.end();
 }
 
+bool SensorService::isUidActive(uid_t uid) {
+    return mUidPolicy->isUidActive(uid);
+}
+
 void SensorService::SensorPrivacyPolicy::registerSelf() {
     SensorPrivacyManager spm;
     mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 7d17dda..3bb8421 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -75,6 +75,11 @@
     class SensorDirectConnection;
 
 public:
+    enum UidState {
+      UID_STATE_ACTIVE = 0,
+      UID_STATE_IDLE,
+    };
+
     void cleanupConnection(SensorEventConnection* connection);
     void cleanupConnection(SensorDirectConnection* c);
 
@@ -194,6 +199,8 @@
             std::unordered_map<uid_t, bool> mOverrideUids;
     };
 
+    bool isUidActive(uid_t uid);
+
     // Sensor privacy allows a user to disable access to all sensors on the device. When
     // enabled sensor privacy will prevent all apps, including active apps, from accessing
     // sensors, they will not receive trigger nor on-change events, flush event behavior
@@ -332,7 +339,11 @@
     // allowed to register for or call flush on sensors. Typically only cts test packages are
     // allowed.
     bool isWhiteListedPackage(const String8& packageName);
-    bool isOperationPermitted(const String16& opPackageName);
+
+    // Returns true if a connection with the specified opPackageName has no access to sensors
+    // in the RESTRICTED mode (i.e. the service is in RESTRICTED mode, and the package is not
+    // whitelisted). mLock must be held to invoke this method.
+    bool isOperationRestrictedLocked(const String16& opPackageName);
 
     // Reset the state of SensorService to NORMAL mode.
     status_t resetToNormalMode();
@@ -349,7 +360,13 @@
     void enableSchedFifoMode();
 
     // Sets whether the given UID can get sensor data
-    void setSensorAccess(uid_t uid, bool hasAccess);
+    void onUidStateChanged(uid_t uid, UidState state);
+
+    // Returns true if a connection with the given uid and opPackageName
+    // currently has access to sensors.
+    bool hasSensorAccess(uid_t uid, const String16& opPackageName);
+    // Same as hasSensorAccess but with mLock held.
+    bool hasSensorAccessLocked(uid_t uid, const String16& opPackageName);
 
     // Overrides the UID state as if it is idle
     status_t handleSetUidState(Vector<String16>& args, int err);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 9d293b7..0b9e3d7 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -199,13 +199,8 @@
     }
 }
 
-void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+void RegionSamplingThread::addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
                                        const sp<IRegionSamplingListener>& listener) {
-    wp<Layer> stopLayer;
-    if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) {
-        stopLayer = static_cast<Layer::Handle*>(stopLayerHandle.get())->owner;
-    }
-
     sp<IBinder> asBinder = IInterface::asBinder(listener);
     asBinder->linkToDeath(this);
     std::lock_guard lock(mSamplingMutex);
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 99c07c2..b9b7a3c 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -69,7 +69,7 @@
 
     // Add a listener to receive luma notifications. The luma reported via listener will
     // report the median luma for the layers under the stopLayerHandle, in the samplingArea region.
-    void addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+    void addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
                      const sp<IRegionSamplingListener>& listener);
     // Remove the listener to stop receiving median luma notifications.
     void removeListener(const sp<IRegionSamplingListener>& listener);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a6e1e69..5ccf7c7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1454,7 +1454,9 @@
     if (!listener || samplingArea == Rect::INVALID_RECT) {
         return BAD_VALUE;
     }
-    mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
+
+    const wp<Layer> stopLayer = fromHandle(stopLayerHandle);
+    mRegionSamplingThread->addListener(samplingArea, stopLayer, listener);
     return NO_ERROR;
 }
 
@@ -2330,6 +2332,9 @@
     }
     getBE().mLastSwapTime = currentTime;
 
+    // Cleanup any outstanding resources due to rendering a prior frame.
+    getRenderEngine().cleanupPostRender();
+
     {
         std::lock_guard lock(mTexturePoolMutex);
         if (mTexturePool.size() < mTexturePoolSize) {
@@ -3157,7 +3162,7 @@
         Mutex::Autolock _l(mStateLock);
         sp<Layer> parent;
         if (parentHandle != nullptr) {
-            parent = fromHandle(parentHandle);
+            parent = fromHandleLocked(parentHandle).promote();
             if (parent == nullptr) {
                 return NAME_NOT_FOUND;
             }
@@ -3532,7 +3537,7 @@
 
     sp<Layer> layer = nullptr;
     if (s.surface) {
-        layer = fromHandle(s.surface);
+        layer = fromHandleLocked(s.surface).promote();
     } else {
         // The client may provide us a null handle. Treat it as if the layer was removed.
         ALOGW("Attempt to set client state with a null layer handle");
@@ -3848,7 +3853,7 @@
 
     {
         Mutex::Autolock _l(mStateLock);
-        mirrorFrom = fromHandle(mirrorFromHandle);
+        mirrorFrom = fromHandleLocked(mirrorFromHandle).promote();
         if (!mirrorFrom) {
             return NAME_NOT_FOUND;
         }
@@ -5560,7 +5565,7 @@
     {
         Mutex::Autolock lock(mStateLock);
 
-        parent = fromHandle(layerHandleBinder);
+        parent = fromHandleLocked(layerHandleBinder).promote();
         if (parent == nullptr || parent->isRemovedFromCurrentState()) {
             ALOGE("captureLayers called with an invalid or removed parent");
             return NAME_NOT_FOUND;
@@ -5593,7 +5598,7 @@
         reqHeight = crop.height() * frameScale;
 
         for (const auto& handle : excludeHandles) {
-            sp<Layer> excludeLayer = fromHandle(handle);
+            sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
             if (excludeLayer != nullptr) {
                 excludeLayers.emplace(excludeLayer);
             } else {
@@ -6056,7 +6061,12 @@
     mFlinger->setInputWindowsFinished();
 }
 
-sp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
+    Mutex::Autolock _l(mStateLock);
+    return fromHandleLocked(handle);
+}
+
+wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) {
     BBinder* b = nullptr;
     if (handle) {
         b = handle->localBinder();
@@ -6066,7 +6076,7 @@
     }
     auto it = mLayersByLocalBinderToken.find(b);
     if (it != mLayersByLocalBinderToken.end()) {
-        return it->second.promote();
+        return it->second;
     }
     return nullptr;
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7f6c260..6e49f37 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -331,7 +331,12 @@
         return mTransactionCompletedThread;
     }
 
-    sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
+    // Converts from a binder handle to a Layer
+    // Returns nullptr if the handle does not point to an existing layer.
+    // Otherwise, returns a weak reference so that callers off the main-thread
+    // won't accidentally hold onto the last strong reference.
+    wp<Layer> fromHandle(const sp<IBinder>& handle);
+    wp<Layer> fromHandleLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
 
     // Inherit from ClientCache::ErasedRecipient
     void bufferErased(const client_cache_t& clientCacheId) override;
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index cccf314..ba640de 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -404,7 +404,6 @@
     auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
 
     auto fromHandle(const sp<IBinder>& handle) {
-        Mutex::Autolock _l(mFlinger->mStateLock);
         return mFlinger->fromHandle(handle);
     }
 
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index fbbb69c..2a48a22 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -322,7 +322,7 @@
 TEST_F(TransactionApplicationTest, FromHandle) {
     sp<IBinder> badHandle;
     auto ret = mFlinger.fromHandle(badHandle);
-    EXPECT_EQ(nullptr, ret.get());
+    EXPECT_EQ(nullptr, ret.promote().get());
 }
 } // namespace android