Merge "Replace the use of native_handle_t by NativeHandle"
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index a639951..852aa79 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1958,6 +1958,11 @@
/* child -- drop privileges before continuing */
drop_capabilities(uid);
+ // Clear BOOTCLASSPATH.
+ // Let dex2oat use the BCP from boot image, excluding updatable BCP
+ // modules for AOT to avoid app recompilation after their upgrades.
+ unsetenv("BOOTCLASSPATH");
+
SetDex2OatScheduling(boot_complete);
if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index cc24ab3..48b07c4 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/statvfs.h>
+#include <sys/stat.h>
#include <sys/xattr.h>
#include <android-base/file.h>
@@ -70,27 +71,28 @@
static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
const std::string fullPath = get_full_path(path);
- ::mkdir(fullPath.c_str(), mode);
- ::chown(fullPath.c_str(), owner, group);
- ::chmod(fullPath.c_str(), mode);
+ EXPECT_EQ(::mkdir(fullPath.c_str(), mode), 0);
+ EXPECT_EQ(::chown(fullPath.c_str(), owner, group), 0);
+ EXPECT_EQ(::chmod(fullPath.c_str(), mode), 0);
}
static void touch(const char* path, uid_t owner, gid_t group, mode_t mode) {
int fd = ::open(get_full_path(path).c_str(), O_RDWR | O_CREAT, mode);
- ::fchown(fd, owner, group);
- ::fchmod(fd, mode);
- ::close(fd);
+ EXPECT_NE(fd, -1);
+ EXPECT_EQ(::fchown(fd, owner, group), 0);
+ EXPECT_EQ(::fchmod(fd, mode), 0);
+ EXPECT_EQ(::close(fd), 0);
}
static int stat_gid(const char* path) {
struct stat buf;
- ::stat(get_full_path(path).c_str(), &buf);
+ EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
return buf.st_gid;
}
static int stat_mode(const char* path) {
struct stat buf;
- ::stat(get_full_path(path).c_str(), &buf);
+ EXPECT_EQ(::stat(get_full_path(path).c_str(), &buf), 0);
return buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
}
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 68011bb..a96c9a0 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -16,7 +16,7 @@
cc_library {
name: "libbinder_ndk",
- vendor_available: false,
+ vendor_available: true,
export_include_dirs: [
"include_ndk",
@@ -50,6 +50,13 @@
"libandroid_runtime",
],
+ header_libs: [
+ "jni_headers",
+ ],
+ export_header_lib_headers: [
+ "jni_headers",
+ ],
+
version_script: "libbinder_ndk.map.txt",
stubs: {
symbol_file: "libbinder_ndk.map.txt",
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index f40eb6c..0510492 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -104,6 +104,7 @@
"IGraphicBufferConsumer.cpp",
"IGraphicBufferProducer.cpp",
"IProducerListener.cpp",
+ "IRegionSamplingListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
"ITransactionCompletedListener.cpp",
diff --git a/libs/gui/IRegionSamplingListener.cpp b/libs/gui/IRegionSamplingListener.cpp
new file mode 100644
index 0000000..40cbfce
--- /dev/null
+++ b/libs/gui/IRegionSamplingListener.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IRegionSamplingListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/IRegionSamplingListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+ ON_SAMPLE_COLLECTED = IBinder::FIRST_CALL_TRANSACTION,
+ LAST = ON_SAMPLE_COLLECTED,
+};
+
+} // Anonymous namespace
+
+class BpRegionSamplingListener : public SafeBpInterface<IRegionSamplingListener> {
+public:
+ explicit BpRegionSamplingListener(const sp<IBinder>& impl)
+ : SafeBpInterface<IRegionSamplingListener>(impl, "BpRegionSamplingListener") {}
+
+ ~BpRegionSamplingListener() override;
+
+ void onSampleCollected(float medianLuma) override {
+ callRemoteAsync<decltype(
+ &IRegionSamplingListener::onSampleCollected)>(Tag::ON_SAMPLE_COLLECTED, medianLuma);
+ }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpRegionSamplingListener::~BpRegionSamplingListener() = default;
+
+IMPLEMENT_META_INTERFACE(RegionSamplingListener, "android.gui.IRegionSamplingListener");
+
+status_t BnRegionSamplingListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::ON_SAMPLE_COLLECTED:
+ return callLocalAsync(data, reply, &IRegionSamplingListener::onSampleCollected);
+ }
+}
+
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index fc9185d..f77eeb2 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -26,6 +26,7 @@
#include <gui/IDisplayEventConnection.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/IRegionSamplingListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerDebugInfo.h>
@@ -754,6 +755,57 @@
error = reply.readBool(outIsWideColorDisplay);
return error;
}
+
+ virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+ const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ Parcel data, reply;
+ status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to write interface token");
+ return error;
+ }
+ error = data.write(samplingArea);
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to write sampling area");
+ return error;
+ }
+ error = data.writeStrongBinder(stopLayerHandle);
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to write stop layer handle");
+ return error;
+ }
+ error = data.writeStrongBinder(IInterface::asBinder(listener));
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to write listener");
+ return error;
+ }
+ error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply);
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to transact");
+ }
+ return error;
+ }
+
+ virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+ Parcel data, reply;
+ status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to write interface token");
+ return error;
+ }
+ error = data.writeStrongBinder(IInterface::asBinder(listener));
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to write listener");
+ return error;
+ }
+ error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data,
+ &reply);
+ if (error != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to transact");
+ }
+ return error;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -1233,6 +1285,38 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
return reply->writeUint64Vector(getPhysicalDisplayIds());
}
+ case ADD_REGION_SAMPLING_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ Rect samplingArea;
+ status_t result = data.read(samplingArea);
+ if (result != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to read sampling area");
+ return result;
+ }
+ sp<IBinder> stopLayerHandle;
+ result = data.readNullableStrongBinder(&stopLayerHandle);
+ if (result != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to read stop layer handle");
+ return result;
+ }
+ sp<IRegionSamplingListener> listener;
+ result = data.readNullableStrongBinder(&listener);
+ if (result != NO_ERROR) {
+ ALOGE("addRegionSamplingListener: Failed to read listener");
+ return result;
+ }
+ return addRegionSamplingListener(samplingArea, stopLayerHandle, listener);
+ }
+ case REMOVE_REGION_SAMPLING_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IRegionSamplingListener> listener;
+ status_t result = data.readNullableStrongBinder(&listener);
+ if (result != NO_ERROR) {
+ ALOGE("removeRegionSamplingListener: Failed to read listener");
+ return result;
+ }
+ return removeRegionSamplingListener(listener);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/include/gui/IRegionSamplingListener.h b/libs/gui/include/gui/IRegionSamplingListener.h
new file mode 100644
index 0000000..1803d9a
--- /dev/null
+++ b/libs/gui/include/gui/IRegionSamplingListener.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include <binder/IInterface.h>
+#include <binder/SafeInterface.h>
+
+namespace android {
+
+class IRegionSamplingListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(RegionSamplingListener)
+
+ virtual void onSampleCollected(float medianLuma) = 0;
+};
+
+class BnRegionSamplingListener : public SafeBnInterface<IRegionSamplingListener> {
+public:
+ BnRegionSamplingListener()
+ : SafeBnInterface<IRegionSamplingListener>("BnRegionSamplingListener") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a2db7bc..1a0b6bb 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -50,6 +50,7 @@
class IDisplayEventConnection;
class IGraphicBufferProducer;
class ISurfaceComposerClient;
+class IRegionSamplingListener;
class Rect;
enum class FrameEvent;
@@ -338,6 +339,26 @@
*/
virtual status_t isWideColorDisplay(const sp<IBinder>& token,
bool* outIsWideColorDisplay) const = 0;
+
+ /* Registers a listener to stream median luma updates from SurfaceFlinger.
+ *
+ * The sampling area is bounded by both samplingArea and the given stopLayerHandle
+ * (i.e., only layers behind the stop layer will be captured and sampled).
+ *
+ * Multiple listeners may be provided so long as they have independent listeners.
+ * If multiple listeners are provided, the effective sampling region for each listener will
+ * be bounded by whichever stop layer has a lower Z value.
+ *
+ * Requires the same permissions as captureLayers and captureScreen.
+ */
+ virtual status_t addRegionSamplingListener(const Rect& samplingArea,
+ const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) = 0;
+
+ /*
+ * Removes a listener that was streaming median luma updates from SurfaceFlinger.
+ */
+ virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
};
// ----------------------------------------------------------------------------
@@ -383,6 +404,8 @@
IS_WIDE_COLOR_DISPLAY,
GET_DISPLAY_NATIVE_PRIMARIES,
GET_PHYSICAL_DISPLAY_IDS,
+ ADD_REGION_SAMPLING_LISTENER,
+ REMOVE_REGION_SAMPLING_LISTENER,
// Always append new enum to the end.
};
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index bec9299..f127853 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -669,6 +669,16 @@
status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
+ status_t addRegionSamplingListener(const Rect& /*samplingArea*/,
+ const sp<IBinder>& /*stopLayerHandle*/,
+ const sp<IRegionSamplingListener>& /*listener*/) override {
+ return NO_ERROR;
+ }
+ status_t removeRegionSamplingListener(
+ const sp<IRegionSamplingListener>& /*listener*/) override {
+ return NO_ERROR;
+ }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 63748bf..89eee6b 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -206,7 +206,7 @@
memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
}
- const Rect win{computeBounds()};
+ const Rect win{getBounds()};
const float bufferWidth = getBufferSize(s).getWidth();
const float bufferHeight = getBufferSize(s).getHeight();
@@ -654,6 +654,38 @@
return mCompositionLayer;
}
+FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const {
+ const State& s(getDrawingState());
+
+ // If we have a sideband stream, or we are scaling the buffer then return the layer size since
+ // we cannot determine the buffer size.
+ if ((s.sidebandStream != nullptr) ||
+ (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) {
+ return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
+ }
+
+ if (mActiveBuffer == nullptr) {
+ return parentBounds;
+ }
+
+ uint32_t bufWidth = mActiveBuffer->getWidth();
+ uint32_t bufHeight = mActiveBuffer->getHeight();
+
+ // Undo any transformations on the buffer and return the result.
+ if (mCurrentTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+
+ if (getTransformToDisplayInverse()) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+ }
+
+ return FloatRect(0, 0, bufWidth, bufHeight);
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index c118b78..0f8a350 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -191,6 +191,8 @@
Rect getBufferSize(const State& s) const override;
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
+
+ FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index b0506fe..2d6da76 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -314,7 +314,7 @@
// if the display frame is not defined, use the parent bounds as the buffer size.
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
- Rect parentBounds = Rect(p->computeBounds(Region()));
+ Rect parentBounds = Rect(p->getBounds(Region()));
if (!parentBounds.isEmpty()) {
return parentBounds;
}
@@ -326,6 +326,18 @@
}
return Rect::INVALID_RECT;
}
+
+FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
+ const State& s(getDrawingState());
+ // for buffer state layers we use the display frame size as the buffer size.
+ if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
+ return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
+ }
+
+ // if the display frame is not defined, use the parent bounds as the buffer size.
+ return parentBounds;
+}
+
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index ef287b9..3320c5b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -88,6 +88,7 @@
uint64_t /*frameNumber*/) override {}
Rect getBufferSize(const State& s) const override;
+ FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 46e587d..51e1f00 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -294,80 +294,83 @@
return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
}
-Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
- const State& s(getDrawingState());
- Region transparentRegion = reduceTransparentRegion ? getActiveTransparentRegion(s) : Region();
- FloatRect bounds = computeBounds(transparentRegion);
+Rect Layer::getScreenBounds(bool reduceTransparentRegion) const {
+ if (!reduceTransparentRegion) {
+ return Rect{mScreenBounds};
+ }
+
+ FloatRect bounds = getBounds();
ui::Transform t = getTransform();
// Transform to screen space.
bounds = t.transform(bounds);
return Rect{bounds};
}
-FloatRect Layer::computeBounds() const {
+FloatRect Layer::getBounds() const {
const State& s(getDrawingState());
- return computeBounds(getActiveTransparentRegion(s));
+ return getBounds(getActiveTransparentRegion(s));
}
-FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
- const State& s(getDrawingState());
- Rect bounds = getCroppedBufferSize(s);
- FloatRect floatBounds = bounds.toFloatRect();
- if (bounds.isValid()) {
- // Layer has bounds. Pass in our bounds as a special case. Then pass on to our parents so
- // that they can clip it.
- floatBounds = cropChildBounds(floatBounds);
- } else {
- // Layer does not have bounds, so we fill to our parent bounds. This is done by getting our
- // parent bounds and inverting the transform to get the maximum bounds we can have that
- // will fit within our parent bounds.
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- ui::Transform t = s.active_legacy.transform;
- // When calculating the parent bounds for purposes of clipping, we don't need to
- // constrain the parent to its transparent region. The transparent region is an
- // optimization based on the buffer contents of the layer, but does not affect the
- // space allocated to it by policy, and thus children should be allowed to extend into
- // the parent's transparent region.
- // One of the main uses is a parent window with a child sitting behind the parent
- // window, marked by a transparent region. When computing the parent bounds from the
- // parent's perspective we pass in the transparent region to reduce buffer allocation
- // size. When computing the parent bounds from the child's perspective, we pass in an
- // empty transparent region in order to extend into the the parent bounds.
- floatBounds = p->computeBounds(Region());
- // Transform back to layer space.
- floatBounds = t.inverse().transform(floatBounds);
- }
- }
-
+FloatRect Layer::getBounds(const Region& activeTransparentRegion) const {
// Subtract the transparent region and snap to the bounds.
- return reduce(floatBounds, activeTransparentRegion);
+ return reduce(mBounds, activeTransparentRegion);
}
-FloatRect Layer::cropChildBounds(const FloatRect& childBounds) const {
+ui::Transform Layer::getTransformWithScale() const {
+ // If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
+ // it isFixedSize) then there may be additional scaling not accounted
+ // for in the transform. We need to mirror this scaling to child surfaces
+ // or we will break the contract where WM can treat child surfaces as
+ // pixels in the parent surface.
+ if (!isFixedSize() || !getBE().compositionInfo.mBuffer) {
+ return mEffectiveTransform;
+ }
+
+ int bufferWidth;
+ int bufferHeight;
+ if ((mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
+ bufferWidth = getBE().compositionInfo.mBuffer->getWidth();
+ bufferHeight = getBE().compositionInfo.mBuffer->getHeight();
+ } else {
+ bufferHeight = getBE().compositionInfo.mBuffer->getWidth();
+ bufferWidth = getBE().compositionInfo.mBuffer->getHeight();
+ }
+ float sx = getActiveWidth(getDrawingState()) / static_cast<float>(bufferWidth);
+ float sy = getActiveHeight(getDrawingState()) / static_cast<float>(bufferHeight);
+ ui::Transform extraParentScaling;
+ extraParentScaling.set(sx, 0, 0, sy);
+ return mEffectiveTransform * extraParentScaling;
+}
+
+void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform) {
const State& s(getDrawingState());
- Rect bounds = getCroppedBufferSize(s);
- FloatRect croppedBounds = childBounds;
- // If the layer has bounds, then crop the passed in child bounds and pass
- // it to our parents so they can crop it as well. If the layer has no bounds,
- // then pass on the child bounds.
- if (bounds.isValid()) {
- croppedBounds = croppedBounds.intersect(bounds.toFloatRect());
- }
+ // Calculate effective layer transform
+ mEffectiveTransform = parentTransform * getActiveTransform(s);
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- // Transform to parent space and allow parent layer to crop the
- // child bounds as well.
- ui::Transform t = s.active_legacy.transform;
- croppedBounds = t.transform(croppedBounds);
- croppedBounds = p->cropChildBounds(croppedBounds);
- croppedBounds = t.inverse().transform(croppedBounds);
+ // Transform parent bounds to layer space
+ parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
+
+ // Calculate display frame
+ mSourceBounds = computeSourceBounds(parentBounds);
+
+ // Calculate bounds by croping diplay frame with layer crop and parent bounds
+ FloatRect bounds = mSourceBounds;
+ const Rect layerCrop = getCrop(s);
+ if (!layerCrop.isEmpty()) {
+ bounds = mSourceBounds.intersect(layerCrop.toFloatRect());
}
- return croppedBounds;
+ bounds = bounds.intersect(parentBounds);
+
+ mBounds = bounds;
+ mScreenBounds = mEffectiveTransform.transform(mBounds);
+ for (const sp<Layer>& child : mDrawingChildren) {
+ child->computeBounds(mBounds, getTransformWithScale());
+ }
}
+
+
Rect Layer::getCroppedBufferSize(const State& s) const {
Rect size = getBufferSize(s);
Rect crop = getCrop(s);
@@ -389,7 +392,7 @@
// if there are no window scaling involved, this operation will map to full
// pixels in the buffer.
- FloatRect activeCropFloat = computeBounds();
+ FloatRect activeCropFloat = getBounds();
ui::Transform t = getTransform();
// Transform to screen space.
activeCropFloat = t.transform(activeCropFloat);
@@ -550,9 +553,9 @@
Rect(activeCrop.right, activeCrop.top, bufferSize.getWidth(), activeCrop.bottom));
}
- // computeBounds returns a FloatRect to provide more accuracy during the
+ // getBounds returns a FloatRect to provide more accuracy during the
// transformation. We then round upon constructing 'frame'.
- Rect frame{t.transform(computeBounds(activeTransparentRegion))};
+ Rect frame{t.transform(getBounds(activeTransparentRegion))};
if (!frame.intersect(display->getViewport(), &frame)) {
frame.clear();
}
@@ -721,7 +724,7 @@
bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
bool useIdentityTransform, Region& /*clearRegion*/,
renderengine::LayerSettings& layer) {
- FloatRect bounds = computeBounds();
+ FloatRect bounds = getBounds();
half alpha = getAlpha();
layer.geometry.boundaries = bounds;
if (useIdentityTransform) {
@@ -841,7 +844,7 @@
renderengine::Mesh& mesh,
bool useIdentityTransform) const {
const ui::Transform renderAreaTransform(renderArea.getTransform());
- FloatRect win = computeBounds();
+ FloatRect win = getBounds();
vec2 lt = vec2(win.left, win.top);
vec2 lb = vec2(win.left, win.bottom);
@@ -1680,6 +1683,7 @@
void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
for (const sp<Layer>& child : mDrawingChildren) {
child->mDrawingParent = newParent;
+ child->computeBounds(newParent->mBounds, newParent->getTransformWithScale());
}
}
@@ -2007,34 +2011,7 @@
}
ui::Transform Layer::getTransform() const {
- ui::Transform t;
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- t = p->getTransform();
-
- // If the parent is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
- // it isFixedSize) then there may be additional scaling not accounted
- // for in the transform. We need to mirror this scaling in child surfaces
- // or we will break the contract where WM can treat child surfaces as
- // pixels in the parent surface.
- if (p->isFixedSize() && p->getBE().compositionInfo.mBuffer != nullptr) {
- int bufferWidth;
- int bufferHeight;
- if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
- bufferWidth = p->getBE().compositionInfo.mBuffer->getWidth();
- bufferHeight = p->getBE().compositionInfo.mBuffer->getHeight();
- } else {
- bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth();
- bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight();
- }
- float sx = p->getActiveWidth(p->getDrawingState()) / static_cast<float>(bufferWidth);
- float sy = p->getActiveHeight(p->getDrawingState()) / static_cast<float>(bufferHeight);
- ui::Transform extraParentScaling;
- extraParentScaling.set(sx, 0, 0, sy);
- t = t * extraParentScaling;
- }
- }
- return t * getActiveTransform(getDrawingState());
+ return mEffectiveTransform;
}
half Layer::getAlpha() const {
@@ -2066,7 +2043,7 @@
}
}
const float radius = getDrawingState().cornerRadius;
- return radius > 0 ? RoundedCornerState(computeBounds(), radius) : RoundedCornerState();
+ return radius > 0 ? RoundedCornerState(getBounds(), radius) : RoundedCornerState();
}
void Layer::commitChildList() {
@@ -2181,6 +2158,10 @@
for (const auto& entry : state.metadata.mMap) {
(*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
}
+ LayerProtoHelper::writeToProto(mEffectiveTransform, layerInfo->mutable_effective_transform());
+ LayerProtoHelper::writeToProto(mSourceBounds, layerInfo->mutable_source_bounds());
+ LayerProtoHelper::writeToProto(mScreenBounds, layerInfo->mutable_screen_bounds());
+ LayerProtoHelper::writeToProto(mBounds, layerInfo->mutable_bounds());
}
void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8b6d4c7..9241e71 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -349,8 +349,15 @@
void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
bool useIdentityTransform) const;
- FloatRect computeBounds(const Region& activeTransparentRegion) const;
- FloatRect computeBounds() const;
+ FloatRect getBounds(const Region& activeTransparentRegion) const;
+ FloatRect getBounds() const;
+
+ // Compute bounds for the layer and cache the results.
+ void computeBounds(FloatRect parentBounds, ui::Transform parentTransform);
+
+ // Get effective layer transform, taking into account all its parent transform with any
+ // scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE.
+ ui::Transform getTransformWithScale() const;
int32_t getSequence() const { return sequence; }
@@ -643,7 +650,7 @@
ssize_t removeChild(const sp<Layer>& layer);
sp<Layer> getParent() const { return mCurrentParent.promote(); }
bool hasParent() const { return getParent() != nullptr; }
- Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
+ Rect getScreenBounds(bool reduceTransparentRegion = true) const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
bool setChildRelativeLayer(const sp<Layer>& childLayer,
const sp<IBinder>& relativeToHandle, int32_t relativeZ);
@@ -660,6 +667,15 @@
*/
virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
+ /**
+ * Returns the source bounds. If the bounds are not defined, it is inferred from the
+ * buffer size. Failing that, the bounds are determined from the passed in parent bounds.
+ * For the root layer, this is the display viewport size.
+ */
+ virtual FloatRect computeSourceBounds(const FloatRect& parentBounds) const {
+ return parentBounds;
+ }
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -879,19 +895,27 @@
LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree);
/**
- * Retuns the child bounds in layer space cropped to its bounds as well all its parent bounds.
- * The cropped bounds must be transformed back from parent layer space to child layer space by
- * applying the inverse of the child's transformation.
- */
- FloatRect cropChildBounds(const FloatRect& childBounds) const;
-
- /**
* Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
* INVALID_RECT if the layer has no buffer and no crop.
* A layer with an invalid buffer size and no crop is considered to be boundless. The layer
* bounds are constrained by its parent bounds.
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
+
+ // Cached properties computed from drawing state
+ // Effective transform taking into account parent transforms and any parent scaling.
+ ui::Transform mEffectiveTransform;
+
+ // Bounds of the layer before any transformation is applied and before it has been cropped
+ // by its parents.
+ FloatRect mSourceBounds;
+
+ // Bounds of the layer in layer space. This is the mSourceBounds cropped by its layer crop and
+ // its parent bounds.
+ FloatRect mBounds;
+
+ // Layer bounds in screen space.
+ FloatRect mScreenBounds;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/IdleTimer.cpp
index e975e65..b28b1aa 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.cpp
+++ b/services/surfaceflinger/Scheduler/IdleTimer.cpp
@@ -22,8 +22,9 @@
namespace android {
namespace scheduler {
-IdleTimer::IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback)
- : mInterval(interval), mTimeoutCallback(timeoutCallback) {}
+IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
+ const TimeoutCallback& timeoutCallback)
+ : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}
IdleTimer::~IdleTimer() {
stop();
@@ -49,11 +50,34 @@
}
void IdleTimer::loop() {
- std::lock_guard<std::mutex> lock(mMutex);
- while (mState != TimerState::STOPPED) {
- if (mState == TimerState::IDLE) {
- mCondition.wait(mMutex);
- } else if (mState == TimerState::RESET) {
+ while (true) {
+ bool triggerReset = false;
+ bool triggerTimeout = false;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mState == TimerState::STOPPED) {
+ break;
+ }
+
+ if (mState == TimerState::IDLE) {
+ mCondition.wait(mMutex);
+ continue;
+ }
+
+ if (mState == TimerState::RESET) {
+ triggerReset = true;
+ }
+ }
+ if (triggerReset && mResetCallback) {
+ mResetCallback();
+ }
+
+ { // lock the mutex again. someone might have called stop meanwhile
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mState == TimerState::STOPPED) {
+ break;
+ }
+
auto triggerTime = std::chrono::steady_clock::now() + mInterval;
mState = TimerState::WAITING;
while (mState == TimerState::WAITING) {
@@ -62,14 +86,14 @@
if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
if (mState == TimerState::WAITING &&
(triggerTime - std::chrono::steady_clock::now()) <= zero) {
- if (mTimeoutCallback) {
- mTimeoutCallback();
- }
-
+ triggerTimeout = true;
mState = TimerState::IDLE;
}
}
}
+ if (triggerTimeout && mTimeoutCallback) {
+ mTimeoutCallback();
+ }
}
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/IdleTimer.h
index aee3fa3..19f1267 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.h
+++ b/services/surfaceflinger/Scheduler/IdleTimer.h
@@ -32,9 +32,11 @@
class IdleTimer {
public:
using Interval = std::chrono::milliseconds;
+ using ResetCallback = std::function<void()>;
using TimeoutCallback = std::function<void()>;
- IdleTimer(const Interval& interval, const TimeoutCallback& timeoutCallback);
+ IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
+ const TimeoutCallback& timeoutCallback);
~IdleTimer();
void start();
@@ -62,6 +64,9 @@
// Interval after which timer expires.
const Interval mInterval;
+ // Callback that happens when timer resets.
+ const ResetCallback mResetCallback;
+
// Callback that happens when timer expires.
const TimeoutCallback mTimeoutCallback;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5268c8c..af439f7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -75,6 +75,7 @@
if (mSetIdleTimerMs > 0) {
mIdleTimer =
std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetIdleTimerMs),
+ [this] { resetTimerCallback(); },
[this] { expiredTimerCallback(); });
mIdleTimer->start();
}
@@ -87,7 +88,6 @@
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
- ResetIdleTimerCallback resetIdleTimerCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
@@ -97,8 +97,7 @@
std::move(interceptCallback));
auto eventThreadConnection =
- createConnectionInternal(eventThread.get(), std::move(resyncCallback),
- std::move(resetIdleTimerCallback));
+ createConnectionInternal(eventThread.get(), std::move(resyncCallback));
mConnections.emplace(id,
std::make_unique<Connection>(new ConnectionHandle(id),
eventThreadConnection,
@@ -115,26 +114,17 @@
std::move(interceptCallback), connectionName);
}
-sp<EventThreadConnection> Scheduler::createConnectionInternal(
- EventThread* eventThread, ResyncCallback&& resyncCallback,
- ResetIdleTimerCallback&& resetIdleTimerCallback) {
+sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
+ ResyncCallback&& resyncCallback) {
return eventThread->createEventConnection(std::move(resyncCallback),
- [this,
- resetIdleTimerCallback =
- std::move(resetIdleTimerCallback)] {
- resetIdleTimer();
- if (resetIdleTimerCallback) {
- resetIdleTimerCallback();
- }
- });
+ [this] { resetIdleTimer(); });
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
- ResetIdleTimerCallback resetIdleTimerCallback) {
+ const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
RETURN_VALUE_IF_INVALID(nullptr);
return createConnectionInternal(mConnections[handle->id]->thread.get(),
- std::move(resyncCallback), std::move(resetIdleTimerCallback));
+ std::move(resyncCallback));
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -200,9 +190,15 @@
}
void Scheduler::setVsyncPeriod(const nsecs_t period) {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
mPrimaryDispSync->reset();
mPrimaryDispSync->setPeriod(period);
- enableHardwareVsync();
+
+ if (!mPrimaryHWVsyncEnabled) {
+ mPrimaryDispSync->beginResync();
+ mEventControlThread->setVsyncEnabled(true);
+ mPrimaryHWVsyncEnabled = true;
+ }
}
void Scheduler::addResyncSample(const nsecs_t timestamp) {
@@ -238,10 +234,19 @@
mHWVsyncAvailable = makeAvailable;
}
+bool Scheduler::getHWSyncAvailable() {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ return mHWVsyncAvailable;
+}
+
nsecs_t Scheduler::expectedPresentTime() {
return mPrimaryDispSync->expectedPresentTime();
}
+void Scheduler::dumpPrimaryDispSync(std::string& result) const {
+ mPrimaryDispSync->dump(result);
+}
+
void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
const std::string layerName) {
// This is V1 logic. It calculates the average FPS based on the timestamp frequency
@@ -263,6 +268,11 @@
mExpiredTimerCallback = expiredTimerCallback;
}
+void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ mResetTimerCallback = resetTimerCallback;
+}
+
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
ATRACE_INT("FrameSkipCount", skipCount);
if (mSkipCount != skipCount) {
@@ -351,6 +361,13 @@
void Scheduler::resetIdleTimer() {
if (mIdleTimer) {
mIdleTimer->reset();
+ }
+}
+
+void Scheduler::resetTimerCallback() {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mResetTimerCallback) {
+ mResetTimerCallback();
ATRACE_INT("ExpiredIdleTimer", 0);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 089d579..d628e40 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -37,6 +37,7 @@
class Scheduler {
public:
using ExpiredIdleTimerCallback = std::function<void()>;
+ using ResetIdleTimerCallback = std::function<void()>;
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -72,12 +73,11 @@
/** Creates an EventThread connection. */
sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
- ResyncCallback, ResetIdleTimerCallback,
+ ResyncCallback,
impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
- ResyncCallback,
- ResetIdleTimerCallback);
+ ResyncCallback);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -109,6 +109,8 @@
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
void makeHWSyncAvailable(bool makeAvailable);
+ // returns HWSyncAvailable flag to SF would enable HW vsync based on this
+ bool getHWSyncAvailable();
nsecs_t expectedPresentTime();
// Adds the present time for given layer to the history of present times.
void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
@@ -117,9 +119,14 @@
void incrementFrameCounter();
// Callback that gets invoked once the idle timer expires.
void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
+ // Callback that gets invoked once the idle timer is reset.
+ void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
// Returns relevant information about Scheduler for dumpsys purposes.
std::string doDump();
+ // calls DispSync::dump() on primary disp sync
+ void dumpPrimaryDispSync(std::string& result) const;
+
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
@@ -127,8 +134,7 @@
private:
// Creates a connection on the given EventThread and forwards the given callbacks.
- sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
- ResetIdleTimerCallback&&);
+ sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
@@ -140,10 +146,11 @@
void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
// Function that resets the idle timer.
void resetIdleTimer();
+ // Function that is called when the timer resets.
+ void resetTimerCallback();
// Function that is called when the timer expires.
void expiredTimerCallback();
-
// If fences from sync Framework are supported.
const bool mHasSyncFramework;
@@ -184,6 +191,7 @@
std::mutex mCallbackLock;
ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
+ ExpiredIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index d7ec733..0bf3ceb 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -124,7 +124,7 @@
changed = true;
}
if (desired.app != current.app) {
- if (mSfConnectionHandle != nullptr) {
+ if (mAppConnectionHandle != nullptr) {
mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
} else {
mAppEventThread->setPhaseOffset(desired.app);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6e21739..a999b27 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -635,17 +635,13 @@
mPhaseOffsets->setRefreshRateType(
scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
- auto resetIdleTimerCallback =
- std::bind(&SurfaceFlinger::setRefreshRateTo, this, RefreshRateType::PERFORMANCE);
-
mAppConnectionHandle =
- mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
- resyncCallback, resetIdleTimerCallback,
+ mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+ resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
- resyncCallback, resetIdleTimerCallback,
- [this](nsecs_t timestamp) {
+ mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
+ resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
@@ -749,6 +745,10 @@
Mutex::Autolock lock(mStateLock);
setRefreshRateTo(RefreshRateType::DEFAULT);
});
+ mScheduler->setResetIdleTimerCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(RefreshRateType::PERFORMANCE);
+ });
mRefreshRateStats =
std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
@@ -1324,6 +1324,17 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::addRegionSamplingListener(
+ const Rect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/,
+ const sp<IRegionSamplingListener>& /*listener*/) {
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::removeRegionSamplingListener(
+ const sp<IRegionSamplingListener>& /*listener*/) {
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1334,16 +1345,10 @@
});
if (mUseScheduler) {
- auto resetIdleTimerCallback = [this] {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(RefreshRateType::PERFORMANCE);
- };
-
const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle
: mAppConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
- std::move(resetIdleTimerCallback));
+ return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
} else {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
return mSFEventThread->createEventConnection(resyncCallback, ResetIdleTimerCallback());
@@ -1414,17 +1419,23 @@
void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
Mutex::Autolock _l(mHWVsyncLock);
-
- if (makeAvailable) {
- mHWVsyncAvailable = true;
- // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
- if (mUseScheduler) {
+ // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
+ if (mUseScheduler) {
+ if (makeAvailable) {
mScheduler->makeHWSyncAvailable(true);
+ } else if (!mScheduler->getHWSyncAvailable()) {
+ // Hardware vsync is not currently available, so abort the resync
+ // attempt for now
+ return;
}
- } else if (!mHWVsyncAvailable) {
- // Hardware vsync is not currently available, so abort the resync
- // attempt for now
- return;
+ } else {
+ if (makeAvailable) {
+ mHWVsyncAvailable = true;
+ } else if (!mHWVsyncAvailable) {
+ // Hardware vsync is not currently available, so abort the resync
+ // attempt for now
+ return;
+ }
}
if (period <= 0) {
@@ -1826,9 +1837,13 @@
ATRACE_CALL();
bool refreshNeeded = handlePageFlip();
+ if (mVisibleRegionsDirty) {
+ computeLayerBounds();
+ }
+
for (auto& layer : mLayersPendingRefresh) {
Region visibleReg;
- visibleReg.set(layer->computeScreenBounds());
+ visibleReg.set(layer->getScreenBounds());
invalidateLayerStack(layer, visibleReg);
}
mLayersPendingRefresh.clear();
@@ -2307,6 +2322,21 @@
}
#pragma clang optimize on // b/119477596
+void SurfaceFlinger::computeLayerBounds() {
+ for (const auto& pair : mDisplays) {
+ const auto& displayDevice = pair.second;
+ const auto display = displayDevice->getCompositionDisplay();
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ // only consider the layers on the given layer stack
+ if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ return;
+ }
+
+ layer->computeBounds(displayDevice->getViewport().toFloatRect(), ui::Transform());
+ }
+ }
+}
+
void SurfaceFlinger::rebuildLayerStacks() {
ATRACE_CALL();
ALOGV("rebuildLayerStacks");
@@ -3047,11 +3077,8 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (mLayersPendingRemoval.indexOf(layer) >= 0) {
// this layer is not visible anymore
- // TODO: we could traverse the tree from front to back and
- // compute the actual visible region
- // TODO: we could cache the transformed region
Region visibleReg;
- visibleReg.set(layer->computeScreenBounds());
+ visibleReg.set(layer->getScreenBounds());
invalidateLayerStack(layer, visibleReg);
}
});
@@ -3220,7 +3247,7 @@
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
const bool translucent = !layer->isOpaque(s);
- Rect bounds(layer->computeScreenBounds());
+ Rect bounds(layer->getScreenBounds());
visibleRegion.set(bounds);
ui::Transform tr = layer->getTransform();
@@ -4524,7 +4551,13 @@
{"--clear-layer-stats"s, dumper([this](std::string&) { mLayerStats.clear(); })},
{"--disable-layer-stats"s, dumper([this](std::string&) { mLayerStats.disable(); })},
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
- {"--dispsync"s, dumper([this](std::string& s) { mPrimaryDispSync->dump(s); })},
+ {"--dispsync"s, dumper([this](std::string& s) {
+ if (mUseScheduler) {
+ mScheduler->dumpPrimaryDispSync(s);
+ } else {
+ mPrimaryDispSync->dump(s);
+ }
+ })},
{"--dump-layer-stats"s, dumper([this](std::string& s) { mLayerStats.dump(s); })},
{"--enable-layer-stats"s, dumper([this](std::string&) { mLayerStats.enable(); })},
{"--frame-composition"s, dumper(&SurfaceFlinger::dumpFrameCompositionInfo)},
@@ -5105,7 +5138,9 @@
return OK;
}
case CAPTURE_LAYERS:
- case CAPTURE_SCREEN: {
+ case CAPTURE_SCREEN:
+ case ADD_REGION_SAMPLING_LISTENER:
+ case REMOVE_REGION_SAMPLING_LISTENER: {
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
@@ -5527,11 +5562,14 @@
const sp<Layer>& oldParent;
const sp<Layer>& newParent;
- ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent)
+ ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
+ const Rect& drawingBounds)
: oldParent(oldParent), newParent(newParent) {
+ // Compute and cache the bounds for the new parent layer.
+ newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform());
oldParent->setChildrenDrawingParent(newParent);
}
- ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
+ ~ReparentForDrawing() { newParent->setChildrenDrawingParent(oldParent); }
};
void render(std::function<void()> drawLayers) override {
@@ -5549,7 +5587,7 @@
LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
bounds.getWidth(), bounds.getHeight(), 0));
- ReparentForDrawing reparent(mLayer, screenshotParentLayer);
+ ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
drawLayers();
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a748bc5..669d3a1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -476,7 +476,9 @@
status_t getProtectedContentSupport(bool* outSupported) const override;
status_t isWideColorDisplay(const sp<IBinder>& displayToken,
bool* outIsWideColorDisplay) const override;
-
+ status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) override;
+ status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
*/
@@ -606,6 +608,9 @@
const sp<Layer>& parent,
bool addToCurrentState);
+ // Traverse through all the layers and compute and cache its bounds.
+ void computeLayerBounds();
+
/* ------------------------------------------------------------------------
* Boot animation, on/off animations and screen capture
*/
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 4c756d9..72cbfac 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -91,6 +91,11 @@
optional float corner_radius = 41;
// Metadata map. May be empty.
map<int32, bytes> metadata = 42;
+
+ optional TransformProto effective_transform = 43;
+ optional FloatRectProto source_bounds = 44;
+ optional FloatRectProto bounds = 45;
+ optional FloatRectProto screen_bounds = 46;
}
message PositionProto {
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ee79c18..3fb8708 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -746,7 +746,7 @@
layerDrawingState.active.h = 100;
layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
-
+ layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform());
layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
return layer;
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
index dc63260..5e82225 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -44,6 +43,7 @@
// Note that there can be false-negatives if the callback happens later.
static constexpr auto waitTimeForUnexpected3msCallback = 6ms;
+ AsyncCallRecorder<void (*)()> mResetTimerCallback;
AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
std::unique_ptr<IdleTimer> mIdleTimer;
@@ -56,31 +56,39 @@
namespace {
TEST_F(IdleTimerTest, createAndDestroyTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {});
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {});
}
TEST_F(IdleTimerTest, startStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
auto startTime = std::chrono::steady_clock::now();
mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
// The idle timer fires after 30ms, so there should be no callback within
- // 25ms (waiting for a ballback for the full 30ms would be problematic).
+ // 25ms (waiting for a callback for the full 30ms would be problematic).
bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value();
// Under ideal conditions there should be no event. But occasionally
// it is possible that the wait just prior takes more than 30ms, and
// a callback is observed. We check the elapsed time since before the IdleTimer
// thread was started as a sanity check to not have a flakey test.
EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(25));
+ EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
mIdleTimer->stop();
}
TEST_F(IdleTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mExpiredTimerCallback.getInvocable());
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
// Observe any event that happens in about 25ms. We don't care if one was
// observed or not.
mExpiredTimerCallback.waitForCall(25ms).has_value();
mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
// There may have been a race with the reset. Clear any callbacks we
// received right afterwards.
clearPendingCallbacks();
@@ -93,60 +101,110 @@
mIdleTimer->stop();
// Final quick check that no more callback were observed.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, startNotCalledTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
- // The start hasn't happened, so the callback does not happen.
+TEST_F(IdleTimerTest, resetBackToBackTest) {
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
+ mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
+ mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+ mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+ mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+ mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+
+ // A single callback should be generated after 30ms
+ EXPECT_TRUE(
+ mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback + 30ms).has_value());
mIdleTimer->stop();
// Final quick check that no more callback were observed.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
+}
+
+TEST_F(IdleTimerTest, startNotCalledTest) {
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
+ // The start hasn't happened, so the callback does not happen.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall(1us).has_value());
+ mIdleTimer->stop();
+ // Final quick check that no more callback were observed.
+ EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
TEST_F(IdleTimerTest, idleTimerIdlesTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
+
// A callback should be generated after 3ms
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
// After one event, it should be idle, and not generate another.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
// Once reset, it should generate another
mIdleTimer->reset();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
// Final quick check that no more callback were observed.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
-
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall(1us).has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
}
TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
+
mIdleTimer->stop();
clearPendingCallbacks();
mIdleTimer->reset();
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
}
TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mExpiredTimerCallback.getInvocable());
+ mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
+ EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+
mIdleTimer->stop();
clearPendingCallbacks();
mIdleTimer->reset();
+
// No more idle events should be observed
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
}
} // namespace
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 26b6d0c..ec76538 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -82,7 +82,6 @@
.WillRepeatedly(Return(mEventThreadConnection));
mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
- ResetIdleTimerCallback(),
impl::EventThread::InterceptVSyncsCallback());
EXPECT_TRUE(mConnectionHandle != nullptr);
}
@@ -103,8 +102,7 @@
// exceptions, just gracefully continues.
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
- returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(),
- ResetIdleTimerCallback()));
+ returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
@@ -125,8 +123,7 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(),
- ResetIdleTimerCallback()));
+ mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
@@ -155,8 +152,7 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(),
- ResetIdleTimerCallback()));
+ mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
EXPECT_TRUE(returnedValue != nullptr);
ASSERT_EQ(returnedValue, mEventThreadConnection);