summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/installd/tests/installd_utils_test.cpp37
-rw-r--r--cmds/installd/utils.cpp24
-rw-r--r--cmds/lshal/ListCommand.cpp2
-rw-r--r--data/etc/go_handheld_core_hardware.xml85
-rw-r--r--data/etc/handheld_core_hardware.xml6
-rw-r--r--libs/binder/Parcel.cpp73
-rw-r--r--libs/binder/include/binder/Parcel.h2
-rw-r--r--libs/vr/libpdx/private/pdx/service.h8
-rw-r--r--libs/vr/libvrflinger/display_manager_service.cpp8
-rw-r--r--opengl/include/GLES2/gl2ext.h11
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp26
-rw-r--r--services/surfaceflinger/DisplayDevice.h27
-rw-r--r--services/surfaceflinger/Layer.cpp15
-rw-r--r--services/surfaceflinger/Layer.h7
-rw-r--r--services/surfaceflinger/LayerStats.cpp21
-rw-r--r--services/surfaceflinger/LayerStats.h6
-rw-r--r--services/surfaceflinger/RenderArea.cpp9
-rw-r--r--services/surfaceflinger/RenderArea.h17
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp347
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h28
-rw-r--r--services/surfaceflinger/tests/Transaction_test.cpp18
-rw-r--r--services/vr/hardware_composer/impl/vr_hwc.cpp28
-rw-r--r--services/vr/hardware_composer/impl/vr_hwc.h2
23 files changed, 593 insertions, 214 deletions
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index bbff6fb0d7..bcdd03efad 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -33,7 +33,7 @@
#define TEST_APP_PRIVATE_DIR "/data/app-private/"
#define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
#define TEST_ASEC_DIR "/mnt/asec/"
-#define TEST_EXPAND_DIR "/mnt/expand/"
+#define TEST_EXPAND_DIR "/mnt/expand/00000000-0000-0000-0000-000000000000/"
#define TEST_SYSTEM_DIR1 "/system/app/"
#define TEST_SYSTEM_DIR2 "/vendor/app/"
@@ -116,6 +116,41 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) {
<< bad_path5 << " should be rejected as a invalid path";
}
+TEST_F(UtilsTest, IsValidApkPath_TopDir) {
+ EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example"));
+ EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_TopFile) {
+ EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example/base.apk"));
+ EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example/base.apk"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example/base.apk"));
+ EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example/base.apk"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDir) {
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDirDir) {
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64"));
+}
+
+TEST_F(UtilsTest, IsValidApkPath_OatDirDirFile) {
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64/base.odex"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64/base.odex"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64/base.odex"));
+ EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64/base.odex"));
+}
+
TEST_F(UtilsTest, IsValidApkPath_Private) {
// Internal directories
const char *private1 = TEST_APP_PRIVATE_DIR "example.apk";
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index a8c32ed2a5..1ff45e4845 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -855,21 +855,25 @@ bool validate_secondary_dex_path(const std::string& pkgname, const std::string&
* that path. Returns -1 when an invalid path is encountered and 0 when a valid path
* is encountered.
*/
-static int validate_apk_path_internal(const char *path, int maxSubdirs) {
- std::string path_ = path;
- if (validate_path(android_app_dir, path_, maxSubdirs) == 0) {
- return 0;
- } else if (validate_path(android_app_private_dir, path_, maxSubdirs) == 0) {
+static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
+ if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
return 0;
- } else if (validate_path(android_app_ephemeral_dir, path_, maxSubdirs) == 0) {
+ } else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) {
return 0;
- } else if (validate_path(android_asec_dir, path_, maxSubdirs) == 0) {
+ } else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) {
return 0;
- } else if (validate_path(android_mnt_expand_dir, path_, std::max(maxSubdirs, 2)) == 0) {
+ } else if (validate_path(android_asec_dir, path, maxSubdirs) == 0) {
return 0;
- } else {
- return -1;
+ } else if (android::base::StartsWith(path, android_mnt_expand_dir)) {
+ // Rewrite the path as if it were on internal storage, and test that
+ size_t end = path.find('/', android_mnt_expand_dir.size() + 1);
+ if (end != std::string::npos) {
+ auto modified = path;
+ modified.replace(0, end + 1, android_data_dir);
+ return validate_apk_path_internal(modified, maxSubdirs);
+ }
}
+ return -1;
}
int validate_apk_path(const char* path) {
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 8e393c0612..ff220484b2 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -503,7 +503,7 @@ Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) {
using namespace ::android::hidl::manager::V1_0;
using namespace ::android::hidl::base::V1_0;
using std::literals::chrono_literals::operator""s;
- auto ret = timeoutIPC(2s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+ auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
std::map<std::string, TableEntry> entries;
for (const auto &info : infos) {
std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
new file mode 100644
index 0000000000..ffebc9f1b3
--- /dev/null
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<!-- These are the hardware components that all Android Go handheld devices
+ must include. Devices with optional hardware must also include extra
+ hardware files, per the comments below.
+-->
+<permissions>
+ <!-- This is Android and fully CTS compatible. Basically this is for CTS tests to use. -->
+ <feature name="android.software.cts" />
+
+ <feature name="android.hardware.audio.output" />
+ <feature name="android.hardware.camera" />
+ <feature name="android.hardware.location" />
+ <feature name="android.hardware.location.network" />
+ <feature name="android.hardware.sensor.compass" />
+ <feature name="android.hardware.sensor.accelerometer" />
+ <feature name="android.hardware.bluetooth" />
+ <feature name="android.hardware.touchscreen" />
+ <feature name="android.hardware.microphone" />
+ <feature name="android.hardware.screen.portrait" />
+ <feature name="android.hardware.screen.landscape" />
+
+ <!-- basic system services -->
+ <feature name="android.software.connectionservice" />
+ <feature name="android.software.backup" />
+ <feature name="android.software.home_screen" />
+ <feature name="android.software.input_methods" />
+ <feature name="android.software.print" />
+ <feature name="android.software.companion_device_setup" />
+ <feature name="android.software.autofill" />
+
+ <!-- Feature to specify if the device supports adding device admins. -->
+ <feature name="android.software.device_admin" />
+
+ <!-- Devices with all optimizations required to support VR Mode and
+ pass all CDD requirements for this feature may include
+ android.hardware.vr.high_performance -->
+ <!-- Devices that support VR headtracking features and pass all CDD
+ requirements may include
+ android.hardware.vr.headtracking -->
+
+ <!-- devices with GPS must include android.hardware.location.gps.xml -->
+ <!-- devices with an autofocus camera and/or flash must include either
+ android.hardware.camera.autofocus.xml or
+ android.hardware.camera.autofocus-flash.xml -->
+ <!-- devices with a front facing camera must include
+ android.hardware.camera.front.xml -->
+ <!-- devices with WiFi must also include android.hardware.wifi.xml -->
+ <!-- devices that support multitouch must include the most appropriate one
+ of these files:
+
+ If only partial (non-independent) pointers are supported:
+ android.hardware.touchscreen.multitouch.xml
+
+ If up to 4 independently tracked pointers are supported:
+ include android.hardware.touchscreen.multitouch.distinct.xml
+
+ If 5 or more independently tracked pointers are supported:
+ include android.hardware.touchscreen.multitouch.jazzhand.xml
+
+ ONLY ONE of the above should be included. -->
+ <!-- devices with an ambient light sensor must also include
+ android.hardware.sensor.light.xml -->
+ <!-- devices with a proximity sensor must also include
+ android.hardware.sensor.proximity.xml -->
+ <!-- GSM phones must also include android.hardware.telephony.gsm.xml -->
+ <!-- CDMA phones must also include android.hardware.telephony.cdma.xml -->
+ <!-- Devices that have low-latency audio stacks suitable for apps like
+ VoIP may include android.hardware.audio.low_latency.xml. ONLY apps
+ that meet the requirements specified in the CDD may include this. -->
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 6d739a11b9..c76e611e42 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -14,9 +14,9 @@
limitations under the License.
-->
-<!-- These are the hardware components that all handheld devices
- must include. Devices with optional hardware must also include extra
- hardware files, per the comments below.
+<!-- These are the hardware components that all handheld devices except Android Go
+ must include, for Android Go devices include go_handheld_core_hardware.xml.
+ Devices with optional hardware must also include extra hardware files, per the comments below.
Handheld devices include phones, mobile Internet devices (MIDs),
Personal Media Players (PMPs), small tablets (7" or less), and similar
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 2d196c1aa3..cb542bf6e5 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -433,6 +433,7 @@ void Parcel::setDataPosition(size_t pos) const
mDataPos = pos;
mNextObjectHint = 0;
+ mObjectsSorted = false;
}
status_t Parcel::setDataCapacity(size_t size)
@@ -1469,6 +1470,59 @@ void Parcel::remove(size_t /*start*/, size_t /*amt*/)
LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
}
+status_t Parcel::validateReadData(size_t upperBound) const
+{
+ // Don't allow non-object reads on object data
+ if (mObjectsSorted || mObjectsSize <= 1) {
+data_sorted:
+ // Expect to check only against the next object
+ if (mNextObjectHint < mObjectsSize && upperBound > mObjects[mNextObjectHint]) {
+ // For some reason the current read position is greater than the next object
+ // hint. Iterate until we find the right object
+ size_t nextObject = mNextObjectHint;
+ do {
+ if (mDataPos < mObjects[nextObject] + sizeof(flat_binder_object)) {
+ // Requested info overlaps with an object
+ ALOGE("Attempt to read from protected data in Parcel %p", this);
+ return PERMISSION_DENIED;
+ }
+ nextObject++;
+ } while (nextObject < mObjectsSize && upperBound > mObjects[nextObject]);
+ mNextObjectHint = nextObject;
+ }
+ return NO_ERROR;
+ }
+ // Quickly determine if mObjects is sorted.
+ binder_size_t* currObj = mObjects + mObjectsSize - 1;
+ binder_size_t* prevObj = currObj;
+ while (currObj > mObjects) {
+ prevObj--;
+ if(*prevObj > *currObj) {
+ goto data_unsorted;
+ }
+ currObj--;
+ }
+ mObjectsSorted = true;
+ goto data_sorted;
+
+data_unsorted:
+ // Insertion Sort mObjects
+ // Great for mostly sorted lists. If randomly sorted or reverse ordered mObjects become common,
+ // switch to std::sort(mObjects, mObjects + mObjectsSize);
+ for (binder_size_t* iter0 = mObjects + 1; iter0 < mObjects + mObjectsSize; iter0++) {
+ binder_size_t temp = *iter0;
+ binder_size_t* iter1 = iter0 - 1;
+ while (iter1 >= mObjects && *iter1 > temp) {
+ *(iter1 + 1) = *iter1;
+ iter1--;
+ }
+ *(iter1 + 1) = temp;
+ }
+ mNextObjectHint = 0;
+ mObjectsSorted = true;
+ goto data_sorted;
+}
+
status_t Parcel::read(void* outData, size_t len) const
{
if (len > INT32_MAX) {
@@ -1479,6 +1533,10 @@ status_t Parcel::read(void* outData, size_t len) const
if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
&& len <= pad_size(len)) {
+ if (mObjectsSize > 0) {
+ status_t err = validateReadData(mDataPos + pad_size(len));
+ if(err != NO_ERROR) return err;
+ }
memcpy(outData, mData+mDataPos, len);
mDataPos += pad_size(len);
ALOGV("read Setting data pos of %p to %zu", this, mDataPos);
@@ -1497,6 +1555,11 @@ const void* Parcel::readInplace(size_t len) const
if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize
&& len <= pad_size(len)) {
+ if (mObjectsSize > 0) {
+ status_t err = validateReadData(mDataPos + pad_size(len));
+ if(err != NO_ERROR) return NULL;
+ }
+
const void* data = mData+mDataPos;
mDataPos += pad_size(len);
ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos);
@@ -1510,6 +1573,11 @@ status_t Parcel::readAligned(T *pArg) const {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T));
if ((mDataPos+sizeof(T)) <= mDataSize) {
+ if (mObjectsSize > 0) {
+ status_t err = validateReadData(mDataPos + sizeof(T));
+ if(err != NO_ERROR) return err;
+ }
+
const void* data = mData+mDataPos;
mDataPos += sizeof(T);
*pArg = *reinterpret_cast<const T*>(data);
@@ -2366,6 +2434,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,
mObjects = const_cast<binder_size_t*>(objects);
mObjectsSize = mObjectsCapacity = objectsCount;
mNextObjectHint = 0;
+ mObjectsSorted = false;
mOwner = relFunc;
mOwnerCookie = relCookie;
for (size_t i = 0; i < mObjectsSize; i++) {
@@ -2524,6 +2593,7 @@ status_t Parcel::restartWrite(size_t desired)
mObjects = NULL;
mObjectsSize = mObjectsCapacity = 0;
mNextObjectHint = 0;
+ mObjectsSorted = false;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
@@ -2610,6 +2680,7 @@ status_t Parcel::continueWrite(size_t desired)
mDataCapacity = desired;
mObjectsSize = mObjectsCapacity = objectsSize;
mNextObjectHint = 0;
+ mObjectsSorted = false;
} else if (mData) {
if (objectsSize < mObjectsSize) {
@@ -2631,6 +2702,7 @@ status_t Parcel::continueWrite(size_t desired)
}
mObjectsSize = objectsSize;
mNextObjectHint = 0;
+ mObjectsSorted = false;
}
// We own the data, so we can just do a realloc().
@@ -2703,6 +2775,7 @@ void Parcel::initState()
mObjectsSize = 0;
mObjectsCapacity = 0;
mNextObjectHint = 0;
+ mObjectsSorted = false;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5d36526cb3..dede78f61e 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -417,6 +417,7 @@ private:
void freeDataNoInit();
void initState();
void scanForFds() const;
+ status_t validateReadData(size_t len) const;
template<class T>
status_t readAligned(T *pArg) const;
@@ -463,6 +464,7 @@ private:
size_t mObjectsSize;
size_t mObjectsCapacity;
mutable size_t mNextObjectHint;
+ mutable bool mObjectsSorted;
mutable bool mFdsKnown;
mutable bool mHasFds;
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 0d30614562..13aa3e90d7 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -589,6 +589,14 @@ class Service : public std::enable_shared_from_this<Service> {
}
/*
+ * Return true if a channel with the given ID exists in the Channel map.
+ */
+ bool HasChannelId(int channel_id) const {
+ std::lock_guard<std::mutex> autolock(channels_mutex_);
+ return channels_.find(channel_id) != channels_.end();
+ }
+
+ /*
* Subclasses of Service may override this method to provide a text string
* describing the state of the service. This method is called by
* HandleSystemMessage in response to the standard
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index ef8cca38dd..34b3b0a6f4 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -45,6 +45,14 @@ std::shared_ptr<pdx::Channel> DisplayManagerService::OnChannelOpen(
const int user_id = message.GetEffectiveUserId();
const bool trusted = user_id == AID_ROOT || IsTrustedUid(user_id);
+ // Check if the display_manager_ has a defunct channel.
+ if (display_manager_ && !HasChannelId(display_manager_->channel_id())) {
+ ALOGE("DisplayManagerService::OnChannelOpen: Found defunct channel %d with "
+ "no OnChannelClose, clearing prior display manager.",
+ display_manager_->channel_id());
+ display_manager_ = nullptr;
+ }
+
// Prevent more than one display manager from registering at a time or
// untrusted UIDs from connecting.
if (display_manager_ || !trusted) {
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index 3ad39d967b..e8d7515944 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -3612,17 +3612,6 @@ GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
#define GL_SHADER_BINARY_VIV 0x8FC4
#endif /* GL_VIV_shader_binary */
-/* Temporary hack to allow frameworks/base/libs/hwui/debug to build.
- * This function was removed from the Khronos version of the headers
- * (it is specified with the EXT prefix, not OES). */
-#ifndef GL_ANDROID_draw_elements_base_vertex_backwards_compatibility
-#define GL_ANDROID_draw_elements_base_vertex_backwards_compatibility 1
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexOES (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
-#endif
-#endif /* GL_ANDROID_draw_elements_base_vertex_backwards_compatibility */
-
#ifdef __cplusplus
}
#endif
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 58a774b7e2..d90ab1dfed 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -55,6 +55,7 @@ namespace android {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
using android::ui::ColorMode;
+using android::ui::RenderIntent;
/*
* Initialize the display to the specified values.
@@ -75,8 +76,8 @@ DisplayDevice::DisplayDevice(
std::unique_ptr<RE::Surface> renderSurface,
int displayWidth,
int displayHeight,
- bool supportWideColor,
- bool supportHdr,
+ bool hasWideColorGamut,
+ bool hasHdr10,
int initialPowerMode)
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
@@ -98,8 +99,8 @@ DisplayDevice::DisplayDevice(
mActiveConfig(0),
mActiveColorMode(ColorMode::NATIVE),
mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
- mDisplayHasWideColor(supportWideColor),
- mDisplayHasHdr(supportHdr)
+ mHasWideColorGamut(hasWideColorGamut),
+ mHasHdr10(hasHdr10)
{
// clang-format on
@@ -268,6 +269,14 @@ ColorMode DisplayDevice::getActiveColorMode() const {
return mActiveColorMode;
}
+RenderIntent DisplayDevice::getActiveRenderIntent() const {
+ return mActiveRenderIntent;
+}
+
+void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
+ mActiveRenderIntent = renderIntent;
+}
+
void DisplayDevice::setColorTransform(const mat4& transform) {
const bool isIdentity = (transform == mat4());
mColorTransform =
@@ -279,10 +288,15 @@ android_color_transform_t DisplayDevice::getColorTransform() const {
}
void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
+ mCompositionDataSpace = dataspace;
ANativeWindow* const window = mNativeWindow.get();
native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
}
+ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
+ return mCompositionDataSpace;
+}
+
// ----------------------------------------------------------------------------
void DisplayDevice::setLayerStack(uint32_t stack) {
@@ -464,8 +478,8 @@ void DisplayDevice::dump(String8& result) const {
tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
auto const surface = static_cast<Surface*>(window);
ui::Dataspace dataspace = surface->getBuffersDataSpace();
- result.appendFormat(" wideColor=%d, hdr=%d, colorMode=%s, dataspace: %s (%d)\n",
- mDisplayHasWideColor, mDisplayHasHdr,
+ result.appendFormat(" wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
+ mHasWideColorGamut, mHasHdr10,
decodeColorMode(mActiveColorMode).c_str(),
dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e844d115c2..b8a890679e 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -84,8 +84,8 @@ public:
std::unique_ptr<RE::Surface> renderSurface,
int displayWidth,
int displayHeight,
- bool supportWideColor,
- bool supportHdr,
+ bool hasWideColorGamut,
+ bool hasHdr10,
int initialPowerMode);
// clang-format on
@@ -135,8 +135,8 @@ public:
// machine happy without actually queueing a buffer if nothing has changed
status_t beginFrame(bool mustRecompose) const;
status_t prepareFrame(HWComposer& hwc);
- bool getWideColorSupport() const { return mDisplayHasWideColor; }
- bool getHdrSupport() const { return mDisplayHasHdr; }
+ bool hasWideColorGamut() const { return mHasWideColorGamut; }
+ bool hasHdr10() const { return mHasHdr10; }
void swapBuffers(HWComposer& hwc) const;
@@ -165,9 +165,12 @@ public:
ui::ColorMode getActiveColorMode() const;
void setActiveColorMode(ui::ColorMode mode);
+ ui::RenderIntent getActiveRenderIntent() const;
+ void setActiveRenderIntent(ui::RenderIntent renderIntent);
android_color_transform_t getColorTransform() const;
void setColorTransform(const mat4& transform);
void setCompositionDataSpace(ui::Dataspace dataspace);
+ ui::Dataspace getCompositionDataSpace() const;
/* ------------------------------------------------------------------------
* Display active config management.
@@ -241,14 +244,17 @@ private:
int mActiveConfig;
// current active color mode
ui::ColorMode mActiveColorMode;
+ // Current active render intent.
+ ui::RenderIntent mActiveRenderIntent;
+ ui::Dataspace mCompositionDataSpace;
// Current color transform
android_color_transform_t mColorTransform;
// Need to know if display is wide-color capable or not.
// Initialized by SurfaceFlinger when the DisplayDevice is created.
// Fed to RenderEngine during composition.
- bool mDisplayHasWideColor;
- bool mDisplayHasHdr;
+ bool mHasWideColorGamut;
+ bool mHasHdr10;
};
struct DisplayDeviceState {
@@ -281,7 +287,8 @@ public:
rotation) {}
DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqHeight,
uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
- : RenderArea(reqHeight, reqWidth, rotation), mDevice(device), mSourceCrop(sourceCrop) {}
+ : RenderArea(reqHeight, reqWidth, CaptureFill::OPAQUE, rotation), mDevice(device),
+ mSourceCrop(sourceCrop) {}
const Transform& getTransform() const override { return mDevice->getTransform(); }
Rect getBounds() const override { return mDevice->getBounds(); }
@@ -290,9 +297,9 @@ public:
bool isSecure() const override { return mDevice->isSecure(); }
bool needsFiltering() const override { return mDevice->needsFiltering(); }
Rect getSourceCrop() const override { return mSourceCrop; }
- bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); }
- ui::ColorMode getActiveColorMode() const override {
- return mDevice->getActiveColorMode();
+ bool getWideColorSupport() const override { return mDevice->hasWideColorGamut(); }
+ ui::Dataspace getDataSpace() const override {
+ return mDevice->getCompositionDataSpace();
}
private:
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9d356d86c7..8c0050ee47 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1643,6 +1643,21 @@ bool Layer::detachChildren() {
return true;
}
+// Dataspace::UNKNOWN, Dataspace::SRGB, Dataspace::SRGB_LINEAR,
+// Dataspace::V0_SRGB and Dataspace::V0_SRGB_LINEAR are considered legacy
+// SRGB data space for now.
+// Note that Dataspace::V0_SRGB and Dataspace::V0_SRGB_LINEAR are not legacy
+// data space, however since framework doesn't distinguish them out of legacy
+// SRGB, we have to treat them as the same for now.
+bool Layer::isLegacySrgbDataSpace() const {
+ // TODO(lpy) b/77652630, need to figure out when UNKNOWN can be treated as SRGB.
+ return mDrawingState.dataSpace == ui::Dataspace::UNKNOWN ||
+ mDrawingState.dataSpace == ui::Dataspace::SRGB ||
+ mDrawingState.dataSpace == ui::Dataspace::SRGB_LINEAR ||
+ mDrawingState.dataSpace == ui::Dataspace::V0_SRGB ||
+ mDrawingState.dataSpace == ui::Dataspace::V0_SRGB_LINEAR;
+}
+
void Layer::setParent(const sp<Layer>& layer) {
mCurrentParent = layer;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8d2a0488dc..d382a1a173 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -297,6 +297,13 @@ public:
bool reparent(const sp<IBinder>& newParentHandle);
bool detachChildren();
+ // Before color management is introduced, contents on Android have to be
+ // desaturated in order to match what they appears like visually.
+ // With color management, these contents will appear desaturated, thus
+ // needed to be saturated so that they match what they are designed for
+ // visually. When returns true, legacy SRGB data space is passed to HWC.
+ bool isLegacySrgbDataSpace() const;
+
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
index 38ea6edfc5..04ab121560 100644
--- a/services/surfaceflinger/LayerStats.cpp
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -57,11 +57,12 @@ bool LayerStats::isEnabled() {
}
void LayerStats::traverseLayerTreeStatsLocked(
- std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
- const LayerProtoParser::LayerGlobal* layerGlobal, std::vector<std::string>& layerShapeVec) {
- for (std::unique_ptr<LayerProtoParser::Layer>& layer : layerTree) {
+ const std::vector<std::unique_ptr<LayerProtoParser::Layer>>& layerTree,
+ const LayerProtoParser::LayerGlobal& layerGlobal,
+ std::vector<std::string>* const outLayerShapeVec) {
+ for (const auto& layer : layerTree) {
if (!layer) continue;
- traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal, layerShapeVec);
+ traverseLayerTreeStatsLocked(layer->children, layerGlobal, outLayerShapeVec);
std::string key = "";
base::StringAppendF(&key, ",%s", layer->type.c_str());
base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
@@ -70,21 +71,21 @@ void LayerStats::traverseLayerTreeStatsLocked(
base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
base::StringAppendF(&key, ",%s",
- destinationLocation(layer->hwcFrame.left, layerGlobal->resolution[0],
+ destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0],
true));
base::StringAppendF(&key, ",%s",
- destinationLocation(layer->hwcFrame.top, layerGlobal->resolution[1],
+ destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1],
false));
base::StringAppendF(&key, ",%s",
destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
- layerGlobal->resolution[0], true));
+ layerGlobal.resolution[0], true));
base::StringAppendF(&key, ",%s",
destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
- layerGlobal->resolution[1], false));
+ layerGlobal.resolution[1], false));
base::StringAppendF(&key, ",%s", scaleRatioWH(layer.get()).c_str());
base::StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
- layerShapeVec.push_back(key);
+ outLayerShapeVec->push_back(key);
ALOGV("%s", key.c_str());
}
}
@@ -97,7 +98,7 @@ void LayerStats::logLayerStats(const LayersProto& layersProto) {
std::vector<std::string> layerShapeVec;
std::lock_guard<std::mutex> lock(mMutex);
- traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal, layerShapeVec);
+ traverseLayerTreeStatsLocked(layerTree, layerGlobal, &layerShapeVec);
std::string layerShapeKey =
base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
index 7871fc6602..7a190fdb41 100644
--- a/services/surfaceflinger/LayerStats.h
+++ b/services/surfaceflinger/LayerStats.h
@@ -38,9 +38,9 @@ public:
private:
// Traverse layer tree to get all visible layers' stats
void traverseLayerTreeStatsLocked(
- std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
- const LayerProtoParser::LayerGlobal* layerGlobal,
- std::vector<std::string>& layerShapeVec);
+ const std::vector<std::unique_ptr<LayerProtoParser::Layer>>& layerTree,
+ const LayerProtoParser::LayerGlobal& layerGlobal,
+ std::vector<std::string>* const outLayerShapeVec);
// Convert layer's top-left position into 8x8 percentage of the display
static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
// Convert layer's size into 8x8 percentage of the display
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
index 6225df134d..46ec8e68ba 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -2,6 +2,15 @@
namespace android {
+float RenderArea::getCaptureFillValue(CaptureFill captureFill) {
+ switch(captureFill) {
+ case CaptureFill::CLEAR:
+ return 0.0f;
+ case CaptureFill::OPAQUE:
+ default:
+ return 1.0f;
+ }
+}
/*
* Checks that the requested width and height are valid and updates them to the render area
* dimensions if they are set to 0
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index bf0707f13b..36306773f7 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -9,10 +9,15 @@
namespace android {
class RenderArea {
+
public:
- RenderArea(uint32_t reqHeight, uint32_t reqWidth,
+ enum class CaptureFill {CLEAR, OPAQUE};
+
+ static float getCaptureFillValue(CaptureFill captureFill);
+
+ RenderArea(uint32_t reqHeight, uint32_t reqWidth, CaptureFill captureFill,
ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
- : mReqHeight(reqHeight), mReqWidth(reqWidth) {
+ : mReqHeight(reqHeight), mReqWidth(reqWidth), mCaptureFill(captureFill) {
mRotationFlags = Transform::fromRotation(rotation);
}
@@ -25,21 +30,23 @@ public:
virtual bool isSecure() const = 0;
virtual bool needsFiltering() const = 0;
virtual Rect getSourceCrop() const = 0;
+ virtual bool getWideColorSupport() const = 0;
+ virtual ui::Dataspace getDataSpace() const = 0;
virtual void render(std::function<void()> drawLayers) { drawLayers(); }
int getReqHeight() const { return mReqHeight; };
int getReqWidth() const { return mReqWidth; };
Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
- virtual bool getWideColorSupport() const = 0;
- virtual ui::ColorMode getActiveColorMode() const = 0;
-
status_t updateDimensions();
+ CaptureFill getCaptureFill() const { return mCaptureFill; };
+
private:
uint32_t mReqHeight;
uint32_t mReqWidth;
Transform::orientation_flags mRotationFlags;
+ CaptureFill mCaptureFill;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 982107b4d8..57f729bf0b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -157,6 +157,31 @@ bool useTrebleTestingOverride() {
return std::string(value) == "true";
}
+DisplayColorSetting toDisplayColorSetting(int value) {
+ switch(value) {
+ case 0:
+ return DisplayColorSetting::MANAGED;
+ case 1:
+ return DisplayColorSetting::UNMANAGED;
+ case 2:
+ return DisplayColorSetting::ENHANCED;
+ default:
+ return DisplayColorSetting::MANAGED;
+ }
+}
+
+std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
+ switch(displayColorSetting) {
+ case DisplayColorSetting::MANAGED:
+ return std::string("Natural Mode");
+ case DisplayColorSetting::UNMANAGED:
+ return std::string("Saturated Mode");
+ case DisplayColorSetting::ENHANCED:
+ return std::string("Auto Color Mode");
+ }
+ return std::string("Unknown Display Color Setting");
+}
+
NativeWindowSurface::~NativeWindowSurface() = default;
namespace impl {
@@ -690,6 +715,9 @@ void SurfaceFlinger::init() {
ALOGE("Run StartPropertySetThread failed!");
}
+ mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+ Dataspace::SRGB_LINEAR);
+
ALOGV("Done initializing");
}
@@ -697,14 +725,13 @@ void SurfaceFlinger::readPersistentProperties() {
char value[PROPERTY_VALUE_MAX];
property_get("persist.sys.sf.color_saturation", value, "1.0");
- mSaturation = atof(value);
- ALOGV("Saturation is set to %.2f", mSaturation);
+ mGlobalSaturationFactor = atof(value);
+ ALOGV("Saturation is set to %.2f", mGlobalSaturationFactor);
property_get("persist.sys.sf.native_mode", value, "0");
- mForceNativeColorMode = atoi(value) == 1;
- if (mForceNativeColorMode) {
- ALOGV("Forcing native color mode");
- }
+ mDisplayColorSetting = toDisplayColorSetting(atoi(value));
+ ALOGV("Display Color Setting is set to %s.",
+ decodeDisplayColorSetting(mDisplayColorSetting).c_str());
}
void SurfaceFlinger::startBootAnim() {
@@ -989,11 +1016,29 @@ ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
}
void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
- ColorMode mode) {
+ ColorMode mode, Dataspace dataSpace) {
int32_t type = hw->getDisplayType();
ColorMode currentMode = hw->getActiveColorMode();
-
- if (mode == currentMode) {
+ Dataspace currentDataSpace = hw->getCompositionDataSpace();
+ RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
+
+ // Natural Mode means it's color managed and the color must be right,
+ // thus we pick RenderIntent::COLORIMETRIC as render intent.
+ // Native Mode means the display is not color managed, and whichever
+ // render intent is picked doesn't matter, thus return
+ // RenderIntent::COLORIMETRIC as default here.
+ RenderIntent renderIntent = RenderIntent::COLORIMETRIC;
+
+ // In Auto Color Mode, we want to strech to panel color space, right now
+ // only the built-in display supports it.
+ if (mDisplayColorSetting == DisplayColorSetting::ENHANCED &&
+ mBuiltinDisplaySupportsEnhance &&
+ hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) {
+ renderIntent = RenderIntent::ENHANCE;
+ }
+
+ if (mode == currentMode && dataSpace == currentDataSpace &&
+ renderIntent == currentRenderIntent) {
return;
}
@@ -1002,11 +1047,15 @@ void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
return;
}
- ALOGD("Set active color mode: %s (%d), type=%d", decodeColorMode(mode).c_str(), mode,
- hw->getDisplayType());
-
hw->setActiveColorMode(mode);
- getHwComposer().setActiveColorMode(type, mode, RenderIntent::COLORIMETRIC);
+ hw->setCompositionDataSpace(dataSpace);
+ hw->setActiveRenderIntent(renderIntent);
+ getHwComposer().setActiveColorMode(type, mode, renderIntent);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+ decodeColorMode(mode).c_str(), mode,
+ decodeRenderIntent(renderIntent).c_str(), renderIntent,
+ hw->getDisplayType());
}
@@ -1037,7 +1086,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
ALOGW("Attempt to set active color mode %s %d for virtual display",
decodeColorMode(mMode).c_str(), mMode);
} else {
- mFlinger.setActiveColorModeInternal(hw, mMode);
+ mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN);
}
return true;
}
@@ -1072,7 +1121,7 @@ status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
std::unique_ptr<HdrCapabilities> capabilities =
getBE().mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
if (capabilities) {
- if (displayDevice->getWideColorSupport() && !displayDevice->getHdrSupport()) {
+ if (displayDevice->hasWideColorGamut() && !displayDevice->hasHdr10()) {
// insert HDR10 as we will force client composition for HDR10
// layers
std::vector<int32_t> types = capabilities->getSupportedHdrTypes();
@@ -1338,7 +1387,7 @@ void SurfaceFlinger::onRefreshReceived(int sequenceId,
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- repaintEverythingLocked();
+ repaintEverything();
}
void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
@@ -1821,81 +1870,86 @@ void SurfaceFlinger::rebuildLayerStacks() {
}
mat4 SurfaceFlinger::computeSaturationMatrix() const {
- if (mSaturation == 1.0f) {
+ if (mGlobalSaturationFactor == 1.0f) {
return mat4();
}
// Rec.709 luma coefficients
float3 luminance{0.213f, 0.715f, 0.072f};
- luminance *= 1.0f - mSaturation;
+ luminance *= 1.0f - mGlobalSaturationFactor;
return mat4(
- vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
- vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
- vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
+ vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},
+ vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},
+ vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},
vec4{0.0f, 0.0f, 0.0f, 1.0f}
);
}
-// pickColorMode translates a given dataspace into the best available color mode.
-// Currently only support sRGB and Display-P3.
-ColorMode SurfaceFlinger::pickColorMode(Dataspace dataSpace) const {
- if (mForceNativeColorMode) {
- return ColorMode::NATIVE;
+// Returns a dataspace that fits all visible layers. The returned dataspace
+// can only be one of
+//
+// - Dataspace::V0_SRGB
+// - Dataspace::DISPLAY_P3
+// - Dataspace::V0_SCRGB_LINEAR
+// TODO(b/73825729) Add BT2020 data space.
+ui::Dataspace SurfaceFlinger::getBestDataspace(
+ const sp<const DisplayDevice>& displayDevice) const {
+ Dataspace bestDataspace = Dataspace::V0_SRGB;
+ for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ switch (layer->getDataSpace()) {
+ case Dataspace::V0_SCRGB:
+ case Dataspace::V0_SCRGB_LINEAR:
+ // return immediately
+ return Dataspace::V0_SCRGB_LINEAR;
+ case Dataspace::BT2020_PQ:
+ case Dataspace::BT2020_ITU_PQ:
+ // Historically, HDR dataspaces are ignored by SurfaceFlinger. But
+ // since SurfaceFlinger simulates HDR support now, it should honor
+ // them unless there is also native support.
+ if (!displayDevice->hasHdr10()) {
+ return Dataspace::V0_SCRGB_LINEAR;
+ }
+ break;
+ case Dataspace::DISPLAY_P3:
+ bestDataspace = Dataspace::DISPLAY_P3;
+ break;
+ default:
+ break;
+ }
}
- switch (dataSpace) {
- // treat Unknown as regular SRGB buffer, since that's what the rest of the
- // system expects.
- case Dataspace::UNKNOWN:
- case Dataspace::SRGB:
- case Dataspace::V0_SRGB:
- return ColorMode::SRGB;
- break;
+ return bestDataspace;
+}
+
+// Pick the ColorMode / Dataspace for the display device.
+// TODO(b/73825729) Add BT2020 color mode.
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
+ ColorMode* outMode, Dataspace* outDataSpace) const {
+ if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
+ *outMode = ColorMode::NATIVE;
+ *outDataSpace = Dataspace::UNKNOWN;
+ return;
+ }
+ switch (getBestDataspace(displayDevice)) {
case Dataspace::DISPLAY_P3:
- return ColorMode::DISPLAY_P3;
+ case Dataspace::V0_SCRGB_LINEAR:
+ *outMode = ColorMode::DISPLAY_P3;
+ *outDataSpace = Dataspace::DISPLAY_P3;
break;
-
default:
- // TODO (courtneygo): Do we want to assert an error here?
- ALOGE("No color mode mapping for %s (%#x)",
- dataspaceDetails(static_cast<android_dataspace>(dataSpace)).c_str(),
- dataSpace);
- return ColorMode::SRGB;
+ *outMode = ColorMode::SRGB;
+ *outDataSpace = Dataspace::V0_SRGB;
break;
}
}
-Dataspace SurfaceFlinger::bestTargetDataSpace(
- Dataspace a, Dataspace b, bool hasHdr) const {
- // Only support sRGB and Display-P3 right now.
- if (a == Dataspace::DISPLAY_P3 || b == Dataspace::DISPLAY_P3) {
- return Dataspace::DISPLAY_P3;
- }
- if (a == Dataspace::V0_SCRGB_LINEAR || b == Dataspace::V0_SCRGB_LINEAR) {
- return Dataspace::DISPLAY_P3;
- }
- if (a == Dataspace::V0_SCRGB || b == Dataspace::V0_SCRGB) {
- return Dataspace::DISPLAY_P3;
- }
- if (!hasHdr) {
- if (a == Dataspace::BT2020_PQ || b == Dataspace::BT2020_PQ) {
- return Dataspace::DISPLAY_P3;
- }
- if (a == Dataspace::BT2020_ITU_PQ || b == Dataspace::BT2020_ITU_PQ) {
- return Dataspace::DISPLAY_P3;
- }
- }
-
- return Dataspace::V0_SRGB;
-}
-
void SurfaceFlinger::setUpHWComposer() {
ATRACE_CALL();
ALOGV("setUpHWComposer");
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
+ bool dirty = !mDisplays[dpy]->getDirtyRegion(mRepaintEverything).isEmpty();
bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
@@ -1970,7 +2024,7 @@ void SurfaceFlinger::setUpHWComposer() {
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !displayDevice->getHdrSupport()) {
+ !displayDevice->hasHdr10()) {
layer->forceClientComposition(hwcId);
}
@@ -1984,19 +2038,10 @@ void SurfaceFlinger::setUpHWComposer() {
}
if (hasWideColorDisplay) {
- ColorMode newColorMode;
- Dataspace newDataSpace = Dataspace::V0_SRGB;
-
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace,
- displayDevice->getHdrSupport());
- ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
- layer->getName().string(), dataspaceDetails(static_cast<android_dataspace>(layer->getDataSpace())).c_str(),
- layer->getDataSpace(), dataspaceDetails(static_cast<android_dataspace>(newDataSpace)).c_str(), newDataSpace);
- }
- newColorMode = pickColorMode(newDataSpace);
-
- setActiveColorModeInternal(displayDevice, newColorMode);
+ ColorMode colorMode;
+ Dataspace dataSpace;
+ pickColorMode(displayDevice, &colorMode, &dataSpace);
+ setActiveColorModeInternal(displayDevice, colorMode, dataSpace);
}
}
@@ -2204,29 +2249,40 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
- bool hasWideColorSupport = false;
+ bool hasWideColorGamut = false;
if (hasWideColorDisplay) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(state.type);
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
for (ColorMode colorMode : modes) {
switch (colorMode) {
case ColorMode::DISPLAY_P3:
case ColorMode::ADOBE_RGB:
case ColorMode::DCI_P3:
- hasWideColorSupport = true;
+ hasWideColorGamut = true;
break;
+ // TODO(lpy) Handle BT2020, BT2100_PQ and BT2100_HLG properly.
default:
break;
}
+
+ std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
+ colorMode);
+ if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+ for (auto intent : renderIntents) {
+ if (intent == RenderIntent::ENHANCE) {
+ mBuiltinDisplaySupportsEnhance = true;
+ break;
+ }
+ }
+ }
}
}
- bool hasHdrSupport = false;
- std::unique_ptr<HdrCapabilities> hdrCapabilities =
- getHwComposer().getHdrCapabilities(state.type);
+ bool hasHdr10 = false;
+ std::unique_ptr<HdrCapabilities> hdrCapabilities = getHwComposer().getHdrCapabilities(hwcId);
if (hdrCapabilities) {
const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes();
auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10);
- hasHdrSupport = iter != types.cend();
+ hasHdr10 = iter != types.cend();
}
auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
@@ -2260,18 +2316,19 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
sp<DisplayDevice> hw =
new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
dispSurface, std::move(renderSurface), displayWidth, displayHeight,
- hasWideColorSupport, hasHdrSupport, initialPowerMode);
+ hasWideColorGamut, hasHdr10, initialPowerMode);
if (maxFrameBufferAcquiredBuffers >= 3) {
nativeWindowSurface->preallocateBuffers();
}
ColorMode defaultColorMode = ColorMode::NATIVE;
- if (hasWideColorSupport) {
+ Dataspace defaultDataSpace = Dataspace::UNKNOWN;
+ if (hasWideColorGamut) {
defaultColorMode = ColorMode::SRGB;
+ defaultDataSpace = Dataspace::V0_SRGB;
}
- setActiveColorModeInternal(hw, defaultColorMode);
- hw->setCompositionDataSpace(Dataspace::UNKNOWN);
+ setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace);
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation, state.viewport, state.frame);
hw->setDisplayName(state.displayName);
@@ -2822,23 +2879,27 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev
const Region bounds(displayDevice->bounds());
const DisplayRenderArea renderArea(displayDevice);
const auto hwcId = displayDevice->getHwcDisplayId();
+ const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+ const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
+ const bool skipClientColorTransform = getBE().mHwc->hasCapability(
+ HWC2::Capability::SkipClientColorTransform);
+ ATRACE_INT("hasClientComposition", hasClientComposition);
mat4 oldColorMatrix;
- const bool applyColorMatrix = !getBE().mHwc->hasDeviceComposition(hwcId) &&
- !getBE().mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
+ mat4 legacySrgbSaturationMatrix = mLegacySrgbSaturationMatrix;
+ const bool applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
if (applyColorMatrix) {
- mat4 colorMatrix = mColorMatrix * mDaltonizer();
+ mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix);
+ legacySrgbSaturationMatrix = colorMatrix * legacySrgbSaturationMatrix;
}
- bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
if (hasClientComposition) {
ALOGV("hasClientComposition");
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (displayDevice->getWideColorSupport() &&
- displayDevice->getActiveColorMode() == ColorMode::DISPLAY_P3) {
- outputDataspace = Dataspace::DISPLAY_P3;
+ if (displayDevice->hasWideColorGamut()) {
+ outputDataspace = displayDevice->getCompositionDataSpace();
}
getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
@@ -2855,7 +2916,6 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev
}
// Never touch the framebuffer if we don't have any framebuffer layers
- const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
if (hasDeviceComposition) {
// when using overlays, we assume a fully transparent framebuffer
// NOTE: we could reduce how much we need to clear, for instance
@@ -2930,7 +2990,20 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDev
break;
}
case HWC2::Composition::Client: {
+ // Only apply saturation matrix layer that is legacy SRGB dataspace
+ // when auto color mode is on.
+ bool restore = false;
+ mat4 savedMatrix;
+ if (mDisplayColorSetting == DisplayColorSetting::ENHANCED &&
+ layer->isLegacySrgbDataSpace()) {
+ savedMatrix =
+ getRenderEngine().setupColorTransform(legacySrgbSaturationMatrix);
+ restore = true;
+ }
layer->draw(renderArea, clip);
+ if (restore) {
+ getRenderEngine().setupColorTransform(savedMatrix);
+ }
break;
}
default:
@@ -3643,7 +3716,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
- repaintEverythingLocked();
+ repaintEverything();
struct sched_param param = {0};
param.sched_priority = 1;
@@ -4004,7 +4077,7 @@ void SurfaceFlinger::dumpBufferingStats(String8& result) const {
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
- result.appendFormat("forceNativeColorMode: %d\n", mForceNativeColorMode);
+ result.appendFormat("DisplayColorSetting: %d\n", mDisplayColorSetting);
// TODO: print out if wide-color mode is active or not
@@ -4500,15 +4573,22 @@ status_t SurfaceFlinger::onTransact(
return NO_ERROR;
}
case 1022: { // Set saturation boost
- mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+ mGlobalSaturationFactor = std::max(0.0f, std::min(data.readFloat(), 2.0f));
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
}
case 1023: { // Set native mode
- mForceNativeColorMode = data.readInt32() == 1;
+ int32_t value = data.readInt32();
+ if (value > 2) {
+ return BAD_VALUE;
+ }
+ if (value == 2 && !mBuiltinDisplaySupportsEnhance) {
+ return BAD_VALUE;
+ }
+ mDisplayColorSetting = toDisplayColorSetting(value);
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
@@ -4535,27 +4615,33 @@ status_t SurfaceFlinger::onTransact(
reply->writeBool(mTracing.isEnabled());
return NO_ERROR;
}
+ // Is a DisplayColorSetting supported?
+ case 1027: {
+ int32_t value = data.readInt32();
+ switch (value) {
+ case 0:
+ reply->writeBool(hasWideColorDisplay);
+ return NO_ERROR;
+ case 1:
+ reply->writeBool(true);
+ return NO_ERROR;
+ case 2:
+ reply->writeBool(mBuiltinDisplaySupportsEnhance);
+ return NO_ERROR;
+ default:
+ return BAD_VALUE;
+ }
+ }
}
}
return err;
}
-void SurfaceFlinger::repaintEverythingLocked() {
+void SurfaceFlinger::repaintEverything() {
android_atomic_or(1, &mRepaintEverything);
- for (size_t dpy = 0; dpy < mDisplays.size(); dpy++) {
- const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
- const Rect bounds(displayDevice->getBounds());
- displayDevice->dirtyRegion.orSelf(Region(bounds));
- }
signalTransaction();
}
-void SurfaceFlinger::repaintEverything() {
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
- repaintEverythingLocked();
-}
-
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
@@ -4597,11 +4683,12 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
public:
LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
int32_t reqWidth, int32_t reqHeight, bool childrenOnly)
- : RenderArea(reqHeight, reqWidth),
+ : RenderArea(reqHeight, reqWidth, CaptureFill::CLEAR),
mLayer(layer),
mCrop(crop),
mFlinger(flinger),
mChildrenOnly(childrenOnly) {}
+ const Transform& getTransform() const override { return mTransform; }
Rect getBounds() const override {
const Layer::State& layerState(mLayer->getDrawingState());
return Rect(layerState.active.w, layerState.active.h);
@@ -4610,7 +4697,15 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
int getWidth() const override { return mLayer->getDrawingState().active.w; }
bool isSecure() const override { return false; }
bool needsFiltering() const override { return false; }
- const Transform& getTransform() const { return mTransform; }
+ Rect getSourceCrop() const override {
+ if (mCrop.isEmpty()) {
+ return getBounds();
+ } else {
+ return mCrop;
+ }
+ }
+ bool getWideColorSupport() const override { return false; }
+ Dataspace getDataSpace() const override { return Dataspace::UNKNOWN; }
class ReparentForDrawing {
public:
@@ -4639,16 +4734,6 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
}
}
- Rect getSourceCrop() const override {
- if (mCrop.isEmpty()) {
- return getBounds();
- } else {
- return mCrop;
- }
- }
- bool getWideColorSupport() const override { return false; }
- ColorMode getActiveColorMode() const override { return ColorMode::NATIVE; }
-
private:
const sp<Layer> mLayer;
const Rect mCrop;
@@ -4820,9 +4905,8 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
}
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (renderArea.getWideColorSupport() &&
- renderArea.getActiveColorMode() == ColorMode::DISPLAY_P3) {
- outputDataspace = Dataspace::DISPLAY_P3;
+ if (renderArea.getWideColorSupport()) {
+ outputDataspace = renderArea.getDataSpace();
}
getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
@@ -4834,8 +4918,9 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
renderArea.getRotationFlags());
engine.disableTexturing();
+ const float alpha = RenderArea::getCaptureFillValue(renderArea.getCaptureFill());
// redraw the screen entirely...
- engine.clearWithColor(0, 0, 0, 1);
+ engine.clearWithColor(0, 0, 0, alpha);
traverseLayers([&](Layer* layer) {
if (filtering) layer->setFiltering(true);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a29d1d7475..33706dafe9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -123,6 +123,12 @@ enum {
eTransactionMask = 0x0f,
};
+enum class DisplayColorSetting : int32_t {
+ MANAGED = 0,
+ UNMANAGED = 1,
+ ENHANCED = 2,
+};
+
// A thin interface to abstract creating instances of Surface (gui/Surface.h) to
// use as a NativeWindow.
class NativeWindowSurface {
@@ -306,8 +312,6 @@ public:
// force full composition on all displays
void repaintEverything();
- // Can only be called from the main thread or with mStateLock held
- void repaintEverythingLocked();
// returns the default Display
sp<const DisplayDevice> getDefaultDisplayDevice() const {
@@ -467,7 +471,9 @@ private:
bool stateLockHeld);
// Called on the main thread in response to setActiveColorMode()
- void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode);
+ void setActiveColorModeInternal(const sp<DisplayDevice>& hw,
+ ui::ColorMode colorMode,
+ ui::Dataspace dataSpace);
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -641,9 +647,10 @@ private:
// Given a dataSpace, returns the appropriate color_mode to use
// to display that dataSpace.
- ui::ColorMode pickColorMode(ui::Dataspace dataSpace) const;
- ui::Dataspace bestTargetDataSpace(ui::Dataspace a, ui::Dataspace b,
- bool hasHdr) const;
+ ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice) const;
+ void pickColorMode(const sp<DisplayDevice>& displayDevice,
+ ui::ColorMode* outMode,
+ ui::Dataspace* outDataSpace) const;
mat4 computeSaturationMatrix() const;
@@ -846,7 +853,6 @@ private:
size_t mNumLayers;
-
// Verify that transaction is being called by an approved process:
// either AID_GRAPHICS or AID_SYSTEM.
status_t CheckTransactCodeCredentials(uint32_t code);
@@ -856,8 +862,12 @@ private:
static bool useVrFlinger;
std::thread::id mMainThreadId;
- float mSaturation = 1.0f;
- bool mForceNativeColorMode = false;
+ DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::MANAGED;
+ // Applied on sRGB layers when the render intent is non-colorimetric.
+ mat4 mLegacySrgbSaturationMatrix;
+ // Applied globally.
+ float mGlobalSaturationFactor = 1.0f;
+ bool mBuiltinDisplaySupportsEnhance = false;
using CreateBufferQueueFunction =
std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 176c691c6a..a0f12f1438 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2358,6 +2358,24 @@ TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
mCapture->expectChildColor(0, 0);
}
+TEST_F(ScreenCaptureTest, CaptureTransparent) {
+ sp<SurfaceControl> child =
+ mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888,
+ 0, mFGSurfaceControl.get());
+
+ fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ auto childHandle = child->getHandle();
+
+ // Captures child
+ ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
+ mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
+ // Area outside of child's bounds is transparent.
+ mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
+}
+
// In the following tests we verify successful skipping of a parent layer,
// so we use the same verification logic and only change how we mutate
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 11ffc3f2fe..4af47d2a35 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -251,20 +251,22 @@ VrHwc::~VrHwc() {}
bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
void VrHwc::registerEventCallback(EventCallback* callback) {
- event_callback_ = callback;
-
- if (client_ != nullptr) {
- {
- int32_t width, height;
- GetPrimaryDisplaySize(&width, &height);
- std::lock_guard<std::mutex> guard(mutex_);
- // Create the primary display late to avoid initialization issues between
- // VR HWC and SurfaceFlinger.
- displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
- }
- event_callback_->onHotplug(kDefaultDisplayId,
- IComposerCallback::Connection::CONNECTED);
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
+ event_callback_ = callback;
+ int32_t width, height;
+ GetPrimaryDisplaySize(&width, &height);
+ // Create the primary display late to avoid initialization issues between
+ // VR HWC and SurfaceFlinger.
+ displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
}
+ event_callback_->onHotplug(kDefaultDisplayId,
+ IComposerCallback::Connection::CONNECTED);
+}
+
+void VrHwc::unregisterEventCallback() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ event_callback_ = nullptr;
}
uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index d5d5f55e2e..85e587abbe 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -213,7 +213,7 @@ class VrHwc : public IComposer, public ComposerHal, public ComposerView {
std::string dumpDebugInfo() override { return {}; }
void registerEventCallback(EventCallback* callback) override;
- void unregisterEventCallback() override {}
+ void unregisterEventCallback() override;
uint32_t getMaxVirtualDisplayCount() override;
Error createVirtualDisplay(uint32_t width, uint32_t height,