summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/dumpstate/dumpstate.cpp15
-rw-r--r--cmds/installd/dexopt.cpp8
-rw-r--r--cmds/installd/run_dex2oat.cpp7
-rw-r--r--include/input/Input.h30
-rw-r--r--include/input/InputDevice.h2
-rw-r--r--libs/binder/TEST_MAPPING3
-rw-r--r--libs/gui/BLASTBufferQueue.cpp21
-rw-r--r--libs/gui/LayerState.cpp4
-rw-r--r--libs/gui/bufferqueue/1.0/Conversion.cpp18
-rw-r--r--libs/gui/include/gui/LayerState.h1
-rw-r--r--libs/gui/tests/BLASTBufferQueue_test.cpp46
-rw-r--r--libs/input/android/os/IInputConstants.aidl15
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.cpp15
-rw-r--r--libs/renderengine/gl/GLESRenderEngine.h2
-rw-r--r--libs/renderengine/include/renderengine/RenderEngine.h2
-rw-r--r--libs/renderengine/include/renderengine/mock/RenderEngine.h2
-rw-r--r--libs/renderengine/skia/Cache.cpp156
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.cpp23
-rw-r--r--libs/renderengine/skia/SkiaGLRenderEngine.h2
-rw-r--r--libs/renderengine/skia/SkiaRenderEngine.h1
-rw-r--r--libs/renderengine/skia/filters/LinearEffect.cpp9
-rw-r--r--libs/renderengine/tests/RenderEngineThreadedTest.cpp26
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.cpp33
-rw-r--r--libs/renderengine/threaded/RenderEngineThreaded.h3
-rw-r--r--libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl4
-rw-r--r--libs/ui/include/ui/Transform.h16
-rw-r--r--services/gpuservice/bpfprogs/gpu_mem.c2
-rw-r--r--services/inputflinger/TEST_MAPPING12
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp29
-rw-r--r--services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp25
-rw-r--r--services/inputflinger/reader/mapper/MultiTouchInputMapper.h1
-rw-r--r--services/inputflinger/reader/mapper/TouchInputMapper.cpp7
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp65
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp67
-rw-r--r--services/surfaceflinger/BufferStateLayer.cpp1
-rw-r--r--services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h4
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp2
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp2
-rw-r--r--services/surfaceflinger/Layer.cpp10
-rw-r--r--services/surfaceflinger/Layer.h2
-rw-r--r--services/surfaceflinger/RegionSamplingThread.cpp27
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp53
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h4
43 files changed, 571 insertions, 206 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 25e6dc95c7..2d11b908c2 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -176,6 +176,7 @@ void add_mountinfo();
#define LINKERCONFIG_DIR "/linkerconfig"
#define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list"
#define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace"
+#define CGROUPFS_DIR "/sys/fs/cgroup"
// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
@@ -1240,8 +1241,15 @@ static Dumpstate::RunStatus RunDumpsysTextByPriority(const std::string& title, i
if (status == OK) {
dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
std::chrono::duration<double> elapsed_seconds;
- status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
- /* as_proto = */ false, elapsed_seconds, bytes_written);
+ if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+ service == String16("meminfo")) {
+ // Use a longer timeout for meminfo, since 30s is not always enough.
+ status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
+ } else {
+ status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
+ }
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
@@ -1785,6 +1793,9 @@ static Dumpstate::RunStatus dumpstate() {
// Add linker configuration directory
ds.AddDir(LINKERCONFIG_DIR, true);
+ /* Dump cgroupfs */
+ ds.AddDir(CGROUPFS_DIR, true);
+
if (ds.dump_pool_) {
WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
} else {
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index af4a525290..871edfc081 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1231,6 +1231,14 @@ class RunDexoptAnalyzer : public ExecVHelper {
}
}
+ // On-device signing related. odsign sets the system property odsign.verification.success if
+ // AOT artifacts have the expected signatures.
+ const bool trust_art_apex_data_files =
+ ::android::base::GetBoolProperty("odsign.verification.success", false);
+ if (!trust_art_apex_data_files) {
+ AddRuntimeArg("-Xdeny-art-apex-data-files");
+ }
+
PrepareArgs(dexoptanalyzer_bin);
}
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index e847626a14..b6616841f0 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -283,6 +283,13 @@ void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex,
}
}
+ // On-device signing related. odsign sets the system property odsign.verification.success if
+ // AOT artifacts have the expected signatures.
+ const bool trust_art_apex_data_files = GetBoolProperty("odsign.verification.success", false);
+ if (!trust_art_apex_data_files) {
+ AddRuntimeArg("-Xdeny-art-apex-data-files");
+ }
+
if (target_sdk_version != 0) {
AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version));
}
diff --git a/include/input/Input.h b/include/input/Input.h
index e8678d27c3..2e326cb102 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -43,6 +43,13 @@
* Additional private constants not defined in ndk/ui/input.h.
*/
enum {
+#ifdef __linux__
+ /* This event was generated or modified by accessibility service. */
+ AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
+ android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+#else
+ AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800,
+#endif
/* Signifies that the key is being predispatched */
AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000,
@@ -81,6 +88,16 @@ enum {
*/
AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40,
+#ifdef __linux__
+ /**
+ * This event was generated or modified by accessibility service.
+ */
+ AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
+ android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+#else
+ AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800,
+#endif
+
/* Motion event is inconsistent with previously sent motion events. */
AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
};
@@ -89,14 +106,15 @@ enum {
* Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified.
* These values must be kept in sync with VerifiedKeyEvent.java
*/
-constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED;
+constexpr int32_t VERIFIED_KEY_EVENT_FLAGS =
+ AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
/**
* Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified.
* These values must be kept in sync with VerifiedMotionEvent.java
*/
-constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
+ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED | AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
/**
* This flag indicates that the point up event has been canceled.
@@ -222,16 +240,14 @@ enum {
POLICY_FLAG_GESTURE = 0x00000008,
POLICY_FLAG_RAW_MASK = 0x0000ffff,
-#ifdef __linux__
- POLICY_FLAG_INPUTFILTER_TRUSTED = android::os::IInputConstants::POLICY_FLAG_INPUTFILTER_TRUSTED,
+#ifdef __linux__
POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY =
android::os::IInputConstants::POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
#else
- POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000,
-
POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000,
#endif
+
/* These flags are set by the input dispatcher. */
// Indicates that the input event was injected.
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 1955104a22..7f0324a4a8 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -318,8 +318,6 @@ extern std::string getInputDeviceConfigurationFilePathByName(
const std::string& name, InputDeviceConfigurationFileType type);
enum ReservedInputDeviceId : int32_t {
- // Device id assigned to input events generated inside accessibility service
- ACCESSIBILITY_DEVICE_ID = -2,
// Device id of a special "virtual" keyboard that is always present.
VIRTUAL_KEYBOARD_ID = -1,
// Device id of the "built-in" keyboard if there is one.
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index b58d919d33..1010a2d79d 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -52,6 +52,9 @@
"name": "CtsOsTestCases",
"options": [
{
+ "exclude-annotation": "android.platform.test.annotations.LargeTest"
+ },
+ {
"exclude-filter": "android.os.cts.BuildTest#testSdkInt"
},
{
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ac8feaa0c2..7d57d8b02c 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -171,6 +171,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceCont
.apply();
mNumAcquired = 0;
mNumFrameAvailable = 0;
+ BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
+ height, format, mTransformHint);
}
BLASTBufferQueue::~BLASTBufferQueue() {
@@ -190,7 +192,6 @@ BLASTBufferQueue::~BLASTBufferQueue() {
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
int32_t format) {
std::unique_lock _lock{mMutex};
- BQA_LOGV("update width=%d height=%d format=%d", width, height, format);
if (mFormat != format) {
mFormat = format;
mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
@@ -212,6 +213,8 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
}
+ BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format,
+ mTransformHint);
ui::Size newSize(width, height);
if (mRequestedSize != newSize) {
@@ -267,6 +270,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
mTransformHint = stat.transformHint;
mBufferItemConsumer->setTransformHint(mTransformHint);
+ BQA_LOGV("updated mTransformHint=%d", mTransformHint);
// Update frametime stamps if the frame was latched and presented, indicated by a
// valid latch time.
if (stat.latchTime > 0) {
@@ -339,6 +343,7 @@ void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
mTransformHint = transformHint;
mSurfaceControl->setTransformHint(transformHint);
mBufferItemConsumer->setTransformHint(mTransformHint);
+ BQA_LOGV("updated mTransformHint=%d", mTransformHint);
}
// Calculate how many buffers we need to hold before we release them back
@@ -422,7 +427,7 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
}
if (rejectBuffer(bufferItem)) {
- BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d"
+ BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d "
"buffer{size=%dx%d transform=%d}",
mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
@@ -515,11 +520,11 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
" applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
- " graphicBufferId=%" PRIu64 "%s",
+ " graphicBufferId=%" PRIu64 "%s transform=%d",
mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction),
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(),
- bufferItem.mAutoRefresh ? " mAutoRefresh" : "");
+ bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform);
}
Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
@@ -646,14 +651,6 @@ public:
status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override {
return mBbq->setFrameTimelineInfo(frameTimelineInfo);
}
- protected:
- uint32_t getTransformHint() const override {
- if (mStickyTransform == 0 && !transformToDisplayInverse()) {
- return mBbq->getLastTransformHint();
- } else {
- return 0;
- }
- }
};
// TODO: Can we coalesce this with frame updates? Need to confirm
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e65c721ae1..2d99fc1903 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -562,6 +562,10 @@ bool layer_state_t::hasBufferChanges() const {
return (what & layer_state_t::eBufferChanged) || (what & layer_state_t::eCachedBufferChanged);
}
+bool layer_state_t::hasValidBuffer() const {
+ return buffer || cachedBuffer.isValid();
+}
+
status_t layer_state_t::matrix22_t::write(Parcel& output) const {
SAFE_PARCEL(output.writeFloat, dsdx);
SAFE_PARCEL(output.writeFloat, dtdx);
diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp
index 3e20a37d54..55462c3b1f 100644
--- a/libs/gui/bufferqueue/1.0/Conversion.cpp
+++ b/libs/gui/bufferqueue/1.0/Conversion.cpp
@@ -1187,14 +1187,15 @@ bool convertTo(::android::Region* l, Region const& t) {
*/
constexpr size_t minFlattenedSize(
HGraphicBufferProducer::QueueBufferInput const& /* t */) {
- return sizeof(int64_t) + // timestamp
- sizeof(int) + // isAutoTimestamp
+ return sizeof(int64_t) + // timestamp
+ sizeof(int) + // isAutoTimestamp
sizeof(android_dataspace) + // dataSpace
- sizeof(::android::Rect) + // crop
- sizeof(int) + // scalingMode
- sizeof(uint32_t) + // transform
- sizeof(uint32_t) + // stickyTransform
- sizeof(bool); // getFrameTimestamps
+ sizeof(::android::Rect) + // crop
+ sizeof(int) + // scalingMode
+ sizeof(uint32_t) + // transform
+ sizeof(uint32_t) + // stickyTransform
+ sizeof(bool) + // getFrameTimestamps
+ sizeof(int); // slot
}
/**
@@ -1267,6 +1268,7 @@ status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
return status;
}
FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
+ FlattenableUtils::write(buffer, size, -1 /*slot*/);
return NO_ERROR;
}
@@ -1319,7 +1321,7 @@ status_t unflatten(
if (status != NO_ERROR) {
return status;
}
- // HdrMetadata ignored
+ // HdrMetadata and slot ignored
return unflatten(&(t->surfaceDamage), buffer, size);
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 8ac1e5d9e9..465e34ca33 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -126,6 +126,7 @@ struct layer_state_t {
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
bool hasBufferChanges() const;
+ bool hasValidBuffer() const;
struct matrix22_t {
float dsdx{0};
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 6ff67aa7cb..9082d275a2 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -71,6 +71,10 @@ public:
return mBlastBufferQueueAdapter->mSurfaceControl;
}
+ sp<Surface> getSurface() {
+ return mBlastBufferQueueAdapter->getSurface(false /* includeSurfaceControlHandle */);
+ }
+
void waitForCallbacks() {
std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
// Wait until all but one of the submitted buffers have been released.
@@ -758,6 +762,48 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
{0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2}));
}
+TEST_F(BLASTBufferQueueTest, TransformHint) {
+ // Transform hint is provided to BBQ via the surface control passed by WM
+ mSurfaceControl->setTransformHint(ui::Transform::ROT_90);
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer = adapter.getIGraphicBufferProducer();
+ ASSERT_NE(nullptr, igbProducer.get());
+ ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
+ sp<Surface> surface = adapter.getSurface();
+
+ // Before connecting to the surface, we do not get a valid transform hint
+ int transformHint;
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_0, transformHint);
+
+ ASSERT_EQ(NO_ERROR,
+ surface->connect(NATIVE_WINDOW_API_CPU, new TestProducerListener(igbProducer)));
+
+ // After connecting to the surface, we should get the correct hint.
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_90, transformHint);
+
+ ANativeWindow_Buffer buffer;
+ surface->lock(&buffer, nullptr /* inOutDirtyBounds */);
+
+ // Transform hint is updated via callbacks or surface control updates
+ mSurfaceControl->setTransformHint(ui::Transform::ROT_0);
+ adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+ // The hint does not change and matches the value used when dequeueing the buffer.
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_90, transformHint);
+
+ surface->unlockAndPost();
+
+ // After queuing the buffer, we get the updated transform hint
+ surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ ASSERT_EQ(ui::Transform::ROT_0, transformHint);
+
+ adapter.waitForCallbacks();
+}
+
class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest {
public:
void test(uint32_t tr) {
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 3038d9daa5..474a1e410d 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -42,16 +42,15 @@ interface IInputConstants
const int INVALID_INPUT_EVENT_ID = 0;
/**
- * The injected event was originally sent from InputDispatcher. Most likely, the journey of the
- * event looked as follows:
- * InputDispatcherPolicyInterface::filterInputEvent -> InputFilter.java::onInputEvent ->
- * InputFilter.java::sendInputEvent -> InputDispatcher::injectInputEvent, without being modified
- * along the way.
+ * The input event was injected from accessibility. Used in policyFlags for input event
+ * injection.
*/
- const int POLICY_FLAG_INPUTFILTER_TRUSTED = 0x10000;
+ const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
/**
- * The input event was injected from accessibility
+ * The input event was generated or modified by accessibility service.
+ * Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either
+ * set of flags, including in input/Input.h and in android/input.h.
*/
- const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
+ const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index b5dd8ac580..467f848237 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1028,20 +1028,17 @@ bool GLESRenderEngine::supportsProtectedContent() const {
return mProtectedEGLContext != EGL_NO_CONTEXT;
}
-bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
- if (useProtectedContext == mInProtectedContext) {
- return true;
- }
- if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) {
- return false;
+void GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
+ if (useProtectedContext == mInProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
}
+
const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface;
const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
- const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
- if (success) {
+ if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
mInProtectedContext = useProtectedContext;
}
- return success;
}
EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
bool isProtected,
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 915dba364f..4cb1b4259b 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -62,7 +62,7 @@ public:
void deleteTextures(size_t count, uint32_t const* names) override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
const std::shared_ptr<ExternalTexture>& buffer,
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ac0affb2ee..5964bc3927 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -127,7 +127,7 @@ public:
virtual bool supportsProtectedContent() const = 0;
// Attempt to switch RenderEngine into and out of protectedContext mode
- virtual bool useProtectedContext(bool useProtectedContext) = 0;
+ virtual void useProtectedContext(bool useProtectedContext) = 0;
// Notify RenderEngine of changes to the dimensions of the primary display
// so that it can configure its internal caches accordingly.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0175af3a85..a4aa9ea488 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -44,7 +44,7 @@ public:
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
- MOCK_METHOD1(useProtectedContext, bool(bool));
+ MOCK_METHOD1(useProtectedContext, void(bool));
MOCK_METHOD0(cleanupPostRender, void());
MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
MOCK_METHOD6(drawLayers,
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 34577daf2c..ae8f2384c4 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -41,6 +41,10 @@ const auto kScaleAsymmetric = mat4(0.8f, 0.f, 0.f, 0.f,
0.f, 1.1f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
0.f, 0.f, 0.f, 1.f);
+const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f,
+ 0.1f, 1.1f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 2.f, 2.f, 0.f, 1.f);
// clang-format on
// When setting layer.sourceDataspace, whether it matches the destination or not determines whether
// a color correction effect is added to the shader.
@@ -52,42 +56,64 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin
const std::shared_ptr<ExternalTexture>& dstTexture) {
// Somewhat arbitrary dimensions, but on screen and slightly shorter, based
// on actual use.
- FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30);
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ FloatRect smallerRect(20, 20, displayRect.width()-20, displayRect.height()-20);
+
LayerSettings layer{
.geometry =
Geometry{
.boundaries = rect,
.roundedCornersCrop = rect,
+ .roundedCornersRadius = 50.f,
},
// drawShadow ignores alpha
.shadow =
ShadowSettings{
+ .boundaries = rect,
.ambientColor = vec4(0, 0, 0, 0.00935997f),
.spotColor = vec4(0, 0, 0, 0.0455841f),
- .lightPos = vec3(370.508f, -1527.03f, 1650.f),
- .lightRadius = 2200.0f,
- .length = 0.955342f,
+ .lightPos = vec3(500.f, -1500.f, 1500.f),
+ .lightRadius = 2500.0f,
+ .length = 15.f,
},
- // important that this matches dest so the general shadow fragment shader doesn't
- // have color correction added, and important that it be srgb, so the *vertex* shader
- // doesn't have color correction added.
- .sourceDataspace = kDestDataSpace,
// setting this is mandatory for shadows and blurs
.skipContentDraw = true,
+ .alpha = 1,
+ };
+ LayerSettings caster{
+ .geometry =
+ Geometry{
+ .boundaries = smallerRect,
+ .roundedCornersCrop = rect,
+ .roundedCornersRadius = 50.f,
+ },
+ .source =
+ PixelSource{
+ .solidColor = half3(0.f, 0.f, 0.f),
+ },
+ .alpha = 1,
};
- auto layers = std::vector<const LayerSettings*>{&layer};
- // The identity matrix will generate the fast shader
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd(),
- nullptr);
- // This matrix, which has different scales for x and y, will
- // generate the slower (more general case) version, which has variants for translucent
- // casters and rounded rects.
- layer.geometry.positionTransform = kScaleAsymmetric;
- for (auto translucent : {false, true}) {
- layer.shadow.casterIsTranslucent = translucent;
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ auto layers = std::vector<const LayerSettings*>{&layer, &caster};
+ // When sourceDataspace matches dest, the general shadow fragment shader doesn't
+ // have color correction added.
+ // independently, when it is not srgb, the *vertex* shader has color correction added.
+ // This may be a bug, but the shader still needs to be cached as it is triggered
+ // during youtube pip.
+ for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
+ layer.sourceDataspace = dataspace;
+ // The 2nd matrix, which has different scales for x and y, will
+ // generate the slower (more general case) shadow shader
+ for (auto transform : {mat4(), kScaleAndTranslate, kFlip}) {
+ layer.geometry.positionTransform = transform;
+ caster.geometry.positionTransform = transform;
+ for (bool translucent : {false, true}){
+ layer.shadow.casterIsTranslucent = translucent;
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+ }
+ }
}
}
@@ -115,6 +141,8 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting
auto layers = std::vector<const LayerSettings*>{&layer};
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
+ // Cache shaders for both rects and round rects.
+ // In reduced shader mode, all non-zero round rect radii get the same code path.
for (float roundedCornersRadius : {0.0f, 50.0f}) {
// roundedCornersCrop is always set, but the radius triggers the behavior
layer.geometry.roundedCornersRadius = roundedCornersRadius;
@@ -217,11 +245,9 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti
layer.source = pixelSource;
for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
layer.sourceDataspace = dataspace;
- // Produce a CircularRRect clip and an EllipticalRRect clip
+ // Produce a CircularRRect clip and an EllipticalRRect clip.
for (auto transform : {kScaleAndTranslate, kScaleAsymmetric}) {
layer.geometry.positionTransform = transform;
- // In real use, I saw alpha of 1.0 and 0.999, probably a mistake, but cache both
- // shaders.
for (float alpha : {0.5f, 1.f}) {
layer.alpha = alpha,
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
@@ -232,6 +258,69 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti
}
}
+static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ const std::shared_ptr<ExternalTexture>& dstTexture,
+ const std::shared_ptr<ExternalTexture>& srcTexture) {
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ // Note that this flip matrix only makes a difference when clipping,
+ // which happens in this layer because the roundrect crop is just a bit
+ // larger than the layer bounds.
+ .positionTransform = kFlip,
+ .boundaries = rect,
+ .roundedCornersRadius = 94.2551,
+ .roundedCornersCrop = FloatRect(
+ -93.75, 0, displayRect.width() + 93.75, displayRect.height()),
+ },
+ .source = PixelSource{.buffer =
+ Buffer{
+ .buffer = srcTexture,
+ .maxLuminanceNits = 1000.f,
+ .isOpaque = 0,
+ .usePremultipliedAlpha = 1,
+ }},
+ .sourceDataspace = kOtherDataSpace,
+ .alpha = 1,
+
+ };
+
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+}
+
+static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ const std::shared_ptr<ExternalTexture>& dstTexture) {
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ FloatRect small(0, 0, displayRect.width()-20, displayRect.height()+20);
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .positionTransform = kScaleAndTranslate,
+ // the boundaries have to be smaller than the rounded crop so that
+ // clipRRect is used instead of drawRRect
+ .boundaries = small,
+ .roundedCornersRadius = 50.f,
+ .roundedCornersCrop = rect,
+ },
+ .source = PixelSource{
+ .solidColor = half3(0.f, 0.f, 0.f),
+ },
+ .sourceDataspace = kDestDataSpace,
+ .alpha = 0,
+ .disableBlending = true,
+
+ };
+
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+}
+
//
// The collection of shaders cached here were found by using perfetto to record shader compiles
// during actions that involve RenderEngine, logging the layer settings, and the shader code
@@ -243,8 +332,6 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti
// kFlushAfterEveryLayer = true
// in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
// gPrintSKSL = true
-//
-// TODO(b/184631553) cache the shader involved in youtube pip return.
void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
const int previousCount = renderengine->reportShadersCompiled();
if (previousCount) {
@@ -264,6 +351,12 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
.maxLuminance = 500,
.outputDataspace = kDestDataSpace,
};
+ DisplaySettings p3Display{
+ .physicalDisplay = displayRect,
+ .clip = displayRect,
+ .maxLuminance = 500,
+ .outputDataspace = kOtherDataSpace,
+ };
const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
@@ -286,9 +379,10 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
std::make_shared<ExternalTexture>(srcBuffer, *renderengine,
ExternalTexture::Usage::READABLE |
ExternalTexture::Usage::WRITEABLE);
-
+ drawHolePunchLayer(renderengine, display, dstTexture);
drawSolidLayers(renderengine, display, dstTexture);
drawShadowLayers(renderengine, display, srcTexture);
+ drawShadowLayers(renderengine, p3Display, srcTexture);
if (renderengine->supportsBackgroundBlur()) {
drawBlurLayers(renderengine, display, dstTexture);
@@ -313,12 +407,20 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
// The majority of shaders are related to sampling images.
// These need to be generated with various source textures
- for (auto texture : {srcTexture, externalTexture, f16ExternalTexture}) {
+ // The F16 texture may not be usable on all devices, so check first that it was created with
+ // the requested usage bit.
+ auto textures = {srcTexture, externalTexture};
+ auto texturesWithF16 = {srcTexture, externalTexture, f16ExternalTexture};
+ bool canUsef16 = f16ExternalBuffer->getUsage() & GRALLOC_USAGE_HW_TEXTURE;
+
+ for (auto texture : canUsef16 ? texturesWithF16 : textures) {
drawImageLayers(renderengine, display, dstTexture, texture);
// Draw layers for b/185569240.
drawClippedLayers(renderengine, display, dstTexture, texture);
}
+ drawPIPImageLayer(renderengine, display, dstTexture, externalTexture);
+
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
const int shadersCompiled = renderengine->reportShadersCompiled();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c7356ea728..3c59f11395 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -320,7 +320,8 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL
options.fReducedShaderVariations = true;
options.fPersistentCache = &mSkSLCacheMonitor;
mGrContext = GrDirectContext::MakeGL(glInterface, options);
- if (useProtectedContext(true)) {
+ if (supportsProtectedContent()) {
+ useProtectedContext(true);
mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options);
useProtectedContext(false);
}
@@ -373,12 +374,10 @@ GrDirectContext* SkiaGLRenderEngine::getActiveGrContext() const {
return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get();
}
-bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
- if (useProtectedContext == mInProtectedContext) {
- return true;
- }
- if (useProtectedContext && !supportsProtectedContent()) {
- return false;
+void SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
+ if (useProtectedContext == mInProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
}
// release any scratch resources before switching into a new mode
@@ -389,9 +388,8 @@ bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
const EGLSurface surface =
useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface;
const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
- const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
- if (success) {
+ if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
mInProtectedContext = useProtectedContext;
// given that we are sharing the same thread between two GrContexts we need to
// make sure that the thread state is reset when switching between the two.
@@ -399,7 +397,6 @@ bool SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
getActiveGrContext()->resetContext();
}
}
- return success;
}
base::unique_fd SkiaGLRenderEngine::flush() {
@@ -1413,10 +1410,12 @@ void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) {
getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
// if it is possible to switch contexts then we will resize the other context
- if (useProtectedContext(!mInProtectedContext)) {
+ const bool originalProtectedState = mInProtectedContext;
+ useProtectedContext(!mInProtectedContext);
+ if (mInProtectedContext != originalProtectedState) {
getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
// reset back to the initial context that was active when this method was called
- useProtectedContext(!mInProtectedContext);
+ useProtectedContext(originalProtectedState);
}
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index b30355bb67..a852bbcaf8 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -64,7 +64,7 @@ public:
int getContextPriority() override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
void assertShadersCompiled(int numShaders) override;
void onPrimaryDisplaySizeChanged(ui::Size size) override;
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 31ad63e9ce..7cd9eca976 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -44,7 +44,6 @@ public:
virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
virtual bool isProtected() const override { return false; } // mInProtectedContext; }
virtual bool supportsProtectedContent() const override { return false; };
- virtual bool useProtectedContext(bool /*useProtectedContext*/) override { return false; };
virtual status_t drawLayers(const DisplaySettings& /*display*/,
const std::vector<const LayerSettings*>& /*layers*/,
const std::shared_ptr<ExternalTexture>& /*buffer*/,
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 9b044e1685..fc45af945b 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -167,13 +167,12 @@ static void generateToneMapInterpolation(ui::Dataspace inputDataspace,
float nits = xyz.y;
- // clamp to max input luminance
- nits = clamp(nits, 0.0, maxInLumi);
-
- // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
+ // if the max input luminance is less than what we can output then
+ // no tone mapping is needed as all color values will be in range.
if (maxInLumi <= maxOutLumi) {
- return xyz * (maxOutLumi / maxInLumi);
+ return xyz;
} else {
+
// three control points
const float x0 = 10.0;
const float y0 = 17.0;
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index c65e731230..830f4630e5 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -118,16 +118,26 @@ TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsTrue) {
ASSERT_EQ(true, result);
}
-TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsFalse) {
- EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(false));
- status_t result = mThreadedRE->useProtectedContext(false);
- ASSERT_EQ(false, result);
+TEST_F(RenderEngineThreadedTest, useProtectedContext) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(true));
+ auto& ipExpect = EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
+ EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderEngine, isProtected()).After(ipExpect).WillOnce(Return(true));
+
+ mThreadedRE->useProtectedContext(true);
+ ASSERT_EQ(true, mThreadedRE->isProtected());
+
+ // call ANY synchronous function to ensure that useProtectedContext has completed.
+ mThreadedRE->getContextPriority();
+ ASSERT_EQ(true, mThreadedRE->isProtected());
}
-TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsTrue) {
- EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
- status_t result = mThreadedRE->useProtectedContext(false);
- ASSERT_EQ(true, result);
+TEST_F(RenderEngineThreadedTest, useProtectedContext_quickReject) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).Times(0);
+ EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
+ mThreadedRE->useProtectedContext(false);
+ // call ANY synchronous function to ensure that useProtectedContext has completed.
+ mThreadedRE->getContextPriority();
}
TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index ea3871f235..b9dabc1d05 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -90,6 +90,7 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S
}
mRenderEngine = factory();
+ mIsProtected = mRenderEngine->isProtected();
pthread_setname_np(pthread_self(), mThreadName);
@@ -248,10 +249,8 @@ size_t RenderEngineThreaded::getMaxViewportDims() const {
bool RenderEngineThreaded::isProtected() const {
waitUntilInitialized();
- // ensure that useProtectedContext is not currently being changed by some
- // other thread.
std::lock_guard lock(mThreadMutex);
- return mRenderEngine->isProtected();
+ return mIsProtected;
}
bool RenderEngineThreaded::supportsProtectedContent() const {
@@ -259,20 +258,28 @@ bool RenderEngineThreaded::supportsProtectedContent() const {
return mRenderEngine->supportsProtectedContent();
}
-bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
- std::promise<bool> resultPromise;
- std::future<bool> resultFuture = resultPromise.get_future();
+void RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
+ if (isProtected() == useProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
+ }
+
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push(
- [&resultPromise, useProtectedContext](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::useProtectedContext");
- bool returnValue = instance.useProtectedContext(useProtectedContext);
- resultPromise.set_value(returnValue);
- });
+ mFunctionCalls.push([useProtectedContext, this](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::useProtectedContext");
+ instance.useProtectedContext(useProtectedContext);
+ if (instance.isProtected() != useProtectedContext) {
+ ALOGE("Failed to switch RenderEngine context.");
+ // reset the cached mIsProtected value to a good state, but this does not
+ // prevent other callers of this method and isProtected from reading the
+ // invalid cached value.
+ mIsProtected = instance.isProtected();
+ }
+ });
+ mIsProtected = useProtectedContext;
}
mCondition.notify_one();
- return resultFuture.get();
}
void RenderEngineThreaded::cleanupPostRender() {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 9b523b2140..f2f5c0f7cd 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -53,7 +53,7 @@ public:
bool isProtected() const override;
bool supportsProtectedContent() const override;
- bool useProtectedContext(bool useProtectedContext) override;
+ void useProtectedContext(bool useProtectedContext) override;
void cleanupPostRender() override;
status_t drawLayers(const DisplaySettings& display,
@@ -100,6 +100,7 @@ private:
* Render Engine
*/
std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ std::atomic<bool> mIsProtected = false;
};
} // namespace threaded
} // namespace renderengine
diff --git a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
index f91f5b9017..9564cba60d 100644
--- a/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
+++ b/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
@@ -36,7 +36,7 @@ interface ISensorPrivacyManager {
void setSensorPrivacy(boolean enable);
- void setIndividualSensorPrivacy(int userId, int sensor, boolean enable);
+ void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
- void setIndividualSensorPrivacyForProfileGroup(int userId, int sensor, boolean enable);
+ void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
}
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index a197b3b20e..33fbe05035 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -112,6 +112,7 @@ public:
void dump(const char* name, const char* prefix = "") const;
static constexpr RotationFlags toRotationFlags(Rotation);
+ static constexpr Rotation toRotation(RotationFlags);
private:
struct mat33 {
@@ -151,5 +152,20 @@ inline constexpr Transform::RotationFlags Transform::toRotationFlags(Rotation ro
}
}
+inline constexpr Rotation Transform::toRotation(Transform::RotationFlags rotationFlags) {
+ switch (rotationFlags) {
+ case ROT_0:
+ return ROTATION_0;
+ case ROT_90:
+ return ROTATION_90;
+ case ROT_180:
+ return ROTATION_180;
+ case ROT_270:
+ return ROTATION_270;
+ default:
+ return ROTATION_0;
+ }
+}
+
} // namespace ui
} // namespace android
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c
index c75213bbd4..16e1e8a1ef 100644
--- a/services/gpuservice/bpfprogs/gpu_mem.c
+++ b/services/gpuservice/bpfprogs/gpu_mem.c
@@ -72,4 +72,4 @@ DEFINE_BPF_PROG("tracepoint/gpu_mem/gpu_mem_total", AID_ROOT, AID_GRAPHICS, tp_g
return 0;
}
-char _license[] SEC("license") = "Apache 2.0";
+LICENSE("Apache 2.0");
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index dc0e60c858..3d85befaf8 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -27,7 +27,17 @@
"name": "CtsViewTestCases",
"options": [
{
- "include-filter": "android.view.cts.MotionEventTest"
+ "include-filter": "android.view.cts.MotionEventTest",
+ "include-filter": "android.view.cts.VerifyInputEventTest"
+ }
+ ]
+ },
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.view.VerifiedKeyEventTest",
+ "include-filter": "android.view.VerifiedMotionEventTest"
}
]
},
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c0010abf8a..1899c5f29d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3787,7 +3787,7 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
- policyFlags |= POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED;
+ policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
@@ -4010,16 +4010,14 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
}
// For all injected events, set device id = VIRTUAL_KEYBOARD_ID. The only exception is events
- // that have gone through the InputFilter. If the event passed through the InputFilter,
- // but did not get modified, assign the provided device id. If the InputFilter modifies the
- // events in any way, it is responsible for removing this flag.
- // If the injected event originated from accessibility, assign the accessibility device id,
- // so that it can be distinguished from regular injected events.
+ // that have gone through the InputFilter. If the event passed through the InputFilter, assign
+ // the provided device id. If the InputFilter is accessibility, and it modifies or synthesizes
+ // the injected event, it is responsible for setting POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY.
+ // For those events, we will set FLAG_IS_ACCESSIBILITY_EVENT to allow apps to distinguish them
+ // from events that originate from actual hardware.
int32_t resolvedDeviceId = VIRTUAL_KEYBOARD_ID;
- if (policyFlags & POLICY_FLAG_INPUTFILTER_TRUSTED) {
+ if (policyFlags & POLICY_FLAG_FILTERED) {
resolvedDeviceId = event->getDeviceId();
- } else if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
- resolvedDeviceId = ACCESSIBILITY_DEVICE_ID;
}
std::queue<std::unique_ptr<EventEntry>> injectedEntries;
@@ -4032,6 +4030,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
}
int32_t flags = incomingKey.getFlags();
+ if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
+ flags |= AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+ }
int32_t keyCode = incomingKey.getKeyCode();
int32_t metaState = incomingKey.getMetaState();
accelerateMetaShortcuts(resolvedDeviceId, action,
@@ -4073,6 +4074,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
size_t pointerCount = motionEvent.getPointerCount();
const PointerProperties* pointerProperties = motionEvent.getPointerProperties();
int32_t actionButton = motionEvent.getActionButton();
+ int32_t flags = motionEvent.getFlags();
int32_t displayId = motionEvent.getDisplayId();
if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
return InputEventInjectionResult::FAILED;
@@ -4088,6 +4090,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
}
}
+ if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
+ flags |= AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+ }
+
mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent.getSamplePointerCoords();
@@ -4095,8 +4101,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
motionEvent.getDisplayId(), policyFlags, action,
- actionButton, motionEvent.getFlags(),
- motionEvent.getMetaState(),
+ actionButton, flags, motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
motionEvent.getEdgeFlags(),
@@ -4116,7 +4121,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
motionEvent.getDisplayId(), policyFlags,
- action, actionButton, motionEvent.getFlags(),
+ action, actionButton, flags,
motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index ca43123d28..fab7f4ca14 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -104,36 +104,37 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
#endif
} else {
Slot* slot = &mSlots[mCurrentSlot];
+ // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
+ // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while
+ // updating the slot.
+ if (!mUsingSlotsProtocol) {
+ slot->mInUse = true;
+ }
switch (rawEvent->code) {
case ABS_MT_POSITION_X:
- slot->mInUse = true;
slot->mAbsMTPositionX = rawEvent->value;
+ warnIfNotInUse(*rawEvent, *slot);
break;
case ABS_MT_POSITION_Y:
- slot->mInUse = true;
slot->mAbsMTPositionY = rawEvent->value;
+ warnIfNotInUse(*rawEvent, *slot);
break;
case ABS_MT_TOUCH_MAJOR:
- slot->mInUse = true;
slot->mAbsMTTouchMajor = rawEvent->value;
break;
case ABS_MT_TOUCH_MINOR:
- slot->mInUse = true;
slot->mAbsMTTouchMinor = rawEvent->value;
slot->mHaveAbsMTTouchMinor = true;
break;
case ABS_MT_WIDTH_MAJOR:
- slot->mInUse = true;
slot->mAbsMTWidthMajor = rawEvent->value;
break;
case ABS_MT_WIDTH_MINOR:
- slot->mInUse = true;
slot->mAbsMTWidthMinor = rawEvent->value;
slot->mHaveAbsMTWidthMinor = true;
break;
case ABS_MT_ORIENTATION:
- slot->mInUse = true;
slot->mAbsMTOrientation = rawEvent->value;
break;
case ABS_MT_TRACKING_ID:
@@ -147,15 +148,12 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) {
}
break;
case ABS_MT_PRESSURE:
- slot->mInUse = true;
slot->mAbsMTPressure = rawEvent->value;
break;
case ABS_MT_DISTANCE:
- slot->mInUse = true;
slot->mAbsMTDistance = rawEvent->value;
break;
case ABS_MT_TOOL_TYPE:
- slot->mInUse = true;
slot->mAbsMTToolType = rawEvent->value;
slot->mHaveAbsMTToolType = true;
break;
@@ -177,6 +175,13 @@ bool MultiTouchMotionAccumulator::hasStylus() const {
return mHaveStylus;
}
+void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) {
+ if (!slot.mInUse) {
+ ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i",
+ event.code, event.value, mCurrentSlot, slot.mAbsMTTrackingId);
+ }
+}
+
// --- MultiTouchMotionAccumulator::Slot ---
MultiTouchMotionAccumulator::Slot::Slot() {
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index ea6f2078d7..225ad49363 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -87,6 +87,7 @@ private:
bool mHaveStylus;
void clearSlots(int32_t initialSlot);
+ void warnIfNotInUse(const RawEvent& event, const Slot& slot);
};
class MultiTouchInputMapper : public TouchInputMapper {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 60502384a3..962d8d2935 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -1471,6 +1471,13 @@ void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {
next.rawPointerData.canceledIdBits.value);
#endif
+ if (!next.rawPointerData.touchingIdBits.isEmpty() &&
+ !next.rawPointerData.hoveringIdBits.isEmpty() &&
+ last.rawPointerData.hoveringIdBits != next.rawPointerData.hoveringIdBits) {
+ ALOGI("Multi-touch contains some hovering ids 0x%08x",
+ next.rawPointerData.hoveringIdBits.value);
+ }
+
processRawTouches(false /*timeout*/);
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 77ca12c5dc..3a9dede89b 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3171,7 +3171,8 @@ protected:
mWindow->consumeFocusEvent(true);
}
- void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId) {
+ void testInjectedKey(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
+ int32_t flags) {
KeyEvent event;
const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -3188,6 +3189,45 @@ protected:
InputEvent* received = mWindow->consume();
ASSERT_NE(nullptr, received);
ASSERT_EQ(resolvedDeviceId, received->getDeviceId());
+ ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_KEY);
+ KeyEvent& keyEvent = static_cast<KeyEvent&>(*received);
+ ASSERT_EQ(flags, keyEvent.getFlags());
+ }
+
+ void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId,
+ int32_t flags) {
+ MotionEvent event;
+ PointerProperties pointerProperties[1];
+ PointerCoords pointerCoords[1];
+ pointerProperties[0].clear();
+ pointerProperties[0].id = 0;
+ pointerCoords[0].clear();
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 300);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 400);
+
+ ui::Transform identityTransform;
+ const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ event.initialize(InputEvent::nextId(), injectedDeviceId, AINPUT_SOURCE_TOUCHSCREEN,
+ DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
+ identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/,
+ 0 /*AMOTION_EVENT_INVALID_DISPLAY_SIZE*/, eventTime, eventTime,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
+
+ const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER;
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
+ InputEventInjectionSync::WAIT_FOR_RESULT, 10ms,
+ policyFlags | additionalPolicyFlags));
+
+ InputEvent* received = mWindow->consume();
+ ASSERT_NE(nullptr, received);
+ ASSERT_EQ(resolvedDeviceId, received->getDeviceId());
+ ASSERT_EQ(received->getType(), AINPUT_EVENT_TYPE_MOTION);
+ MotionEvent& motionEvent = static_cast<MotionEvent&>(*received);
+ ASSERT_EQ(flags, motionEvent.getFlags());
}
private:
@@ -3195,20 +3235,29 @@ private:
};
TEST_F(InputFilterInjectionPolicyTest, TrustedFilteredEvents_KeepOriginalDeviceId) {
- // We don't need POLICY_FLAG_FILTERED here, but it will be set in practice, so keep it to make
- // the test more closely resemble the real usage
- testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INPUTFILTER_TRUSTED, 3 /*injectedDeviceId*/,
- 3 /*resolvedDeviceId*/);
+ // Must have POLICY_FLAG_FILTERED here to indicate that the event has gone through the input
+ // filter. Without it, the event will no different from a regularly injected event, and the
+ // injected device id will be overwritten.
+ testInjectedKey(POLICY_FLAG_FILTERED, 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+ 0 /*flags*/);
}
-TEST_F(InputFilterInjectionPolicyTest, EventsInjectedFromAccessibility_HaveAccessibilityDeviceId) {
+TEST_F(InputFilterInjectionPolicyTest, KeyEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
testInjectedKey(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
- 3 /*injectedDeviceId*/, ACCESSIBILITY_DEVICE_ID /*resolvedDeviceId*/);
+ 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+ AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
+}
+
+TEST_F(InputFilterInjectionPolicyTest,
+ MotionEventsInjectedFromAccessibility_HaveAccessibilityFlag) {
+ testInjectedMotion(POLICY_FLAG_FILTERED | POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY,
+ 3 /*injectedDeviceId*/, 3 /*resolvedDeviceId*/,
+ AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT);
}
TEST_F(InputFilterInjectionPolicyTest, RegularInjectedEvents_ReceiveVirtualDeviceId) {
testInjectedKey(0 /*policyFlags*/, 3 /*injectedDeviceId*/,
- VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/);
+ VIRTUAL_KEYBOARD_ID /*resolvedDeviceId*/, 0 /*flags*/);
}
class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 73198bc5a1..997cbe88a1 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2276,6 +2276,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) {
const Point centerPoint = mDevice->getCenterPoint();
// ACTION_DOWN
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
@@ -2296,6 +2297,8 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) {
const Point centerPoint = mDevice->getCenterPoint();
// ACTION_DOWN
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendTrackingId(FIRST_TRACKING_ID);
mDevice->sendDown(centerPoint);
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
@@ -8217,6 +8220,70 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin
ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags);
}
+/**
+ * Test multi-touch should sent ACTION_POINTER_UP/ACTION_UP when received the INVALID_TRACKING_ID,
+ * to prevent the driver side may send unexpected data after set tracking id as INVALID_TRACKING_ID
+ * cause slot be valid again.
+ */
+TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION | ID | SLOT | PRESSURE);
+ MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+ NotifyMotionArgs motionArgs;
+
+ constexpr int32_t x1 = 100, y1 = 200, x2 = 0, y2 = 0;
+ // First finger down.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1, y1);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // First finger move.
+ processId(mapper, FIRST_TRACKING_ID);
+ processPosition(mapper, x1 + 1, y1 + 1);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+
+ // Second finger down.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, SECOND_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(uint32_t(2), motionArgs.pointerCount);
+
+ // second finger up with some unexpected data.
+ processSlot(mapper, SECOND_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ motionArgs.action);
+ ASSERT_EQ(uint32_t(2), motionArgs.pointerCount);
+
+ // first finger up with some unexpected data.
+ processSlot(mapper, FIRST_SLOT);
+ processId(mapper, INVALID_TRACKING_ID);
+ processPosition(mapper, x2, y2);
+ processPressure(mapper, RAW_PRESSURE_MAX);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action);
+ ASSERT_EQ(uint32_t(1), motionArgs.pointerCount);
+}
+
// --- MultiTouchInputMapperTest_ExternalDevice ---
class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 645e883364..032ff9a572 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -590,6 +590,7 @@ bool BufferStateLayer::setTransactionCompletedListeners(
}
bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
+ mDrawingState.sequence++;
mDrawingState.transparentRegionHint = transparent;
mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 2bf931cb3d..2e7a377feb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -65,7 +65,9 @@ public:
size_t getLayerCount() const { return mLayers.size(); }
const Layer& getFirstLayer() const { return mLayers[0]; }
const Rect& getBounds() const { return mBounds; }
- Rect getTextureBounds() const { return mOutputSpace.content; }
+ Rect getTextureBounds() const {
+ return mTexture ? mTexture->get()->getBuffer()->getBounds() : Rect::INVALID_RECT;
+ }
const Region& getVisibleRegion() const { return mVisibleRegion; }
size_t getAge() const { return mAge; }
std::shared_ptr<renderengine::ExternalTexture> getBuffer() const {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 742b155c9f..ee73cfc0c1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3487,7 +3487,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifDisplayIsNotSecure)
mLayer2.mLayerFEState.hasProtectedContent = true;
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
- EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
+ EXPECT_CALL(mRenderEngine, useProtectedContext(false));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 7f0e186692..b05a594a92 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -355,7 +355,7 @@ TEST_F(CachedSetTest, render) {
expectReadyBuffer(cachedSet);
EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
- EXPECT_EQ(mOutputState.framebufferSpace.content, cachedSet.getTextureBounds());
+ EXPECT_EQ(Rect(kOutputSize.width, kOutputSize.height), cachedSet.getTextureBounds());
// Now check that appending a new cached set properly cleans up RenderEngine resources.
CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ad31b3fcad..00e043289a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -177,6 +177,9 @@ Layer::~Layer() {
if (mDrawingState.sidebandStream != nullptr) {
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
+ if (mHadClonedChild) {
+ mFlinger->mNumClones--;
+ }
}
LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name,
@@ -254,6 +257,7 @@ void Layer::addToCurrentState() {
if (mRemovedFromDrawingState) {
mRemovedFromDrawingState = false;
mFlinger->mScheduler->registerLayer(this);
+ mFlinger->removeFromOffscreenLayers(this);
}
for (const auto& child : mCurrentChildren) {
@@ -2535,6 +2539,12 @@ bool Layer::getPrimaryDisplayOnly() const {
return parent == nullptr ? false : parent->getPrimaryDisplayOnly();
}
+void Layer::setClonedChild(const sp<Layer>& clonedChild) {
+ mClonedChild = clonedChild;
+ mHadClonedChild = true;
+ mFlinger->mNumClones++;
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ec9bb7c27f..e726d379d6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -863,6 +863,8 @@ public:
// 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 mHadClonedChild = false;
+ void setClonedChild(const sp<Layer>& mClonedChild);
mutable bool contentDirty{false};
Region surfaceDamageRegion;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 653aca6cde..aa2fec56ad 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -287,33 +287,12 @@ void RegionSamplingThread::captureSample() {
descriptors.emplace_back(descriptor);
}
- auto dx = 0;
- auto dy = 0;
- switch (orientation) {
- case ui::Transform::ROT_90:
- dx = displaySize.getWidth();
- break;
- case ui::Transform::ROT_180:
- dx = displaySize.getWidth();
- dy = displaySize.getHeight();
- break;
- case ui::Transform::ROT_270:
- dy = displaySize.getHeight();
- break;
- default:
- break;
- }
-
- ui::Transform t(orientation);
- auto screencapRegion = t.transform(sampleRegion);
- screencapRegion = screencapRegion.translate(dx, dy);
-
const Rect sampledBounds = sampleRegion.bounds();
+ constexpr bool kUseIdentityTransform = false;
SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] {
- return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(),
- sampledBounds.getSize(), ui::Dataspace::V0_SRGB,
- orientation);
+ return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
+ ui::Dataspace::V0_SRGB, kUseIdentityTransform);
});
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8df0852a3e..2650fa0583 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -45,6 +45,7 @@
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <configstore/Utils.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
@@ -2309,21 +2310,24 @@ void SurfaceFlinger::postComposition() {
HdrLayerInfoReporter::HdrLayerInfo info;
int32_t maxArea = 0;
mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
- if (layer->isVisible() &&
- compositionDisplay->belongsInOutput(layer->getCompositionEngineLayerFE())) {
+ const auto layerFe = layer->getCompositionEngineLayerFE();
+ if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) {
const Dataspace transfer =
static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
transfer == Dataspace::TRANSFER_HLG);
if (isHdr) {
- info.numberOfHdrLayers++;
- auto bufferRect = layer->getCompositionState()->geomBufferSize;
- int32_t area = bufferRect.width() * bufferRect.height();
- if (area > maxArea) {
- maxArea = area;
- info.maxW = bufferRect.width();
- info.maxH = bufferRect.height();
+ const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe);
+ if (outputLayer) {
+ info.numberOfHdrLayers++;
+ const auto displayFrame = outputLayer->getState().displayFrame;
+ const int32_t area = displayFrame.width() * displayFrame.height();
+ if (area > maxArea) {
+ maxArea = area;
+ info.maxW = displayFrame.width();
+ info.maxH = displayFrame.height();
+ }
}
}
}
@@ -3254,19 +3258,10 @@ void SurfaceFlinger::commitTransactionLocked() {
}
}
- // TODO(b/163019109): See if this traversal is needed at all...
- if (!mOffscreenLayers.empty()) {
- mDrawingState.traverse([&](Layer* layer) {
- // If the layer can be reached when traversing mDrawingState, then the layer is no
- // longer offscreen. Remove the layer from the offscreenLayer set.
- if (mOffscreenLayers.count(layer)) {
- mOffscreenLayers.erase(layer);
- }
- });
- }
-
commitOffscreenLayers();
- mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
+ if (mNumClones > 0) {
+ mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
+ }
}
void SurfaceFlinger::commitOffscreenLayers() {
@@ -3372,7 +3367,9 @@ bool SurfaceFlinger::handlePageFlip() {
mBootStage = BootStage::BOOTANIMATION;
}
- mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ if (mNumClones > 0) {
+ mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ }
// Only continue with the refresh if there is actually new work to do
return !mLayersWithQueuedFrames.empty() && newDataLatched;
@@ -4257,7 +4254,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>
return result;
}
- mirrorLayer->mClonedChild = mirrorFrom->createClone();
+ mirrorLayer->setClonedChild(mirrorFrom->createClone());
}
*outLayerId = mirrorLayer->sequence;
@@ -6623,7 +6620,7 @@ void SurfaceFlinger::onLayerFirstRef(Layer* layer) {
void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
mNumLayers--;
- removeFromOffscreenLayers(layer);
+ removeHierarchyFromOffscreenLayers(layer);
if (!layer->isRemovedFromCurrentState()) {
mScheduler->deregisterLayer(layer);
}
@@ -6636,13 +6633,17 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
// from dangling children layers such that they are not reachable from the
// Drawing state nor the offscreen layer list
// See b/141111965
-void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) {
+void SurfaceFlinger::removeHierarchyFromOffscreenLayers(Layer* layer) {
for (auto& child : layer->getCurrentChildren()) {
mOffscreenLayers.emplace(child.get());
}
mOffscreenLayers.erase(layer);
}
+void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) {
+ mOffscreenLayers.erase(layer);
+}
+
status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ,
float lightRadius) {
@@ -6861,7 +6862,7 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) con
void SurfaceFlinger::TransactionState::traverseStatesWithBuffers(
std::function<void(const layer_state_t&)> visitor) {
for (const auto& state : states) {
- if (state.state.hasBufferChanges() && (state.state.surface)) {
+ if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && state.state.surface) {
visitor(state.state);
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 644f76f65a..b9b26db260 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -313,8 +313,12 @@ public:
void onLayerFirstRef(Layer*);
void onLayerDestroyed(Layer*);
+ void removeHierarchyFromOffscreenLayers(Layer* layer);
void removeFromOffscreenLayers(Layer* layer);
+ // TODO: Remove atomic if move dtor to main thread CL lands
+ std::atomic<uint32_t> mNumClones;
+
TransactionCallbackInvoker& getTransactionCallbackInvoker() {
return mTransactionCallbackInvoker;
}