Merge "Add hinge angle sensor enum docs"
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 7c989f6..6459805 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -61,11 +61,15 @@
 
 static std::vector<apex::ApexFile> ActivateApexPackages() {
     // The logic here is (partially) copied and adapted from
-    // system/apex/apexd/apexd_main.cpp.
+    // system/apex/apexd/apexd.cpp.
     //
-    // Only scan the APEX directory under /system (within the chroot dir).
-    // Cast call to void to suppress warn_unused_result.
-    static_cast<void>(apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir));
+    // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir).
+    std::vector<const char*> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir,
+                                       apex::kApexPackageVendorDir};
+    for (const auto& dir : apex_dirs) {
+        // Cast call to void to suppress warn_unused_result.
+        static_cast<void>(apex::scanPackagesDirAndActivate(dir));
+    }
     return apex::getActivePackages();
 }
 
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 02416e4..acd833f 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -180,9 +180,9 @@
     }
     mPendingReleaseItem.item = std::move(mSubmitted.front());
     mSubmitted.pop();
-    if (mNextTransaction == nullptr) {
-        processNextBufferLocked();
-    }
+
+    processNextBufferLocked();
+
     mCallbackCV.notify_all();
     decStrong((void*)transactionCallbackThunk);
 }
@@ -201,7 +201,7 @@
     SurfaceComposerClient::Transaction localTransaction;
     bool applyTransaction = true;
     SurfaceComposerClient::Transaction* t = &localTransaction;
-    if (mNextTransaction != nullptr) {
+    if (mNextTransaction != nullptr && mUseNextTransaction) {
         t = mNextTransaction;
         mNextTransaction = nullptr;
         applyTransaction = false;
@@ -263,9 +263,10 @@
     std::unique_lock _lock{mMutex};
 
     if (mNextTransaction != nullptr) {
-        while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) {
+        while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
             mCallbackCV.wait(_lock);
         }
+        mUseNextTransaction = true;
     }
     // add to shadow queue
     mNumFrameAvailable++;
@@ -274,6 +275,7 @@
 
 void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
     std::lock_guard _lock{mMutex};
+    mUseNextTransaction = false;
     mNextTransaction = t;
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7017b7c..ff8b719 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -526,21 +526,6 @@
     mDesiredPresentTime = -1;
 }
 
-void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle) {
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    Vector<ComposerState> composerStates;
-    Vector<DisplayState> displayStates;
-
-    ComposerState s;
-    s.state.surface = handle;
-    s.state.what |= layer_state_t::eReparent;
-    s.state.parentHandleForChild = nullptr;
-
-    composerStates.add(s);
-    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
-    sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, false, {});
-}
-
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
 
@@ -1558,7 +1543,7 @@
         }
         ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
         if (err == NO_ERROR) {
-            return new SurfaceControl(this, handle, gbp, true /* owned */, transformHint);
+            return new SurfaceControl(this, handle, gbp, transformHint);
         }
     }
     return nullptr;
@@ -1589,7 +1574,7 @@
         }
         ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
         if (err == NO_ERROR) {
-            *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */, transformHint);
+            *outSurface = new SurfaceControl(this, handle, gbp, transformHint);
         }
     }
     return err;
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 6292388..a332a1f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -46,34 +46,22 @@
 // ============================================================================
 
 SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
-                               const sp<IGraphicBufferProducer>& gbp, bool owned,
+                               const sp<IGraphicBufferProducer>& gbp,
                                uint32_t transform)
       : mClient(client),
         mHandle(handle),
         mGraphicBufferProducer(gbp),
-        mOwned(owned),
         mTransformHint(transform) {}
 
 SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
     mClient = other->mClient;
     mHandle = other->mHandle;
     mGraphicBufferProducer = other->mGraphicBufferProducer;
-    mOwned = false;
     mTransformHint = other->mTransformHint;
 }
 
 SurfaceControl::~SurfaceControl()
 {
-    // Avoid reparenting the server-side surface to null if we are not the owner of it,
-    // meaning that we retrieved it from another process.
-    if (mHandle != nullptr && mOwned) {
-        SurfaceComposerClient::doDropReferenceTransaction(mHandle);
-    }
-    release();
-}
-
-void SurfaceControl::release()
-{
     // Trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
     mClient.clear();
@@ -157,7 +145,6 @@
 
 sp<IBinder> SurfaceControl::getHandle() const
 {
-    Mutex::Autolock lock(mLock);
     return mHandle;
 }
 
@@ -206,7 +193,7 @@
     return new SurfaceControl(new SurfaceComposerClient(
                                       interface_cast<ISurfaceComposerClient>(client)),
                               handle.get(), interface_cast<IGraphicBufferProducer>(gbp),
-                              false /* owned */, transformHint);
+                               transformHint);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 1b22df2..64c21e0 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -123,6 +123,8 @@
     sp<BLASTBufferItemConsumer> mBufferItemConsumer;
 
     SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
+
+    bool mUseNextTransaction = false;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d0bb6a3..27877bb 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -184,12 +184,6 @@
     static bool getProtectedContentSupport();
 
     /**
-     * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
-     * to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
-     */
-    static void doDropReferenceTransaction(const sp<IBinder>& handle);
-
-    /**
      * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
      * in order with other transactions that use buffers.
      */
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 7bc7c68..ac2bbcc 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -58,10 +58,6 @@
     static bool isSameSurface(
             const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
 
-    // Release the handles assosciated with the SurfaceControl, without reparenting
-    // them off-screen. At the moment if this isn't executed before ~SurfaceControl
-    // is called then the destructor will reparent the layer off-screen for you.
-    void        release();
     // Reparent off-screen and release. This is invoked by the destructor.
     void destroy();
 
@@ -89,7 +85,7 @@
     explicit SurfaceControl(const sp<SurfaceControl>& other);
 
     SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
-                   const sp<IGraphicBufferProducer>& gbp, bool owned, uint32_t transformHint = 0);
+                   const sp<IGraphicBufferProducer>& gbp, uint32_t transformHint = 0);
 
 private:
     // can't be copied
@@ -109,7 +105,6 @@
     sp<IGraphicBufferProducer>  mGraphicBufferProducer;
     mutable Mutex               mLock;
     mutable sp<Surface>         mSurfaceData;
-    bool                        mOwned;
     uint32_t mTransformHint;
 };
 
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index b1a84bd..eb66c8f 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -132,8 +132,7 @@
 }
 
 string BlurFilter::getVertexShader() const {
-    return R"SHADER(
-        #version 310 es
+    return R"SHADER(#version 310 es
 
         in vec2 aPosition;
         in highp vec2 aUV;
@@ -147,8 +146,7 @@
 }
 
 string BlurFilter::getMixFragShader() const {
-    string shader = R"SHADER(
-        #version 310 es
+    string shader = R"SHADER(#version 310 es
         precision mediump float;
 
         in highp vec2 vUV;
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
index 4d7bf44..a0d7af8 100644
--- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp
@@ -43,7 +43,7 @@
     mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition");
     mVUvLoc = mVerticalProgram.getAttributeLocation("aUV");
     mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture");
-    mVIncrementLoc = mVerticalProgram.getUniformLocation("uIncrement");
+    mVGaussianOffsetLoc = mVerticalProgram.getUniformLocation("uGaussianOffsets");
     mVNumSamplesLoc = mVerticalProgram.getUniformLocation("uSamples");
     mVGaussianWeightLoc = mVerticalProgram.getUniformLocation("uGaussianWeights");
 
@@ -51,7 +51,7 @@
     mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition");
     mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV");
     mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture");
-    mHIncrementLoc = mHorizontalProgram.getUniformLocation("uIncrement");
+    mHGaussianOffsetLoc = mHorizontalProgram.getUniformLocation("uGaussianOffsets");
     mHNumSamplesLoc = mHorizontalProgram.getUniformLocation("uSamples");
     mHGaussianWeightLoc = mHorizontalProgram.getUniformLocation("uGaussianWeights");
 }
@@ -60,6 +60,36 @@
     mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight());
 }
 
+static void calculateLinearGaussian(uint32_t samples, double dimension,
+                                    GLfloat* gaussianLinearOffsets, GLfloat* gaussianWeights,
+                                    GLfloat* gaussianLinearWeights) {
+    // The central point in the symmetric bell curve is not offset.
+    // This decision allows one less sampling in the GPU.
+    gaussianLinearWeights[0] = gaussianWeights[0];
+    gaussianLinearOffsets[0] = 0.0;
+
+    // Calculate the linear weights.
+    // This is a vector reduction where an element of the packed reduced array
+    // contains the sum of two adjacent members of the original packed array.
+    // We start preserving the element 1 of the array and then perform sum for
+    // every other (i+=2) element of the gaussianWeights array.
+    gaussianLinearWeights[1] = gaussianWeights[1];
+    const auto start = 1 + ((samples - 1) & 0x1);
+    for (size_t i = start; i < samples; i += 2) {
+        gaussianLinearWeights[start + i / 2] = gaussianWeights[i] + gaussianWeights[i + 1];
+    }
+
+    // Calculate the texture coordinates offsets as an average of the initial offsets,
+    // weighted by the Gaussian weights as described in the original article.
+    gaussianLinearOffsets[1] = 1.0 / dimension;
+    for (size_t i = start; i < samples; i += 2) {
+        GLfloat offset_1 = float(i) / dimension;
+        GLfloat offset_2 = float(i + 1) / dimension;
+        gaussianLinearOffsets[start + i / 2] =
+                (offset_1 * gaussianWeights[i] + offset_2 * gaussianWeights[i + 1]) /
+                gaussianLinearWeights[start + i / 2];
+    }
+}
 status_t GaussianBlurFilter::prepare() {
     ATRACE_NAME("GaussianBlurFilter::prepare");
 
@@ -88,27 +118,47 @@
     mVerticalPassFbo.bind();
     mVerticalProgram.useProgram();
 
-    // Precompute gaussian bell curve, and send it to the shader to avoid
-    // unnecessary computations.
-    auto samples = min(mRadius, kNumSamples);
+    // Precompute gaussian bell curve, and send it to the shader to avoid unnecessary computations.
+    double radiusD = fmax(1.0, mRadius * kFboScale);
+    auto samples = int(fmin(radiusD, kNumSamples));
     GLfloat gaussianWeights[kNumSamples] = {};
-    for (size_t i = 0; i < samples; i++) {
-        float normalized = float(i) / samples;
+
+    gaussianWeights[0] = 1.0f;
+    auto totalWeight = gaussianWeights[0];
+
+    // Gaussian weights calculation.
+    for (size_t i = 1; i < samples; i++) {
+        const double normalized = i / radiusD;
         gaussianWeights[i] = (float)exp(-K * normalized * normalized);
+        totalWeight += 2.0 * gaussianWeights[i];
     }
 
-    // set uniforms
+    // Gaussian weights normalization to avoid work in the GPU.
+    for (size_t i = 0; i < samples; i++) {
+        gaussianWeights[i] /= totalWeight;
+    }
+
     auto width = mVerticalPassFbo.getBufferWidth();
     auto height = mVerticalPassFbo.getBufferHeight();
-    auto radiusF = fmax(1.0f, mRadius * kFboScale);
     glViewport(0, 0, width, height);
+
+    // Allocate space for the corrected Gaussian weights and offsets.
+    // We could use less space, but let's keep the code simple.
+    GLfloat gaussianLinearWeights[kNumSamples] = {};
+    GLfloat gaussianLinearOffsets[kNumSamples] = {};
+
+    // Calculate the weights and offsets for the vertical pass.
+    // This only need to be called every time mRadius or height changes, so it could be optimized.
+    calculateLinearGaussian(samples, double(height), gaussianLinearOffsets, gaussianWeights,
+                            gaussianLinearWeights);
+    // set uniforms
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName());
     glUniform1i(mVTextureLoc, 0);
-    glUniform2f(mVIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f));
-    glUniform1i(mVNumSamplesLoc, samples);
-    glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianWeights);
-    mEngine.checkErrors("Setting vertical-diagonal pass uniforms");
+    glUniform1i(mVNumSamplesLoc, 1 + (samples + 1) / 2);
+    glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianLinearWeights);
+    glUniform1fv(mVGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets);
+    mEngine.checkErrors("Setting vertical pass uniforms");
 
     drawMesh(mVUvLoc, mVPosLoc);
 
@@ -116,14 +166,18 @@
     mBlurredFbo.bind();
     mHorizontalProgram.useProgram();
 
+    // Calculate the weights and offsets for the horizontal pass.
+    // This only needs to be called every time mRadius or width change, so it could be optimized.
+    calculateLinearGaussian(samples, double(width), gaussianLinearOffsets, gaussianWeights,
+                            gaussianLinearWeights);
     // set uniforms
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName());
     glUniform1i(mHTextureLoc, 0);
-    glUniform2f(mHIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f));
-    glUniform1i(mHNumSamplesLoc, samples);
-    glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianWeights);
-    mEngine.checkErrors("Setting vertical pass uniforms");
+    glUniform1i(mHNumSamplesLoc, 1 + (samples + 1) / 2);
+    glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianLinearWeights);
+    glUniform1fv(mHGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets);
+    mEngine.checkErrors("Setting horizontal pass uniforms");
 
     drawMesh(mHUvLoc, mHPosLoc);
 
@@ -142,43 +196,37 @@
     stringstream shader;
     shader << "#version 310 es\n"
            << "#define DIRECTION " << (horizontal ? "1" : "0") << "\n"
-           << "#define NUM_SAMPLES " << kNumSamples <<
+           << "#define NUM_SAMPLES " << 1 + (kNumSamples + 1) / 2 <<
             R"SHADER(
         precision mediump float;
 
         uniform sampler2D uTexture;
-        uniform vec2 uIncrement;
         uniform float[NUM_SAMPLES] uGaussianWeights;
+        uniform float[NUM_SAMPLES] uGaussianOffsets;
         uniform int uSamples;
 
         highp in vec2 vUV;
         out vec4 fragColor;
 
-        vec3 gaussianBlur(sampler2D texture, highp vec2 uv, float inc, vec2 direction) {
-            float totalWeight = 0.0;
-            vec3 blurred = vec3(0.0);
-            float fSamples = 1.0 / float(uSamples);
-
-            for (int i = -uSamples; i <= uSamples; i++) {
-                float weight = uGaussianWeights[abs(i)];
-                float normalized = float(i) * fSamples;
-                float radInc = inc * normalized;
-                blurred += weight * (texture(texture, radInc * direction + uv, 0.0)).rgb;
-                totalWeight += weight;
-            }
-
-            return blurred / totalWeight;
-        }
-
         void main() {
             #if DIRECTION == 1
-            vec3 color = gaussianBlur(uTexture, vUV, uIncrement.x, vec2(1.0, 0.0));
+            const vec2 direction = vec2(1.0, 0.0);
             #else
-            vec3 color = gaussianBlur(uTexture, vUV, uIncrement.y, vec2(0.0, 1.0));
+            const vec2 direction = vec2(0.0, 1.0);
             #endif
-            fragColor = vec4(color, 1.0);
-        }
 
+            // Iteration zero outside loop to avoid sampling the central point twice.
+            vec4 blurred = uGaussianWeights[0] * (texture(uTexture, vUV, 0.0));
+
+            // Iterate one side of the bell to halve the loop iterations.
+            for (int i = 1; i <= uSamples; i++) {
+                vec2 offset = uGaussianOffsets[i] * direction;
+                blurred += uGaussianWeights[i] * (texture(uTexture, vUV + offset, 0.0));
+                blurred += uGaussianWeights[i] * (texture(uTexture, vUV - offset, 0.0));
+            }
+
+            fragColor = vec4(blurred.rgb, 1.0);
+        }
     )SHADER";
     return shader.str();
 }
diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h
index 8580522..44f5fde 100644
--- a/libs/renderengine/gl/filters/GaussianBlurFilter.h
+++ b/libs/renderengine/gl/filters/GaussianBlurFilter.h
@@ -28,9 +28,12 @@
 namespace renderengine {
 namespace gl {
 
+// Class that implements a Gaussian Filter that uses Linear Sampling
+// to halve the number of samples and reduce runtime by 40% as described in:
+// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling
 class GaussianBlurFilter : public BlurFilter {
 public:
-    static constexpr uint32_t kNumSamples = 12;
+    static constexpr uint32_t kNumSamples = 22;
 
     explicit GaussianBlurFilter(GLESRenderEngine& engine);
     status_t prepare() override;
@@ -47,7 +50,7 @@
     GLuint mVPosLoc;
     GLuint mVUvLoc;
     GLuint mVTextureLoc;
-    GLuint mVIncrementLoc;
+    GLuint mVGaussianOffsetLoc;
     GLuint mVNumSamplesLoc;
     GLuint mVGaussianWeightLoc;
 
@@ -56,7 +59,7 @@
     GLuint mHPosLoc;
     GLuint mHUvLoc;
     GLuint mHTextureLoc;
-    GLuint mHIncrementLoc;
+    GLuint mHGaussianOffsetLoc;
     GLuint mHNumSamplesLoc;
     GLuint mHGaussianWeightLoc;
 };
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index dbace11..2fd2579 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -92,7 +92,8 @@
             .setRelativeLayer(layerG, layerR->getHandle(), 1)
             .apply();
 
-    layerG.clear();
+    Transaction().reparent(layerG, nullptr).apply();
+
     // layerG should have been removed
     getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index cf3f8e8..cdd9d92 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -542,6 +542,7 @@
         mCapture->checkPixel(64, 64, 111, 111, 111);
     }
 
+    Transaction().reparent(mChild, nullptr).apply();
     mChild.clear();
 
     {
@@ -1702,6 +1703,7 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
 
     auto redLayerHandle = redLayer->getHandle();
+    Transaction().reparent(redLayer, nullptr).apply();
     redLayer.clear();
     SurfaceComposerClient::Transaction().apply(true);