Merge "Use connection token in CommandEntry"
diff --git a/include/android/permission_manager.h b/include/android/permission_manager.h
new file mode 100644
index 0000000..7817126
--- /dev/null
+++ b/include/android/permission_manager.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_PERMISSION_MANAGER_H
+#define ANDROID_PERMISSION_MANAGER_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+/**
+ * Permission check results.
+ *
+ * Introduced in API 31.
+ */
+enum {
+ /**
+ * This is returned by APermissionManager_checkPermission()
+ * if the permission has been granted to the given package.
+ */
+ PERMISSION_MANAGER_PERMISSION_GRANTED = 0,
+ /**
+ * This is returned by APermissionManager_checkPermission()
+ * if the permission has not been granted to the given package.
+ */
+ PERMISSION_MANAGER_PERMISSION_DENIED = -1,
+};
+
+/**
+ * Permission check return status values.
+ *
+ * Introduced in API 31.
+ */
+enum {
+ /**
+ * This is returned if the permission check completed without errors.
+ * The output result is valid and contains one of {PERMISSION_MANAGER_PERMISSION_GRANTED,
+ * PERMISSION_MANAGER_PERMISSION_DENIED}.
+ */
+ PERMISSION_MANAGER_STATUS_OK = 0,
+ /**
+ * This is returned if the permission check encountered an unspecified error.
+ * The output result is unmodified.
+ */
+ PERMISSION_MANAGER_STATUS_ERROR_UNKNOWN = -1,
+ /**
+ * This is returned if the permission check failed because the service is
+ * unavailable. The output result is unmodified.
+ */
+ PERMISSION_MANAGER_STATUS_SERVICE_UNAVAILABLE = -2,
+};
+
+#if __ANDROID_API__ >= 31
+
+/**
+ * Checks whether the package with the given pid/uid has been granted a permission.
+ *
+ * Note that the Java API of Context#checkPermission() is usually faster due to caching,
+ * thus is preferred over this API wherever possible.
+ *
+ * @param permission the permission to be checked.
+ * @param pid the process id of the package to be checked.
+ * @param uid the uid of the package to be checked.
+ * @param outResult output of the permission check result.
+ *
+ * @return error codes if any error happened during the check.
+ */
+int32_t APermissionManager_checkPermission(const char* permission,
+ pid_t pid,
+ uid_t uid,
+ int32_t* outResult) __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
+__END_DECLS
+
+#endif // ANDROID_PERMISSION_MANAGER_H
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index 5e4c98f..727ea60 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -17,6 +17,7 @@
#include <mutex>
#include <unistd.h>
+#include <android/permission_manager.h>
#include <binder/ActivityManager.h>
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
@@ -98,6 +99,18 @@
return PROCESS_STATE_UNKNOWN;
}
+status_t ActivityManager::checkPermission(const String16& permission,
+ const pid_t pid,
+ const uid_t uid,
+ int32_t* outResult) {
+ sp<IActivityManager> service = getService();
+ if (service != nullptr) {
+ return service->checkPermission(permission, pid, uid, outResult);
+ }
+ // ActivityManagerService appears dead. Return usual error code for dead service.
+ return DEAD_OBJECT;
+}
+
status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
sp<IActivityManager> service = getService();
if (service != nullptr) {
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 1eb5363..e9f5aae 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -17,9 +17,11 @@
#include <unistd.h>
#include <fcntl.h>
+#include <android/permission_manager.h>
#include <binder/ActivityManager.h>
#include <binder/IActivityManager.h>
#include <binder/Parcel.h>
+#include <utils/Errors.h>
namespace android {
@@ -104,6 +106,23 @@
}
return reply.readInt32();
}
+
+ virtual status_t checkPermission(const String16& permission,
+ const pid_t pid,
+ const uid_t uid,
+ int32_t* outResult) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+ data.writeString16(permission);
+ data.writeInt32(pid);
+ data.writeInt32(uid);
+ status_t err = remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
+ if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ return err;
+ }
+ *outResult = reply.readInt32();
+ return NO_ERROR;
+ }
};
// ------------------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 9108e31..6796723 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -77,9 +77,9 @@
void unregisterUidObserver(const sp<IUidObserver>& observer);
bool isUidActive(const uid_t uid, const String16& callingPackage);
int getUidProcessState(const uid_t uid, const String16& callingPackage);
+ status_t checkPermission(const String16& permission, const pid_t pid, const uid_t uid, int32_t* outResult);
-
- status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+ status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
private:
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index e0248f6..4573347 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -39,13 +39,18 @@
virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0;
+ virtual status_t checkPermission(const String16& permission,
+ const pid_t pid,
+ const uid_t uid,
+ int32_t* outResult) = 0;
enum {
OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
REGISTER_UID_OBSERVER_TRANSACTION,
UNREGISTER_UID_OBSERVER_TRANSACTION,
IS_UID_ACTIVE_TRANSACTION,
- GET_UID_PROCESS_STATE_TRANSACTION
+ GET_UID_PROCESS_STATE_TRANSACTION,
+ CHECK_PERMISSION_TRANSACTION,
};
};
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 4610ba9..d35debc 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include <android/binder_context.h>
#include <android/binder_ibinder.h>
#include <android/binder_ibinder_platform.h>
+#include <android/binder_libbinder.h>
#include "ibinder_internal.h"
#include <android/binder_stability.h>
diff --git a/libs/binder/ndk/include_platform/android/binder_context.h b/libs/binder/ndk/include_platform/android/binder_context.h
deleted file mode 100644
index a99d555..0000000
--- a/libs/binder/ndk/include_platform/android/binder_context.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/binder_ibinder.h>
-
-__BEGIN_DECLS
-
-/**
- * Makes calls to AIBinder_getCallingSid work if the kernel supports it. This
- * must be called on a local binder server before it is sent out to any othe
- * process. If this is a remote binder, it will abort. If the kernel doesn't
- * support this feature, you'll always get null from AIBinder_getCallingSid.
- *
- * \param binder local server binder to request security contexts on
- */
-__attribute__((weak)) void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid)
- __INTRODUCED_IN(31);
-
-/**
- * Returns the selinux context of the callee.
- *
- * In order for this to work, the following conditions must be met:
- * - The kernel must be new enough to support this feature.
- * - The server must have called AIBinder_setRequestingSid.
- * - The callee must be a remote process.
- *
- * \return security context or null if unavailable. The lifetime of this context
- * is the lifetime of the transaction.
- */
-__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
-
-__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index 2af65cf..a99d555 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -16,39 +16,32 @@
#pragma once
-// binder_context.h used to be part of this header and is included for backwards
-// compatibility.
-#include <android/binder_context.h>
-
-#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
-
#include <android/binder_ibinder.h>
-#include <binder/IBinder.h>
+
+__BEGIN_DECLS
/**
- * Get libbinder version of binder from AIBinder.
+ * Makes calls to AIBinder_getCallingSid work if the kernel supports it. This
+ * must be called on a local binder server before it is sent out to any othe
+ * process. If this is a remote binder, it will abort. If the kernel doesn't
+ * support this feature, you'll always get null from AIBinder_getCallingSid.
*
- * WARNING: function calls to a local object on the other side of this function
- * will parcel. When converting between binders, keep in mind it is not as
- * efficient as a direct function call.
- *
- * \param binder binder with ownership retained by the client
- * \return platform binder object
+ * \param binder local server binder to request security contexts on
*/
-android::sp<android::IBinder> AIBinder_toPlatformBinder(AIBinder* binder);
+__attribute__((weak)) void AIBinder_setRequestingSid(AIBinder* binder, bool requestingSid)
+ __INTRODUCED_IN(31);
/**
- * Get libbinder_ndk version of binder from platform binder.
+ * Returns the selinux context of the callee.
*
- * WARNING: function calls to a local object on the other side of this function
- * will parcel. When converting between binders, keep in mind it is not as
- * efficient as a direct function call.
+ * In order for this to work, the following conditions must be met:
+ * - The kernel must be new enough to support this feature.
+ * - The server must have called AIBinder_setRequestingSid.
+ * - The callee must be a remote process.
*
- * \param binder platform binder which may be from anywhere (doesn't have to be
- * created with libbinder_ndK)
- * \return binder with one reference count of ownership given to the client. See
- * AIBinder_decStrong
+ * \return security context or null if unavailable. The lifetime of this context
+ * is the lifetime of the transaction.
*/
-AIBinder* AIBinder_fromPlatformBinder(const android::sp<android::IBinder>& binder);
+__attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
-#endif
+__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_libbinder.h b/libs/binder/ndk/include_platform/android/binder_libbinder.h
new file mode 100644
index 0000000..f0c00e8
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_libbinder.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
+
+#include <android/binder_ibinder.h>
+#include <binder/IBinder.h>
+
+/**
+ * Get libbinder version of binder from AIBinder.
+ *
+ * WARNING: function calls to a local object on the other side of this function
+ * will parcel. When converting between binders, keep in mind it is not as
+ * efficient as a direct function call.
+ *
+ * \param binder binder with ownership retained by the client
+ * \return platform binder object
+ */
+android::sp<android::IBinder> AIBinder_toPlatformBinder(AIBinder* binder);
+
+/**
+ * Get libbinder_ndk version of binder from platform binder.
+ *
+ * WARNING: function calls to a local object on the other side of this function
+ * will parcel. When converting between binders, keep in mind it is not as
+ * efficient as a direct function call.
+ *
+ * \param binder platform binder which may be from anywhere (doesn't have to be
+ * created with libbinder_ndK)
+ * \return binder with one reference count of ownership given to the client. See
+ * AIBinder_decStrong
+ */
+AIBinder* AIBinder_fromPlatformBinder(const android::sp<android::IBinder>& binder);
+
+#endif
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 160b9f2..f84d9d3 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -18,9 +18,9 @@
#include <aidl/BnBinderNdkUnitTest.h>
#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
-#include <android/binder_context.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_ibinder_platform.h>
+#include <android/binder_libbinder.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <gtest/gtest.h>
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
index 303f4a5..3f20a4f 100644
--- a/libs/binder/rust/sys/BinderBindings.hpp
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <android/binder_context.h>
#include <android/binder_ibinder.h>
+#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
#include <android/binder_parcel.h>
#include <android/binder_process.h>
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 9299721..f3559fa 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -123,6 +123,7 @@
.apply();
mCaptureArgs.displayToken = mDisplayToken;
+ mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB;
}
void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
@@ -181,6 +182,7 @@
for (uint32_t row = 0; row < height; row++) {
for (uint32_t col = 0; col < width; col++) {
uint8_t* pixel = (uint8_t*)(bufData + (row * stride) + col);
+ ASSERT_NE(nullptr, pixel);
bool inRegion;
if (!outsideRegion) {
inRegion = row >= region.top + border && row < region.bottom - border &&
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 483f171..c39b0b5 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -153,6 +153,24 @@
EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
}
+ void expectTapWithFlag(int x, int y, int32_t flags) {
+ InputEvent *ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
+ MotionEvent *mev = static_cast<MotionEvent *>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
+ EXPECT_EQ(x, mev->getX(0));
+ EXPECT_EQ(y, mev->getY(0));
+ EXPECT_EQ(flags, mev->getFlags() & flags);
+
+ ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
+ mev = static_cast<MotionEvent *>(ev);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+ EXPECT_EQ(flags, mev->getFlags() & flags);
+ }
+
~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); }
void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
@@ -602,4 +620,68 @@
surface->expectTap(5, 10);
}
+TEST_F(InputSurfacesTest, touch_flag_obscured) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+
+ // Add non touchable window to fully cover touchable window. Window behind gets touch, but
+ // with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
+ std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
+ nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.ownerUid = 22222;
+ nonTouchableSurface->showAt(100, 100);
+
+ injectTap(190, 199);
+ surface->expectTapWithFlag(90, 99, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED);
+}
+
+TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+
+ // Add non touchable window to cover touchable window, but parent is cropped to not cover area
+ // that will be tapped. Window behind gets touch, but with flag
+ // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
+ nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.ownerUid = 22222;
+ parentSurface->mInputInfo.ownerUid = 22222;
+ nonTouchableSurface->showAt(0, 0);
+ parentSurface->showAt(100, 100);
+
+ nonTouchableSurface->doTransaction([&](auto &t, auto &sc) {
+ t.setCrop_legacy(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
+ t.reparent(sc, parentSurface->mSurfaceControl);
+ });
+
+ injectTap(190, 199);
+ surface->expectTapWithFlag(90, 99, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
+}
+
+TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(100, 100);
+
+ // Add non touchable window to cover touchable window, but parent is cropped to avoid covering
+ // the touchable window. Window behind gets touch with no obscured flags.
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
+ nonTouchableSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ parentSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+ nonTouchableSurface->mInputInfo.ownerUid = 22222;
+ parentSurface->mInputInfo.ownerUid = 22222;
+ nonTouchableSurface->showAt(0, 0);
+ parentSurface->showAt(50, 50);
+
+ nonTouchableSurface->doTransaction([&](auto &t, auto &sc) {
+ t.setCrop_legacy(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
+ t.reparent(sc, parentSurface->mSurfaceControl);
+ });
+
+ injectTap(101, 110);
+ surface->expectTap(1, 10);
+}
+
} // namespace android::test
diff --git a/libs/renderengine/Description.cpp b/libs/renderengine/Description.cpp
index b9cea10..245c9e1 100644
--- a/libs/renderengine/Description.cpp
+++ b/libs/renderengine/Description.cpp
@@ -52,5 +52,10 @@
return colorMatrix != identity;
}
+bool Description::hasDisplayColorMatrix() const {
+ const mat4 identity;
+ return displayColorMatrix != identity;
+}
+
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 13577f7..be83ebc 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1121,6 +1121,7 @@
setOutputDataSpace(display.outputDataspace);
setDisplayMaxLuminance(display.maxLuminance);
+ setDisplayColorTransform(display.colorTransform);
const mat4 projectionMatrix =
ui::Transform(display.orientation).asMatrix4() * mState.projectionMatrix;
@@ -1189,7 +1190,7 @@
position[3] = vec2(bounds.right, bounds.top);
setupLayerCropping(*layer, mesh);
- setColorTransform(display.colorTransform * layer->colorTransform);
+ setColorTransform(layer->colorTransform);
bool usePremultipliedAlpha = true;
bool disableTexture = true;
@@ -1351,6 +1352,10 @@
mState.colorMatrix = colorTransform;
}
+void GLESRenderEngine::setDisplayColorTransform(const mat4& colorTransform) {
+ mState.displayColorMatrix = colorTransform;
+}
+
void GLESRenderEngine::disableTexturing() {
mState.textureEnabled = false;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 1779994..c0449a1 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -168,6 +168,7 @@
void setupLayerTexturing(const Texture& texture);
void setupFillWithColor(float r, float g, float b, float a);
void setColorTransform(const mat4& colorTransform);
+ void setDisplayColorTransform(const mat4& colorTransform);
void disableTexturing();
void disableBlending();
void setupCornerRadiusCropSize(float width, float height);
diff --git a/libs/renderengine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp
index f4fbf35..a172c56 100644
--- a/libs/renderengine/gl/Program.cpp
+++ b/libs/renderengine/gl/Program.cpp
@@ -66,6 +66,7 @@
mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
mSamplerLoc = glGetUniformLocation(programId, "sampler");
mColorLoc = glGetUniformLocation(programId, "color");
+ mDisplayColorMatrixLoc = glGetUniformLocation(programId, "displayColorMatrix");
mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
mMaxMasteringLuminanceLoc = glGetUniformLocation(programId, "maxMasteringLuminance");
mMaxContentLuminanceLoc = glGetUniformLocation(programId, "maxContentLuminance");
@@ -129,6 +130,9 @@
const float color[4] = {desc.color.r, desc.color.g, desc.color.b, desc.color.a};
glUniform4fv(mColorLoc, 1, color);
}
+ if (mDisplayColorMatrixLoc >= 0) {
+ glUniformMatrix4fv(mDisplayColorMatrixLoc, 1, GL_FALSE, desc.displayColorMatrix.asArray());
+ }
if (mInputTransformMatrixLoc >= 0) {
mat4 inputTransformMatrix = desc.inputTransformMatrix;
glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray());
diff --git a/libs/renderengine/gl/Program.h b/libs/renderengine/gl/Program.h
index fc3755e..4292645 100644
--- a/libs/renderengine/gl/Program.h
+++ b/libs/renderengine/gl/Program.h
@@ -104,6 +104,7 @@
/* location of transform matrix */
GLint mInputTransformMatrixLoc;
GLint mOutputTransformMatrixLoc;
+ GLint mDisplayColorMatrixLoc;
/* location of corner radius uniform */
GLint mCornerRadiusLoc;
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 3ae35ec..7fc0499 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -180,6 +180,9 @@
description.hasOutputTransformMatrix() || description.hasColorMatrix()
? Key::OUTPUT_TRANSFORM_MATRIX_ON
: Key::OUTPUT_TRANSFORM_MATRIX_OFF)
+ .set(Key::Key::DISPLAY_COLOR_TRANSFORM_MATRIX_MASK,
+ description.hasDisplayColorMatrix() ? Key::DISPLAY_COLOR_TRANSFORM_MATRIX_ON
+ : Key::DISPLAY_COLOR_TRANSFORM_MATRIX_OFF)
.set(Key::ROUNDED_CORNERS_MASK,
description.cornerRadius > 0 ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF)
.set(Key::SHADOW_MASK, description.drawShadows ? Key::SHADOW_ON : Key::SHADOW_OFF);
@@ -661,7 +664,8 @@
)__SHADER__";
}
- if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
+ if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) ||
+ needs.hasDisplayColorMatrix()) {
if (needs.needsToneMapping()) {
fs << "uniform float displayMaxLuminance;";
fs << "uniform float maxMasteringLuminance;";
@@ -700,6 +704,21 @@
)__SHADER__";
}
+ if (needs.hasDisplayColorMatrix()) {
+ fs << "uniform mat4 displayColorMatrix;";
+ fs << R"__SHADER__(
+ highp vec3 DisplayColorMatrix(const highp vec3 color) {
+ return clamp(vec3(displayColorMatrix * vec4(color, 1.0)), 0.0, 1.0);
+ }
+ )__SHADER__";
+ } else {
+ fs << R"__SHADER__(
+ highp vec3 DisplayColorMatrix(const highp vec3 color) {
+ return color;
+ }
+ )__SHADER__";
+ }
+
generateEOTF(fs, needs);
generateOOTF(fs, needs);
generateOETF(fs, needs);
@@ -732,14 +751,17 @@
}
}
- if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF())) {
+ if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) ||
+ needs.hasDisplayColorMatrix()) {
if (!needs.isOpaque() && needs.isPremultiplied()) {
// un-premultiply if needed before linearization
// avoid divide by 0 by adding 0.5/256 to the alpha channel
fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
}
fs << "gl_FragColor.rgb = "
- "OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));";
+ "DisplayColorMatrix(OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))"
+ ")));";
+
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index 901e631..37bb651 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -117,6 +117,11 @@
SHADOW_MASK = 1 << SHADOW_SHIFT,
SHADOW_OFF = 0 << SHADOW_SHIFT,
SHADOW_ON = 1 << SHADOW_SHIFT,
+
+ DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT = 14,
+ DISPLAY_COLOR_TRANSFORM_MATRIX_MASK = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
+ DISPLAY_COLOR_TRANSFORM_MATRIX_OFF = 0 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
+ DISPLAY_COLOR_TRANSFORM_MATRIX_ON = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT,
};
inline Key() : mKey(0) {}
@@ -143,6 +148,10 @@
inline bool hasOutputTransformMatrix() const {
return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON;
}
+ inline bool hasDisplayColorMatrix() const {
+ return (mKey & DISPLAY_COLOR_TRANSFORM_MATRIX_MASK) ==
+ DISPLAY_COLOR_TRANSFORM_MATRIX_ON;
+ }
inline bool hasTransformMatrix() const {
return hasInputTransformMatrix() || hasOutputTransformMatrix();
}
diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h
index a62161a..fa6ec10 100644
--- a/libs/renderengine/include/renderengine/private/Description.h
+++ b/libs/renderengine/include/renderengine/private/Description.h
@@ -44,6 +44,7 @@
bool hasInputTransformMatrix() const;
bool hasOutputTransformMatrix() const;
bool hasColorMatrix() const;
+ bool hasDisplayColorMatrix() const;
// whether textures are premultiplied
bool isPremultipliedAlpha = false;
@@ -79,6 +80,8 @@
// The color matrix will be applied in linear space right before OETF.
mat4 colorMatrix;
+ // The display color matrix will be applied in gamma space after OETF
+ mat4 displayColorMatrix;
mat4 inputTransformMatrix;
mat4 outputTransformMatrix;
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index d795616..d20fcc4 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -39,7 +39,7 @@
struct RenderEngineTest : public ::testing::Test {
static void SetUpTestSuite() {
- sRE = renderengine::gl::GLESRenderEngine::create(
+ renderengine::RenderEngineCreationArgs reCreationArgs =
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
.setImageCacheSize(1)
@@ -49,13 +49,18 @@
.setSupportsBackgroundBlur(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
.setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
- .build());
+ .build();
+ sRE = renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+
+ reCreationArgs.useColorManagement = true;
+ sRECM = renderengine::gl::GLESRenderEngine::create(reCreationArgs);
}
static void TearDownTestSuite() {
// The ordering here is important - sCurrentBuffer must live longer
// than RenderEngine to avoid a null reference on tear-down.
sRE = nullptr;
+ sRECM = nullptr;
sCurrentBuffer = nullptr;
}
@@ -85,6 +90,9 @@
sRE->deleteTextures(1, &texName);
EXPECT_FALSE(sRE->isTextureNameKnownForTesting(texName));
}
+ for (uint32_t texName : mTexNamesCM) {
+ sRECM->deleteTextures(1, &texName);
+ }
}
void writeBufferToFile(const char* basename) {
@@ -253,10 +261,11 @@
void invokeDraw(renderengine::DisplaySettings settings,
std::vector<const renderengine::LayerSettings*> layers,
- sp<GraphicBuffer> buffer) {
+ sp<GraphicBuffer> buffer, bool useColorManagement = false) {
base::unique_fd fence;
- status_t status =
- sRE->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence);
+ status_t status = useColorManagement
+ ? sRECM->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence)
+ : sRE->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence);
sCurrentBuffer = buffer;
int fd = fence.release();
@@ -267,7 +276,11 @@
ASSERT_EQ(NO_ERROR, status);
if (layers.size() > 0) {
- ASSERT_TRUE(sRE->isFramebufferImageCachedForTesting(buffer->getId()));
+ if (useColorManagement) {
+ ASSERT_TRUE(sRECM->isFramebufferImageCachedForTesting(buffer->getId()));
+ } else {
+ ASSERT_TRUE(sRE->isFramebufferImageCachedForTesting(buffer->getId()));
+ }
}
}
@@ -322,12 +335,15 @@
void fillBufferLayerTransform();
template <typename SourceVariant>
- void fillBufferWithColorTransform();
+ void fillBufferWithColorTransform(bool useColorManagement = false);
template <typename SourceVariant>
void fillBufferColorTransform();
template <typename SourceVariant>
+ void fillBufferColorTransformCM();
+
+ template <typename SourceVariant>
void fillRedBufferWithRoundedCorners();
template <typename SourceVariant>
@@ -366,6 +382,8 @@
// For now, exercise the GL backend directly so that some caching specifics
// can be tested without changing the interface.
static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRE;
+ // renderengine object with Color Management enabled
+ static std::unique_ptr<renderengine::gl::GLESRenderEngine> sRECM;
// Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
// be freed *after* RenderEngine is destroyed, so that the EGL image is
// destroyed first.
@@ -374,14 +392,17 @@
sp<GraphicBuffer> mBuffer;
std::vector<uint32_t> mTexNames;
+ std::vector<uint32_t> mTexNamesCM;
};
std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRE = nullptr;
+std::unique_ptr<renderengine::gl::GLESRenderEngine> RenderEngineTest::sRECM = nullptr;
+
sp<GraphicBuffer> RenderEngineTest::sCurrentBuffer = nullptr;
struct ColorSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
- RenderEngineTest* /*fixture*/) {
+ RenderEngineTest* /*fixture*/, bool /*useColorManagement*/ = false) {
layer.source.solidColor = half3(r, g, b);
}
};
@@ -409,11 +430,16 @@
template <typename OpaquenessVariant>
struct BufferSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
- RenderEngineTest* fixture) {
+ RenderEngineTest* fixture, bool useColorManagement = false) {
sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1);
uint32_t texName;
- fixture->sRE->genTextures(1, &texName);
- fixture->mTexNames.push_back(texName);
+ if (useColorManagement) {
+ fixture->sRECM->genTextures(1, &texName);
+ fixture->mTexNamesCM.push_back(texName);
+ } else {
+ fixture->sRE->genTextures(1, &texName);
+ fixture->mTexNames.push_back(texName);
+ }
uint8_t* pixels;
buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
@@ -643,7 +669,7 @@
}
template <typename SourceVariant>
-void RenderEngineTest::fillBufferWithColorTransform() {
+void RenderEngineTest::fillBufferWithColorTransform(bool useColorManagement) {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
@@ -652,12 +678,12 @@
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
+ SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this, useColorManagement);
layer.alpha = 1.0f;
// construct a fake color matrix
// annihilate green and blue channels
- settings.colorTransform = mat4::scale(vec4(1, 0, 0, 1));
+ settings.colorTransform = mat4::scale(vec4(0.9f, 0, 0, 1));
// set red channel to red + green
layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
@@ -666,13 +692,19 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers, mBuffer, useColorManagement);
}
template <typename SourceVariant>
void RenderEngineTest::fillBufferColorTransform() {
fillBufferWithColorTransform<SourceVariant>();
- expectBufferColor(fullscreenRect(), 191, 0, 0, 255);
+ expectBufferColor(fullscreenRect(), 172, 0, 0, 255, 1);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransformCM() {
+ fillBufferWithColorTransform<SourceVariant>(true);
+ expectBufferColor(fullscreenRect(), 126, 0, 0, 255, 1);
}
template <typename SourceVariant>
@@ -1073,7 +1105,11 @@
}
TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
- fillBufferLayerTransform<ColorSourceVariant>();
+ fillBufferColorTransform<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_colorSource) {
+ fillBufferColorTransformCM<ColorSourceVariant>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
@@ -1129,7 +1165,11 @@
}
TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
- fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+ fillBufferColorTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_opaqueBufferSource) {
+ fillBufferColorTransformCM<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
@@ -1185,7 +1225,11 @@
}
TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
- fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+ fillBufferColorTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransformCM_bufferSource) {
+ fillBufferColorTransformCM<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b60acde..9481966 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2495,12 +2495,6 @@
transformedLayerBounds.bottom = tmp;
}
- // Input coordinates should be in display coordinate space.
- info.frameLeft = transformedLayerBounds.left;
- info.frameTop = transformedLayerBounds.top;
- info.frameRight = transformedLayerBounds.right;
- info.frameBottom = transformedLayerBounds.bottom;
-
// Compute the correct transform to send to input. This will allow it to transform the
// input coordinates from display space into window space. Therefore, it needs to use the
// final layer frame to create the inverse transform. Since surface insets are added later,
@@ -2522,6 +2516,16 @@
inputTransform.set(translation.x, translation.y);
info.transform = inputTransform.inverse();
+ // We need to send the layer bounds cropped to the screenbounds since the layer can be cropped.
+ // The frame should be the area the user sees on screen since it's used for occlusion
+ // detection.
+ Rect screenBounds = Rect{mScreenBounds};
+ transformedLayerBounds.intersect(screenBounds, &transformedLayerBounds);
+ info.frameLeft = transformedLayerBounds.left;
+ info.frameTop = transformedLayerBounds.top;
+ info.frameRight = transformedLayerBounds.right;
+ info.frameBottom = transformedLayerBounds.bottom;
+
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
info.touchableRegion = inputTransform.transform(info.touchableRegion);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 7d97e72..150f925 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -48,7 +48,7 @@
}
}
-std::string RefreshRateConfigs::Policy::toString() {
+std::string RefreshRateConfigs::Policy::toString() const {
return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
defaultConfig.value(), allowGroupSwitching, primaryRange.min,
@@ -433,10 +433,12 @@
// defaultConfig must be a valid config, and within the given refresh rate range.
auto iter = mRefreshRates.find(policy.defaultConfig);
if (iter == mRefreshRates.end()) {
+ ALOGE("Default config is not found.");
return false;
}
const RefreshRate& refreshRate = *iter->second;
if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
+ ALOGE("Default config is not in the primary range.");
return false;
}
return policy.appRequestRange.min <= policy.primaryRange.min &&
@@ -446,6 +448,7 @@
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
std::lock_guard lock(mLock);
if (!isPolicyValid(policy)) {
+ ALOGE("Invalid refresh rate policy: %s", policy.toString().c_str());
return BAD_VALUE;
}
Policy previousPolicy = *getCurrentPolicyLocked();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 5cf7d07..8ff92a0 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -166,7 +166,7 @@
}
bool operator!=(const Policy& other) const { return !(*this == other); }
- std::string toString();
+ std::string toString() const;
};
// Return code set*Policy() to indicate the current policy is unchanged.