Merge changes Id58fc8e8,Ic5657e0e
* changes:
libbinder fuzzer: print data from inplace reads
libbinder fuzzer: read flattenable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 302d491..0a91a07 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -300,12 +300,10 @@
* Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
* The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
* is set, the vector only contains files that were written in the last 30 minutes.
- * If |limit_by_count| is set, the vector only contains the ten latest files.
*/
static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
const std::string& file_prefix,
- bool limit_by_mtime,
- bool limit_by_count = true) {
+ bool limit_by_mtime) {
const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
@@ -349,15 +347,6 @@
dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
}
- // Sort in descending modification time so that we only keep the newest
- // reports if |limit_by_count| is true.
- std::sort(dump_data.begin(), dump_data.end(),
- [](const DumpData& d1, const DumpData& d2) { return d1.mtime > d2.mtime; });
-
- if (limit_by_count && dump_data.size() > 10) {
- dump_data.erase(dump_data.begin() + 10, dump_data.end());
- }
-
return dump_data;
}
@@ -918,6 +907,31 @@
"-v", "uid", "-d", "*:v"});
}
+static void DumpIncidentReport() {
+ if (!ds.IsZipping()) {
+ MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
+ return;
+ }
+ DurationReporter duration_reporter("INCIDENT REPORT");
+ const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
+ auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ if (fd < 0) {
+ MYLOGE("Could not open %s to dump incident report.\n", path.c_str());
+ return;
+ }
+ RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build());
+ bool empty = 0 == lseek(fd, 0, SEEK_END);
+ if (!empty) {
+ // Use a different name from "incident.proto"
+ // /proto/incident.proto is reserved for incident service dump
+ // i.e. metadata for debugging.
+ ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
+ }
+ unlink(path.c_str());
+}
+
static void DumpIpTablesAsRoot() {
RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
@@ -1490,6 +1504,9 @@
printf("========================================================\n");
// This differs from the usual dumpsys stats, which is the stats report data.
RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
+
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
+
return Dumpstate::RunStatus::OK;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d0f20fe..573a038 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -509,7 +509,7 @@
}
}
-#ifdef __ANDROID_VNDK__
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index b84657a..2894482 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -81,7 +81,7 @@
VINTF = 0b111111,
};
-#ifdef __ANDROID_VNDK__
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
static constexpr Level kLocalStability = Level::VENDOR;
#else
static constexpr Level kLocalStability = Level::SYSTEM;
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index e6aeb04..b03fce1 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -20,7 +20,7 @@
__BEGIN_DECLS
-#ifdef __ANDROID_VNDK__
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
/**
* This interface has the stability of the vendor image.
@@ -31,7 +31,7 @@
AIBinder_markVendorStability(binder);
}
-#else // ndef defined __ANDROID_VNDK__
+#else // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
/**
* This interface has the stability of the system image.
@@ -42,7 +42,7 @@
AIBinder_markSystemStability(binder);
}
-#endif // ifdef __ANDROID_VNDK__
+#endif // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
/**
* This interface has system<->vendor stability
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6b5021d..547e5f1 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1327,7 +1327,9 @@
break;
}
setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]);
- setPosition(sc, x, y);
+ float offsetX = xScale * source.left;
+ float offsetY = yScale * source.top;
+ setPosition(sc, x - offsetX, y - offsetY);
return *this;
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d189846..b500ad3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -295,7 +295,7 @@
const CompositorTiming& compositorTiming) {
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
- if (!mFrameLatencyNeeded) return false;
+ if (!mBufferInfo.mFrameLatencyNeeded) return false;
// Update mFrameEventHistory.
{
@@ -337,7 +337,7 @@
}
mFrameTracker.advanceFrame();
- mFrameLatencyNeeded = false;
+ mBufferInfo.mFrameLatencyNeeded = false;
return true;
}
@@ -401,7 +401,7 @@
gatherBufferInfo();
mRefreshPending = true;
- mFrameLatencyNeeded = true;
+ mBufferInfo.mFrameLatencyNeeded = true;
if (oldBufferInfo.mBuffer == nullptr) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
@@ -735,6 +735,35 @@
mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;
mPotentialCursor = bufferClonedFrom->mPotentialCursor;
mProtectedByApp = bufferClonedFrom->mProtectedByApp;
+
+ updateCloneBufferInfo();
+}
+
+void BufferLayer::updateCloneBufferInfo() {
+ if (!isClone() || !isClonedFromAlive()) {
+ return;
+ }
+
+ sp<BufferLayer> clonedFrom = static_cast<BufferLayer*>(getClonedFrom().get());
+ mBufferInfo = clonedFrom->mBufferInfo;
+ mSidebandStream = clonedFrom->mSidebandStream;
+ surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
+ mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
+ mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
+
+ // After buffer info is updated, the drawingState from the real layer needs to be copied into
+ // the cloned. This is because some properties of drawingState can change when latchBuffer is
+ // called. However, copying the drawingState would also overwrite the cloned layer's relatives.
+ // Therefore, temporarily store the relatives so they can be set in the cloned drawingState
+ // again.
+ wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
+ SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
+ mDrawingState = clonedFrom->mDrawingState;
+ // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
+ // InputWindows per client token yet.
+ mDrawingState.inputInfo.token = nullptr;
+ mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
+ mDrawingState.zOrderRelatives = tmpZOrderRelatives;
}
} // namespace android
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b2c0618..656ba12 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -165,6 +165,8 @@
sp<GraphicBuffer> mBuffer;
int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
+
+ bool mFrameLatencyNeeded{false};
};
BufferInfo mBufferInfo;
@@ -195,6 +197,8 @@
ui::Dataspace translateDataspace(ui::Dataspace dataspace);
void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+ void updateCloneBufferInfo() override;
+ uint64_t mPreviousFrameNumber = 0;
private:
// Returns true if this layer requires filtering
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 36dff15..f3e8a19 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -111,8 +111,6 @@
PixelFormat mFormat{PIXEL_FORMAT_NONE};
- // Only accessed on the main thread.
- uint64_t mPreviousFrameNumber{0};
bool mUpdateTexImageFailed{false};
uint64_t mPreviousBufferId = 0;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 30fdbe1..fa4539a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -125,9 +125,10 @@
bool BufferStateLayer::willPresentCurrentTransaction() const {
// Returns true if the most recent Transaction applied to CurrentState will be presented.
- return getSidebandStreamChanged() || getAutoRefresh() ||
+ return (getSidebandStreamChanged() || getAutoRefresh() ||
(mCurrentState.modified &&
- (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr));
+ (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr))) &&
+ !mLayerDetached;
}
void BufferStateLayer::pushPendingState() {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index e951ccf..3dfe76c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -143,7 +143,6 @@
sp<Fence> mPreviousReleaseFence;
uint64_t mPreviousBufferId = 0;
- uint64_t mPreviousFrameNumber = 0;
uint64_t mPreviousReleasedFrameNumber = 0;
mutable bool mCurrentStateModified = false;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 079bc66..6a45625 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -780,6 +780,15 @@
ATRACE_CALL();
if (mLayerDetached) {
+ // Ensure BLAST buffer callbacks are processed.
+ // detachChildren and mLayerDetached were implemented to avoid geometry updates
+ // to layers in the cases of animation. For BufferQueue layers buffers are still
+ // consumed as normal. This is useful as otherwise the client could get hung
+ // inevitably waiting on a buffer to return. We recreate this semantic for BufferQueue
+ // even though it is a little consistent. detachChildren is shortly slated for removal
+ // by the hierarchy mirroring work so we don't need to worry about it too much.
+ mDrawingState.callbackHandles = mCurrentState.callbackHandles;
+ mCurrentState.callbackHandles = {};
return flags;
}
@@ -2025,6 +2034,118 @@
// InputWindows per client token yet.
mDrawingState.inputInfo.token = nullptr;
}
+
+void Layer::updateMirrorInfo() {
+ if (mClonedChild == nullptr || !mClonedChild->isClonedFromAlive()) {
+ // If mClonedChild is null, there is nothing to mirror. If isClonedFromAlive returns false,
+ // it means that there is a clone, but the layer it was cloned from has been destroyed. In
+ // that case, we want to delete the reference to the clone since we want it to get
+ // destroyed. The root, this layer, will still be around since the client can continue
+ // to hold a reference, but no cloned layers will be displayed.
+ mClonedChild = nullptr;
+ return;
+ }
+
+ std::map<sp<Layer>, sp<Layer>> clonedLayersMap;
+ // If the real layer exists and is in current state, add the clone as a child of the root.
+ // There's no need to remove from drawingState when the layer is offscreen since currentState is
+ // copied to drawingState for the root layer. So the clonedChild is always removed from
+ // drawingState and then needs to be added back each traversal.
+ if (!mClonedChild->getClonedFrom()->isRemovedFromCurrentState()) {
+ addChildToDrawing(mClonedChild);
+ }
+
+ mClonedChild->updateClonedDrawingState(clonedLayersMap);
+ mClonedChild->updateClonedChildren(this, clonedLayersMap);
+ mClonedChild->updateClonedRelatives(clonedLayersMap);
+}
+
+void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
+ // If the layer the clone was cloned from is alive, copy the content of the drawingState
+ // to the clone. If the real layer is no longer alive, continue traversing the children
+ // since we may be able to pull out other children that are still alive.
+ if (isClonedFromAlive()) {
+ sp<Layer> clonedFrom = getClonedFrom();
+ mDrawingState = clonedFrom->mDrawingState;
+ // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
+ // InputWindows per client token yet.
+ mDrawingState.inputInfo.token = nullptr;
+ clonedLayersMap.emplace(clonedFrom, this);
+ }
+
+ // The clone layer may have children in drawingState since they may have been created and
+ // added from a previous request to updateMirorInfo. This is to ensure we don't recreate clones
+ // that already exist, since we can just re-use them.
+ // The drawingChildren will not get overwritten by the currentChildren since the clones are
+ // not updated in the regular traversal. They are skipped since the root will lose the
+ // reference to them when it copies its currentChildren to drawing.
+ for (sp<Layer>& child : mDrawingChildren) {
+ child->updateClonedDrawingState(clonedLayersMap);
+ }
+}
+
+void Layer::updateClonedChildren(const sp<Layer>& mirrorRoot,
+ std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
+ mDrawingChildren.clear();
+
+ if (!isClonedFromAlive()) {
+ return;
+ }
+
+ sp<Layer> clonedFrom = getClonedFrom();
+ for (sp<Layer>& child : clonedFrom->mDrawingChildren) {
+ if (child == mirrorRoot) {
+ // This is to avoid cyclical mirroring.
+ continue;
+ }
+ sp<Layer> clonedChild = clonedLayersMap[child];
+ if (clonedChild == nullptr) {
+ clonedChild = child->createClone();
+ clonedLayersMap[child] = clonedChild;
+ }
+ addChildToDrawing(clonedChild);
+ clonedChild->updateClonedChildren(mirrorRoot, clonedLayersMap);
+ }
+}
+
+void Layer::updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap) {
+ mDrawingState.zOrderRelativeOf = nullptr;
+ mDrawingState.zOrderRelatives.clear();
+
+ if (!isClonedFromAlive()) {
+ return;
+ }
+
+ sp<Layer> clonedFrom = getClonedFrom();
+ for (wp<Layer>& relativeWeak : clonedFrom->mDrawingState.zOrderRelatives) {
+ sp<Layer> relative = relativeWeak.promote();
+ auto clonedRelative = clonedLayersMap[relative];
+ if (clonedRelative != nullptr) {
+ mDrawingState.zOrderRelatives.add(clonedRelative);
+ }
+ }
+
+ // Check if the relativeLayer for the real layer is part of the cloned hierarchy.
+ // It's possible that the layer it's relative to is outside the requested cloned hierarchy.
+ // In that case, we treat the layer as if the relativeOf has been removed. This way, it will
+ // still traverse the children, but the layer with the missing relativeOf will not be shown
+ // on screen.
+ sp<Layer> relativeOf = clonedFrom->mDrawingState.zOrderRelativeOf.promote();
+ sp<Layer> clonedRelativeOf = clonedLayersMap[relativeOf];
+ if (clonedRelativeOf != nullptr) {
+ mDrawingState.zOrderRelativeOf = clonedRelativeOf;
+ }
+
+ for (sp<Layer>& child : mDrawingChildren) {
+ child->updateClonedRelatives(clonedLayersMap);
+ }
+}
+
+void Layer::addChildToDrawing(const sp<Layer>& layer) {
+ mDrawingChildren.add(layer);
+ layer->mDrawingParent = this;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 610df25..3023cf5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -468,13 +468,30 @@
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
virtual bool needsFiltering(const sp<const DisplayDevice>&) const { return false; }
-protected:
- virtual sp<Layer> createClone() = 0;
- sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
+ // This layer is not a clone, but it's the parent to the cloned hierarchy. The
+ // variable mClonedChild represents the top layer that will be cloned so this
+ // layer will be the parent of mClonedChild.
+ // The layers in the cloned hierarchy will match the lifetime of the real layers. That is
+ // if the real layer is destroyed, then the clone layer will also be destroyed.
+ sp<Layer> mClonedChild;
- bool isClone() { return getClonedFrom() != nullptr; }
+ virtual sp<Layer> createClone() = 0;
+ void updateMirrorInfo();
+ virtual void updateCloneBufferInfo(){};
+
+protected:
+ sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
+ bool isClone() { return mClonedFrom != nullptr; }
+ bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
+
virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+ void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+ void updateClonedChildren(const sp<Layer>& mirrorRoot,
+ std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+ void updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap);
+ void addChildToDrawing(const sp<Layer>& layer);
+
public:
/*
* compositionengine::LayerFE overrides
@@ -838,7 +855,6 @@
// We encode unset as -1.
int32_t mOverrideScalingMode{-1};
std::atomic<uint64_t> mCurrentFrameNumber{0};
- bool mFrameLatencyNeeded{false};
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering{false};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8699747..8b2f5e1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -876,7 +876,16 @@
return BAD_VALUE;
}
- return display->getActiveConfig();
+ if (display->isPrimary()) {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ if (mDesiredActiveConfigChanged) {
+ return mDesiredActiveConfig.configId;
+ } else {
+ return display->getActiveConfig();
+ }
+ } else {
+ return display->getActiveConfig();
+ }
}
void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
@@ -2600,6 +2609,7 @@
});
commitOffscreenLayers();
+ mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateMirrorInfo(); });
}
void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) {
@@ -2718,6 +2728,8 @@
mBootStage = BootStage::BOOTANIMATION;
}
+ mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+
// Only continue with the refresh if there is actually new work to do
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index d6b9b60..f422939 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -19,18 +19,19 @@
srcs: [
"BufferGenerator.cpp",
"Credentials_test.cpp",
- "DereferenceSurfaceControl_test.cpp",
+ "DereferenceSurfaceControl_test.cpp",
"DisplayActiveConfig_test.cpp",
- "InvalidHandles_test.cpp",
+ "InvalidHandles_test.cpp",
"LayerCallback_test.cpp",
- "LayerRenderTypeTransaction_test.cpp",
- "LayerTransaction_test.cpp",
- "LayerTypeAndRenderTypeTransaction_test.cpp",
- "LayerTypeTransaction_test.cpp",
- "LayerUpdate_test.cpp",
- "MultiDisplayLayerBounds_test.cpp",
- "RelativeZ_test.cpp",
- "Stress_test.cpp",
+ "LayerRenderTypeTransaction_test.cpp",
+ "LayerTransaction_test.cpp",
+ "LayerTypeAndRenderTypeTransaction_test.cpp",
+ "LayerTypeTransaction_test.cpp",
+ "LayerUpdate_test.cpp",
+ "MultiDisplayLayerBounds_test.cpp",
+ "RelativeZ_test.cpp",
+ "SetGeometry_test.cpp",
+ "Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
"VirtualDisplay_test.cpp",
],
diff --git a/services/surfaceflinger/tests/SetGeometry_test.cpp b/services/surfaceflinger/tests/SetGeometry_test.cpp
new file mode 100644
index 0000000..dca06ec
--- /dev/null
+++ b/services/surfaceflinger/tests/SetGeometry_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetGeometryTest : public LayerTransactionTest {
+protected:
+ void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mLayer = createLayer("Layer", mLayerWidth, mLayerHeight);
+ fillBufferQueueLayerColor(mLayer, Color::RED, mLayerWidth, mLayerHeight);
+ asTransaction([&](Transaction& t) { t.setLayer(mLayer, INT32_MAX - 1).show(mLayer); });
+
+ {
+ SCOPED_TRACE("init");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(Rect(0, 0, mLayerWidth, mLayerHeight), Color::RED);
+ sc->expectBorder(Rect(0, 0, mLayerWidth, mLayerHeight), Color::BLACK);
+ }
+ }
+
+ void TearDown() {
+ LayerTransactionTest::TearDown();
+ sc = 0;
+ mLayer = 0;
+ }
+
+ std::unique_ptr<ScreenCapture> sc;
+ sp<SurfaceControl> mLayer;
+ const int mLayerWidth = 100;
+ const int mLayerHeight = 200;
+};
+
+TEST_F(SetGeometryTest, SourceAtZeroNoScale) {
+ Rect source = Rect(0, 0, 30, 30);
+ Rect dest = Rect(60, 60, 90, 90);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("geometry applied");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+TEST_F(SetGeometryTest, SourceNotAtZero) {
+ Rect source = Rect(40, 40, 70, 70);
+ Rect dest = Rect(60, 60, 90, 90);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("geometry applied");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+TEST_F(SetGeometryTest, Scale) {
+ Rect source = Rect(0, 0, 100, 200);
+ Rect dest = Rect(0, 0, 200, 400);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("Scaled by 2");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+
+ dest = Rect(0, 0, 50, 100);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+ {
+ SCOPED_TRACE("Scaled by .5");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6b4634a..b196684 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*:SetGeometryTest.*"
}
}