Merge changes I9b4b0d4c,I1faca3aa,I38b538c1,I176c6641 into sc-dev
* changes:
SF: do not skip validate if it is called more than a vsync earlier
SF: region sampling scheduling optimization
SF: return the expected wakeup time from VSyncDispatch
SurfaceFlinger: previousFrameFence needs to check the current time
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/bugreport/OWNERS
+++ b/cmds/bugreport/OWNERS
@@ -1,4 +1,5 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/bugreportz/OWNERS
+++ b/cmds/bugreportz/OWNERS
@@ -1,4 +1,5 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/cmds/dumpstate/OWNERS b/cmds/dumpstate/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/dumpstate/OWNERS
+++ b/cmds/dumpstate/OWNERS
@@ -1,4 +1,5 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 4f6a89e..97a63ca 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -1,5 +1,6 @@
set noparent
+gavincorkery@google.com
nandana@google.com
jsharkey@android.com
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index fc745d0..d6807ff 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -9,3 +9,4 @@
ngeoffray@google.com
rpl@google.com
toddke@google.com
+patb@google.com
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index ef7fd44..18b77e6 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -366,19 +366,45 @@
pid_t IPCThreadState::getCallingPid() const
{
+ checkContextIsBinderForUse(__func__);
return mCallingPid;
}
const char* IPCThreadState::getCallingSid() const
{
+ checkContextIsBinderForUse(__func__);
return mCallingSid;
}
uid_t IPCThreadState::getCallingUid() const
{
+ checkContextIsBinderForUse(__func__);
return mCallingUid;
}
+IPCThreadState::SpGuard* IPCThreadState::pushGetCallingSpGuard(SpGuard* guard) {
+ SpGuard* orig = mServingStackPointerGuard;
+ mServingStackPointerGuard = guard;
+ return orig;
+}
+
+void IPCThreadState::restoreGetCallingSpGuard(SpGuard* guard) {
+ mServingStackPointerGuard = guard;
+}
+
+void IPCThreadState::checkContextIsBinderForUse(const char* use) const {
+ if (mServingStackPointerGuard == nullptr) return;
+
+ if (!mServingStackPointer || mServingStackPointerGuard < mServingStackPointer) {
+ LOG_ALWAYS_FATAL("In context %s, %s does not make sense.",
+ mServingStackPointerGuard->context, use);
+ }
+
+ // in the case mServingStackPointer is deeper in the stack than the guard,
+ // we must be serving a binder transaction (maybe nested). This is a binder
+ // context, so we don't abort
+}
+
int64_t IPCThreadState::clearCallingIdentity()
{
// ignore mCallingSid for legacy reasons
@@ -847,15 +873,15 @@
}
IPCThreadState::IPCThreadState()
- : mProcess(ProcessState::self()),
- mServingStackPointer(nullptr),
- mWorkSource(kUnsetWorkSource),
- mPropagateWorkSource(false),
- mIsLooper(false),
- mStrictModePolicy(0),
- mLastTransactionBinderFlags(0),
- mCallRestriction(mProcess->mCallRestriction)
-{
+ : mProcess(ProcessState::self()),
+ mServingStackPointer(nullptr),
+ mServingStackPointerGuard(nullptr),
+ mWorkSource(kUnsetWorkSource),
+ mPropagateWorkSource(false),
+ mIsLooper(false),
+ mStrictModePolicy(0),
+ mLastTransactionBinderFlags(0),
+ mCallRestriction(mProcess->mCallRestriction) {
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 3c63789..9cc6e7f 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -134,7 +134,7 @@
bool RpcServer::acceptOne() {
LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
- LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
+ LOG_ALWAYS_FATAL_IF(!hasServer(), "RpcServer must be setup to join.");
unique_fd clientFd(
TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
@@ -232,11 +232,7 @@
bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
-
- {
- std::lock_guard<std::mutex> _l(mLock);
- LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcServer can only have one server.");
- }
+ LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
unique_fd serverFd(
TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
@@ -275,4 +271,27 @@
(void)mSessions.erase(it);
}
+bool RpcServer::hasServer() {
+ LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+ std::lock_guard<std::mutex> _l(mLock);
+ return mServer.ok();
+}
+
+unique_fd RpcServer::releaseServer() {
+ LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+ std::lock_guard<std::mutex> _l(mLock);
+ return std::move(mServer);
+}
+
+bool RpcServer::setupExternalServer(base::unique_fd serverFd) {
+ LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+ std::lock_guard<std::mutex> _l(mLock);
+ if (mServer.ok()) {
+ ALOGE("Each RpcServer can only have one server.");
+ return false;
+ }
+ mServer = std::move(serverFd);
+ return true;
+}
+
} // namespace android
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 2ba9fa2..e5a6026 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -18,7 +18,9 @@
#include "RpcState.h"
+#include <android-base/scopeguard.h>
#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
#include <binder/RpcServer.h>
#include "Debug.h"
@@ -28,6 +30,8 @@
namespace android {
+using base::ScopeGuard;
+
RpcState::RpcState() {}
RpcState::~RpcState() {}
@@ -470,6 +474,18 @@
status_t RpcState::processServerCommand(const base::unique_fd& fd, const sp<RpcSession>& session,
const RpcWireHeader& command) {
+ IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull();
+ IPCThreadState::SpGuard spGuard{"processing binder RPC command"};
+ IPCThreadState::SpGuard* origGuard;
+ if (kernelBinderState != nullptr) {
+ origGuard = kernelBinderState->pushGetCallingSpGuard(&spGuard);
+ }
+ ScopeGuard guardUnguard = [&]() {
+ if (kernelBinderState != nullptr) {
+ kernelBinderState->restoreGetCallingSpGuard(origGuard);
+ }
+ };
+
switch (command.command) {
case RPC_COMMAND_TRANSACT:
return processTransact(fd, session, command);
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 23a0cb0..5220b62 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -81,6 +81,32 @@
*/
uid_t getCallingUid() const;
+ /**
+ * Make it an abort to rely on getCalling* for a section of
+ * execution.
+ *
+ * Usage:
+ * IPCThreadState::SpGuard guard { "..." };
+ * auto* orig = pushGetCallingSpGuard(&guard);
+ * {
+ * // will abort if you call getCalling*, unless you are
+ * // serving a nested binder transaction
+ * }
+ * restoreCallingSpGuard(orig);
+ */
+ struct SpGuard {
+ const char* context;
+ };
+ SpGuard* pushGetCallingSpGuard(SpGuard* guard);
+ void restoreGetCallingSpGuard(SpGuard* guard);
+ /**
+ * Used internally by getCalling*. Can also be used to assert that
+ * you are in a binder context (getCalling* is valid). This is
+ * intentionally not exposed as a boolean API since code should be
+ * written to know its environment.
+ */
+ void checkContextIsBinderForUse(const char* use) const;
+
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
@@ -203,6 +229,7 @@
Parcel mOut;
status_t mLastError;
const void* mServingStackPointer;
+ SpGuard* mServingStackPointerGuard;
pid_t mCallingPid;
const char* mCallingSid;
uid_t mCallingUid;
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index 9659732..f3ba830 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -50,8 +50,12 @@
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
/**
* Force the service to persist, even when it has 0 clients.
- * If setting this flag from the server side, make sure to do so before calling registerService,
- * or there may be a race with the default dynamic shutdown.
+ * If setting this flag from the server side, make sure to do so before calling
+ * registerService, or there may be a race with the default dynamic shutdown.
+ *
+ * This should only be used if it is every eventually set to false. If a
+ * service needs to persist but doesn't need to dynamically shut down,
+ * prefer to control it with another mechanism such as ctl.start.
*/
void forcePersist(bool persist);
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 6e27540..8f0c6fd 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -74,6 +74,22 @@
*/
[[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+ /**
+ * If setup*Server has been successful, return true. Otherwise return false.
+ */
+ [[nodiscard]] bool hasServer();
+
+ /**
+ * If hasServer(), return the server FD. Otherwise return invalid FD.
+ */
+ [[nodiscard]] base::unique_fd releaseServer();
+
+ /**
+ * Set up server using an external FD previously set up by releaseServer().
+ * Return false if there's already a server.
+ */
+ bool setupExternalServer(base::unique_fd serverFd);
+
void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
/**
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index a90b4aa..2a66941 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -35,7 +35,7 @@
* \return EX_NONE on success.
*/
__attribute__((warn_unused_result)) binder_exception_t AServiceManager_addService(
- AIBinder* binder, const char* instance);
+ AIBinder* binder, const char* instance) __INTRODUCED_IN(29);
/**
* Gets a binder object with this specific instance name. Will return nullptr immediately if the
@@ -47,7 +47,8 @@
*
* \param instance identifier of the service used to lookup the service.
*/
-__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance)
+ __INTRODUCED_IN(29);
/**
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
@@ -59,7 +60,8 @@
*
* \param instance identifier of the service used to lookup the service.
*/
-__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
+ __INTRODUCED_IN(29);
/**
* Registers a lazy service with the default service manager under the 'instance' name.
@@ -135,6 +137,10 @@
/**
* Prevent lazy services without client from shutting down their process
*
+ * This should only be used if it is every eventually set to false. If a
+ * service needs to persist but doesn't need to dynamically shut down,
+ * prefer to control it with another mechanism.
+ *
* \param persist 'true' if the process should not exit.
*/
void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index ef4198d..41daccc 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -55,4 +55,6 @@
oneway void sleepMsAsync(int ms);
void die(boolean cleanup);
+
+ void useKernelBinderCallingId();
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 0c3fbcd..45b2776 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -73,6 +73,7 @@
BINDER_LIB_TEST_REGISTER_SERVER,
BINDER_LIB_TEST_ADD_SERVER,
BINDER_LIB_TEST_ADD_POLL_SERVER,
+ BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION,
BINDER_LIB_TEST_CALL_BACK,
BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF,
BINDER_LIB_TEST_DELAYED_CALL_BACK,
@@ -604,6 +605,24 @@
EXPECT_THAT(callBack->getResult(), StatusEq(NO_ERROR));
}
+TEST_F(BinderLibTest, NoBinderCallContextGuard) {
+ IPCThreadState::SpGuard spGuard{"NoBinderCallContext"};
+ IPCThreadState::SpGuard *origGuard = IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
+ // yes, this test uses threads, but it's careful and uses fork in addServer
+ EXPECT_DEATH({ IPCThreadState::self()->getCallingPid(); },
+ "In context NoBinderCallContext, getCallingPid does not make sense.");
+
+ IPCThreadState::self()->restoreGetCallingSpGuard(origGuard);
+}
+
+TEST_F(BinderLibTest, BinderCallContextGuard) {
+ sp<IBinder> binder = addServer();
+ Parcel data, reply;
+ EXPECT_THAT(binder->transact(BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION, data, &reply),
+ StatusEq(DEAD_OBJECT));
+}
+
TEST_F(BinderLibTest, AddServer)
{
sp<IBinder> server = addServer();
@@ -1262,6 +1281,18 @@
pthread_mutex_unlock(&m_serverWaitMutex);
return ret;
}
+ case BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION: {
+ IPCThreadState::SpGuard spGuard{"GuardInBinderTransaction"};
+ IPCThreadState::SpGuard *origGuard =
+ IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
+ // if the guard works, this should abort
+ (void)IPCThreadState::self()->getCallingPid();
+
+ IPCThreadState::self()->restoreGetCallingSpGuard(origGuard);
+ return NO_ERROR;
+ }
+
case BINDER_LIB_TEST_GETPID:
reply->writeInt32(getpid());
return NO_ERROR;
@@ -1489,6 +1520,11 @@
{
binderLibTestServiceName += String16(binderserversuffix);
+ // Testing to make sure that calls that we are serving can use getCallin*
+ // even though we don't here.
+ IPCThreadState::SpGuard spGuard{"main server thread"};
+ (void)IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
status_t ret;
sp<IServiceManager> sm = defaultServiceManager();
BinderLibTestService* testServicePtr;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 260be57..3f94df2 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -23,6 +23,7 @@
#include <android/binder_libbinder.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
@@ -49,6 +50,19 @@
EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
}
+TEST(BinderRpc, SetExternalServer) {
+ base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
+ int sinkFd = sink.get();
+ auto server = RpcServer::make();
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ ASSERT_FALSE(server->hasServer());
+ ASSERT_TRUE(server->setupExternalServer(std::move(sink)));
+ ASSERT_TRUE(server->hasServer());
+ base::unique_fd retrieved = server->releaseServer();
+ ASSERT_FALSE(server->hasServer());
+ ASSERT_EQ(sinkFd, retrieved.get());
+}
+
using android::binder::Status;
#define EXPECT_OK(status) \
@@ -178,6 +192,13 @@
_exit(1);
}
}
+ Status useKernelBinderCallingId() override {
+ // this is WRONG! It does not make sense when using RPC binder, and
+ // because it is SO wrong, and so much code calls this, it should abort!
+
+ (void)IPCThreadState::self()->getCallingPid();
+ return Status::ok();
+ }
};
sp<IBinder> MyBinderRpcTest::mHeldBinder;
@@ -874,6 +895,19 @@
}
}
+TEST_P(BinderRpc, UseKernelBinderCallingId) {
+ auto proc = createRpcTestSocketServerProcess(1);
+
+ // we can't allocate IPCThreadState so actually the first time should
+ // succeed :(
+ EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
+
+ // second time! we catch the error :)
+ EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
+
+ proc.expectInvalid = true;
+}
+
TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
auto proc = createRpcTestSocketServerProcess(1);
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 9400037..3c58238 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1233,8 +1233,10 @@
}
}
- mState.maxMasteringLuminance = layer->source.buffer.maxMasteringLuminance;
- mState.maxContentLuminance = layer->source.buffer.maxContentLuminance;
+ // Ensure luminance is at least 100 nits to avoid div-by-zero
+ const float maxLuminance = std::max(100.f, layer->source.buffer.maxLuminanceNits);
+ mState.maxMasteringLuminance = maxLuminance;
+ mState.maxContentLuminance = maxLuminance;
mState.projectionMatrix = projectionMatrix * layer->geometry.positionTransform;
const FloatRect bounds = layer->geometry.boundaries;
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index a637796..53fa622 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -60,6 +60,9 @@
// capture of a device in landscape while the buffer is in portrait
// orientation.
uint32_t orientation = ui::Transform::ROT_0;
+
+ // SDR white point, -1f if unknown
+ float sdrWhitePointNits = -1.f;
};
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 6e98352..bfb7465 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -64,8 +64,8 @@
// HDR color-space setting for Y410.
bool isY410BT2020 = false;
- float maxMasteringLuminance = 0.0;
- float maxContentLuminance = 0.0;
+
+ float maxLuminanceNits = 0.0;
};
// Metadata describing the layer geometry.
@@ -175,8 +175,7 @@
lhs.textureTransform == rhs.textureTransform &&
lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha &&
lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 &&
- lhs.maxMasteringLuminance == rhs.maxMasteringLuminance &&
- lhs.maxContentLuminance == rhs.maxContentLuminance;
+ lhs.maxLuminanceNits == rhs.maxLuminanceNits;
}
static inline bool operator==(const Geometry& lhs, const Geometry& rhs) {
@@ -239,8 +238,7 @@
*os << "\n .usePremultipliedAlpha = " << settings.usePremultipliedAlpha;
*os << "\n .isOpaque = " << settings.isOpaque;
*os << "\n .isY410BT2020 = " << settings.isY410BT2020;
- *os << "\n .maxMasteringLuminance = " << settings.maxMasteringLuminance;
- *os << "\n .maxContentLuminance = " << settings.maxContentLuminance;
+ *os << "\n .maxLuminanceNits = " << settings.maxLuminanceNits;
*os << "\n}";
}
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 48d76cc..0eee564 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -108,8 +108,7 @@
.source = PixelSource{.buffer =
Buffer{
.buffer = srcTexture,
- .maxMasteringLuminance = 1000.f,
- .maxContentLuminance = 1000.f,
+ .maxLuminanceNits = 1000.f,
}},
};
@@ -205,8 +204,7 @@
.source = PixelSource{.buffer =
Buffer{
.buffer = srcTexture,
- .maxMasteringLuminance = 1000.f,
- .maxContentLuminance = 1000.f,
+ .maxLuminanceNits = 1000.f,
.textureTransform = kScaleYOnly,
}},
.sourceDataspace = kOtherDataSpace,
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 6d2af4a..05bbc12 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -590,10 +590,14 @@
} else {
runtimeEffect = effectIter->second;
}
+ float maxLuminance = layer->source.buffer.maxLuminanceNits;
+ // If the buffer doesn't have a max luminance, treat it as SDR & use the display's SDR
+ // white point
+ if (maxLuminance <= 0.f) {
+ maxLuminance = display.sdrWhitePointNits;
+ }
return createLinearEffectShader(shader, effect, runtimeEffect, layer->colorTransform,
- display.maxLuminance,
- layer->source.buffer.maxMasteringLuminance,
- layer->source.buffer.maxContentLuminance);
+ display.maxLuminance, maxLuminance);
}
return shader;
}
@@ -904,7 +908,9 @@
const bool requiresLinearEffect = layer->colorTransform != mat4() ||
(mUseColorManagement &&
- needsToneMapping(layer->sourceDataspace, display.outputDataspace));
+ needsToneMapping(layer->sourceDataspace, display.outputDataspace)) ||
+ (display.sdrWhitePointNits > 0.f &&
+ display.sdrWhitePointNits != display.maxLuminance);
// quick abort from drawing the remaining portion of the layer
if (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending &&
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 0fbd669..9b044e1 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -127,7 +127,7 @@
default:
shader.append(R"(
float3 ScaleLuminance(float3 xyz) {
- return xyz * in_displayMaxLuminance;
+ return xyz * in_inputMaxLuminance;
}
)");
break;
@@ -448,7 +448,7 @@
sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader, const LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float maxMasteringLuminance, float maxContentLuminance) {
+ float maxLuminance) {
ATRACE_CALL();
SkRuntimeShaderBuilder effectBuilder(runtimeEffect);
@@ -467,8 +467,10 @@
}
effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
+ // If the input luminance is unknown, use display luminance (aka, no-op any luminance changes)
+ // This will be the case for eg screenshots in addition to uncalibrated displays
effectBuilder.uniform("in_inputMaxLuminance") =
- std::min(maxMasteringLuminance, maxContentLuminance);
+ maxLuminance > 0 ? maxLuminance : maxDisplayLuminance;
return effectBuilder.makeShader(nullptr, false);
}
diff --git a/libs/renderengine/skia/filters/LinearEffect.h b/libs/renderengine/skia/filters/LinearEffect.h
index 20b8338..9e989ea 100644
--- a/libs/renderengine/skia/filters/LinearEffect.h
+++ b/libs/renderengine/skia/filters/LinearEffect.h
@@ -98,7 +98,7 @@
const LinearEffect& linearEffect,
sk_sp<SkRuntimeEffect> runtimeEffect,
const mat4& colorTransform, float maxDisplayLuminance,
- float maxMasteringLuminance, float maxContentLuminance);
+ float maxLuminance);
} // namespace skia
} // namespace renderengine
} // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4c73b6e..cacad52 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -58,8 +58,7 @@
namespace android {
-static constexpr float defaultMaxMasteringLuminance = 1000.0;
-static constexpr float defaultMaxContentLuminance = 1000.0;
+static constexpr float defaultMaxLuminance = 1000.0;
BufferLayer::BufferLayer(const LayerCreationArgs& args)
: Layer(args),
@@ -206,12 +205,24 @@
layer.source.buffer.isY410BT2020 = isHdrY410();
bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086;
bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3;
- layer.source.buffer.maxMasteringLuminance = hasSmpte2086
- ? mBufferInfo.mHdrMetadata.smpte2086.maxLuminance
- : defaultMaxMasteringLuminance;
- layer.source.buffer.maxContentLuminance = hasCta861_3
- ? mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel
- : defaultMaxContentLuminance;
+ float maxLuminance = 0.f;
+ if (hasSmpte2086 && hasCta861_3) {
+ maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance,
+ mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel);
+ } else if (hasSmpte2086) {
+ maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance;
+ } else if (hasCta861_3) {
+ maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel;
+ } else {
+ switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ case HAL_DATASPACE_TRANSFER_HLG:
+ // Behavior-match previous releases for HDR content
+ maxLuminance = defaultMaxLuminance;
+ break;
+ }
+ }
+ layer.source.buffer.maxLuminanceNits = maxLuminance;
layer.frameNumber = mCurrentFrameNumber;
layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer()->getId() : 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 9fba7aa..257974f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -184,6 +184,9 @@
// Sets the output color mode
virtual void setColorProfile(const ColorProfile&) = 0;
+ // Sets current calibrated display brightness information
+ virtual void setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) = 0;
+
// Outputs a string with a state dump
virtual void dump(std::string&) const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 2893c3f..f10ff25 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -49,6 +49,7 @@
void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
+ void setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) override;
void dump(std::string&) const override;
void dumpPlannerInfo(const Vector<String16>& args, std::string&) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index f0ef6d6..d41c2dd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -118,6 +118,12 @@
// The earliest time to send the present command to the HAL
std::chrono::steady_clock::time_point earliestPresentTime;
+ // Current display brightness
+ float displayBrightnessNits{-1.f};
+
+ // SDR white point
+ float sdrWhitePointNits{-1.f};
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 2488c66..2ffd472 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -78,9 +78,10 @@
void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition,
- bool isPeekingThrough);
+ bool isPeekingThrough, bool skipLayer);
void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
Hwc2::IComposerClient::Composition to) const;
+ bool isClientCompositionForced(bool isPeekingThrough) const;
};
// This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index b98043b..3f670a1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -125,6 +125,9 @@
// Set to true when overridden info has been sent to HW composer
bool stateOverridden = false;
+
+ // True when this layer was skipped as part of SF-side layer caching.
+ bool layerSkipped = false;
};
// The HWC state is optional, and is only set up if there is any potential
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 749675d..4b4d375 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -44,6 +44,7 @@
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
+ MOCK_METHOD2(setDisplayBrightness, void(float, float));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD2(dumpPlannerInfo, void(const Vector<String16>&, std::string&));
diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
index b1ee3fb..7e020ee 100644
--- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
@@ -46,8 +46,7 @@
lhs.textureTransform == rhs.textureTransform &&
lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha &&
lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 &&
- lhs.maxMasteringLuminance == rhs.maxMasteringLuminance &&
- lhs.maxContentLuminance == rhs.maxContentLuminance;
+ lhs.maxLuminanceNits == rhs.maxLuminanceNits;
}
inline bool equalIgnoringBuffer(const renderengine::LayerSettings& lhs,
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 796fe7d..bf36355 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -259,6 +259,18 @@
dirtyEntireOutput();
}
+void Output::setDisplayBrightness(float sdrWhitePointNits, float displayBrightnessNits) {
+ auto& outputState = editState();
+ if (outputState.sdrWhitePointNits == sdrWhitePointNits &&
+ outputState.displayBrightnessNits == displayBrightnessNits) {
+ // Nothing changed
+ return;
+ }
+ outputState.sdrWhitePointNits = sdrWhitePointNits;
+ outputState.displayBrightnessNits = displayBrightnessNits;
+ dirtyEntireOutput();
+}
+
void Output::dump(std::string& out) const {
using android::base::StringAppendF;
@@ -1035,8 +1047,13 @@
clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
? outputState.dataspace
: ui::Dataspace::UNKNOWN;
- clientCompositionDisplay.maxLuminance =
- mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+
+ // If we have a valid current display brightness use that, otherwise fall back to the
+ // display's max desired
+ clientCompositionDisplay.maxLuminance = outputState.displayBrightnessNits > 0.f
+ ? outputState.displayBrightnessNits
+ : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+ clientCompositionDisplay.sdrWhitePointNits = outputState.sdrWhitePointNits;
// Compute the global color transform matrix.
if (!outputState.usesDeviceComposition && !getSkipColorTransform()) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 01da070..cd14327 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <DisplayHardware/Hal.h>
#include <android-base/stringprintf.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/LayerFECompositionState.h>
@@ -350,12 +351,14 @@
writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState);
- writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough);
+ writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough,
+ skipLayer);
// Always set the layer color after setting the composition type.
writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
editState().hwc->stateOverridden = isOverridden;
+ editState().hwc->layerSkipped = skipLayer;
}
void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer,
@@ -482,7 +485,8 @@
const Region& surfaceDamage = getState().overrideInfo.buffer
? getState().overrideInfo.damageRegion
- : outputIndependentState.surfaceDamage;
+ : (getState().hwc->stateOverridden ? Region::INVALID_REGION
+ : outputIndependentState.surfaceDamage);
if (auto error = hwcLayer->setSurfaceDamage(surfaceDamage); error != hal::Error::NONE) {
ALOGE("[%s] Failed to set surface damage: %s (%d)", getLayerFE().getDebugName(),
@@ -573,17 +577,19 @@
void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer,
hal::Composition requestedCompositionType,
- bool isPeekingThrough) {
+ bool isPeekingThrough, bool skipLayer) {
auto& outputDependentState = editState();
- // If we are forcing client composition, we need to tell the HWC
- if (outputDependentState.forceClientComposition ||
- (!isPeekingThrough && getLayerFE().hasRoundedCorners())) {
+ if (isClientCompositionForced(isPeekingThrough)) {
+ // If we are forcing client composition, we need to tell the HWC
requestedCompositionType = hal::Composition::CLIENT;
}
// Set the requested composition type with the HWC whenever it changes
- if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType) {
+ // We also resend the composition type when this layer was previously skipped, to ensure that
+ // the composition type is up-to-date.
+ if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType ||
+ (outputDependentState.hwc->layerSkipped && !skipLayer)) {
outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
if (auto error = hwcLayer->setCompositionType(requestedCompositionType);
@@ -663,12 +669,22 @@
}
}
+bool OutputLayer::isClientCompositionForced(bool isPeekingThrough) const {
+ return getState().forceClientComposition ||
+ (!isPeekingThrough && getLayerFE().hasRoundedCorners());
+}
+
void OutputLayer::applyDeviceCompositionTypeChange(hal::Composition compositionType) {
auto& state = editState();
LOG_FATAL_IF(!state.hwc);
auto& hwcState = *state.hwc;
- detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+ // Only detected disallowed changes if this was not a skip layer, because the
+ // validated composition type may be arbitrary (usually DEVICE, to reflect that there were
+ // fewer GPU layers)
+ if (!hwcState.layerSkipped) {
+ detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+ }
hwcState.hwcCompositionType = compositionType;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 3adfe40..5bd1216 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -1065,12 +1065,62 @@
kOverrideSurfaceDamage);
expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+ mOutputLayer.editState().hwc->stateOverridden = true;
+
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
+ Region::INVALID_REGION);
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompositionInfo) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+ mOutputLayer.editState().hwc->stateOverridden = true;
+ mOutputLayer.editState().hwc->layerSkipped = true;
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
+ Region::INVALID_REGION);
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false);
}
+TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedClientCompositionInfo) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+ mOutputLayer.editState().forceClientComposition = true;
+ mOutputLayer.editState().hwc->stateOverridden = true;
+ mOutputLayer.editState().hwc->layerSkipped = true;
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+
+ expectGeometryCommonCalls();
+ expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
+ Region::INVALID_REGION);
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+ EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+ mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+ /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
TEST_F(OutputLayerWriteStateToHWCTest, peekThroughChangesBlendMode) {
auto peekThroughLayerFE = sp<compositionengine::mock::LayerFE>::make();
OutputLayer peekThroughLayer{mOutput, peekThroughLayerFE};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4fee723..7713749 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -221,7 +221,10 @@
}
void Layer::removeFromCurrentState() {
- mRemovedFromCurrentState = true;
+ if (!mRemovedFromCurrentState) {
+ mRemovedFromCurrentState = true;
+ mFlinger->mScheduler->deregisterLayer(this);
+ }
mFlinger->markLayerPendingRemovalLocked(this);
}
@@ -246,7 +249,10 @@
}
void Layer::addToCurrentState() {
- mRemovedFromCurrentState = false;
+ if (mRemovedFromCurrentState) {
+ mRemovedFromCurrentState = false;
+ mFlinger->mScheduler->registerLayer(this);
+ }
for (const auto& child : mCurrentChildren) {
child->addToCurrentState();
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index f4bc2a1..0563795 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -84,8 +84,11 @@
LayerHistory::~LayerHistory() = default;
void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
- auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
std::lock_guard lock(mLock);
+ for (const auto& info : mLayerInfos) {
+ LOG_ALWAYS_FATAL_IF(info.first == layer, "%s already registered", layer->getName().c_str());
+ }
+ auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
mLayerInfos.emplace_back(layer, std::move(info));
}
@@ -94,7 +97,7 @@
const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
[layer](const auto& pair) { return pair.first == layer; });
- LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
+ LOG_ALWAYS_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
const size_t i = static_cast<size_t>(it - mLayerInfos.begin());
if (i < mActiveLayersEnd) {
@@ -111,7 +114,11 @@
const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
[layer](const auto& pair) { return pair.first == layer; });
- LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
+ if (it == mLayerInfos.end()) {
+ // Offscreen layer
+ ALOGV("LayerHistory::record: %s not registered", layer->getName().c_str());
+ return;
+ }
const auto& info = it->second;
const auto layerProps = LayerInfo::LayerProps{
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 41aacc0..a5b7107 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -287,6 +287,8 @@
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS");
const String16 sDump("android.permission.DUMP");
+const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONTENT");
+
const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
// ---------------------------------------------------------------------------
@@ -306,6 +308,7 @@
Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
bool SurfaceFlinger::useFrameRateApi;
+bool SurfaceFlinger::enableSdrDimming;
std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
switch(displayColorSetting) {
@@ -477,6 +480,9 @@
base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false");
mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0);
+
+ // Debug property overrides ro. property
+ enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false));
}
SurfaceFlinger::~SurfaceFlinger() = default;
@@ -1486,8 +1492,13 @@
}
return ftl::chain(schedule([=]() MAIN_THREAD {
- if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
- return getHwComposer().setDisplayBrightness(*displayId,
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ if (enableSdrDimming) {
+ display->getCompositionDisplay()
+ ->setDisplayBrightness(brightness.sdrWhitePointNits,
+ brightness.displayBrightnessNits);
+ }
+ return getHwComposer().setDisplayBrightness(display->getPhysicalId(),
brightness.displayBrightness);
} else {
ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
@@ -2197,20 +2208,10 @@
mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
if (layer->isVisible() &&
compositionDisplay->belongsInOutput(layer->getCompositionEngineLayerFE())) {
- bool isHdr = false;
- switch (layer->getDataSpace()) {
- case ui::Dataspace::BT2020:
- case ui::Dataspace::BT2020_HLG:
- case ui::Dataspace::BT2020_PQ:
- case ui::Dataspace::BT2020_ITU:
- case ui::Dataspace::BT2020_ITU_HLG:
- case ui::Dataspace::BT2020_ITU_PQ:
- isHdr = true;
- break;
- default:
- isHdr = false;
- break;
- }
+ const Dataspace transfer =
+ static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
+ const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
+ transfer == Dataspace::TRANSFER_HLG);
if (isHdr) {
info.numberOfHdrLayers++;
@@ -5714,6 +5715,14 @@
}
}
+static bool hasCaptureBlackoutContentPermission() {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ return uid == AID_GRAPHICS || uid == AID_SYSTEM ||
+ PermissionCache::checkPermission(sCaptureBlackoutContent, pid, uid);
+}
+
static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
@@ -5884,6 +5893,10 @@
Rect layerStackSpaceRect;
ui::Dataspace dataspace;
bool captureSecureLayers;
+
+ // Call this before holding mStateLock to avoid any deadlocking.
+ bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
+
{
Mutex::Autolock lock(mStateLock);
@@ -5893,9 +5906,8 @@
return NAME_NOT_FOUND;
}
- const int uid = IPCThreadState::self()->getCallingUid();
- const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
- if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+ if (!canCaptureBlackoutContent &&
+ parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
@@ -6045,8 +6057,7 @@
return BAD_VALUE;
}
- const int uid = IPCThreadState::self()->getCallingUid();
- const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+ bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
if (mRefreshPending) {
@@ -6066,8 +6077,9 @@
status_t result = NO_ERROR;
renderArea->render([&] {
- result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem,
- regionSampling, grayscale, captureResults);
+ result = renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+ canCaptureBlackoutContent, regionSampling, grayscale,
+ captureResults);
});
captureResults.result = result;
@@ -6079,8 +6091,9 @@
status_t SurfaceFlinger::renderScreenImplLocked(
const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool forSystem,
- bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) {
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+ bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
+ ScreenCaptureResults& captureResults) {
ATRACE_CALL();
traverseLayers([&](Layer* layer) {
@@ -6093,7 +6106,7 @@
// We allow the system server to take screenshots of secure layers for
// use in situations like the Screen-rotation animation and place
// the impetus on WindowManager to not persist them.
- if (captureResults.capturedSecureLayers && !forSystem) {
+ if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
ALOGW("FB is protected: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
@@ -6433,13 +6446,17 @@
void SurfaceFlinger::onLayerFirstRef(Layer* layer) {
mNumLayers++;
- mScheduler->registerLayer(layer);
+ if (!layer->isRemovedFromCurrentState()) {
+ mScheduler->registerLayer(layer);
+ }
}
void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
- mScheduler->deregisterLayer(layer);
mNumLayers--;
removeFromOffscreenLayers(layer);
+ if (!layer->isRemovedFromCurrentState()) {
+ mScheduler->deregisterLayer(layer);
+ }
}
// WARNING: ONLY CALL THIS FROM LAYER DTOR
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ea40cb5..cb8d312 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -271,6 +271,10 @@
static constexpr SkipInitializationTag SkipInitialization;
+ // Whether or not SDR layers should be dimmed to the desired SDR white point instead of
+ // being treated as native display brightness
+ static bool enableSdrDimming;
+
// must be called before clients can connect
void init() ANDROID_API;
@@ -911,8 +915,8 @@
const sp<IScreenCaptureListener>&);
status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
const std::shared_ptr<renderengine::ExternalTexture>&,
- bool forSystem, bool regionSampling, bool grayscale,
- ScreenCaptureResults&);
+ bool canCaptureBlackoutContent, bool regionSampling,
+ bool grayscale, ScreenCaptureResults&);
sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index b3dca78..4a69c8f 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -321,6 +321,10 @@
return defaultValue;
}
+bool enable_sdr_dimming(bool defaultValue) {
+ return SurfaceFlingerProperties::enable_sdr_dimming().value_or(defaultValue);
+}
+
int32_t display_update_imminent_timeout_ms(int32_t defaultValue) {
auto temp = SurfaceFlingerProperties::display_update_imminent_timeout_ms();
if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index b19d216..039d316 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -102,6 +102,8 @@
bool enable_layer_caching(bool defaultValue);
+bool enable_sdr_dimming(bool defaultValue);
+
} // namespace sysprop
} // namespace android
#endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 10d58a6..d6a0787 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -351,12 +351,16 @@
std::max(mTimeStats.displayEventConnectionsCountLegacy, count);
}
+static int32_t toMs(nsecs_t nanos) {
+ int64_t millis =
+ std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(nanos))
+ .count();
+ millis = std::clamp(millis, int64_t(INT32_MIN), int64_t(INT32_MAX));
+ return static_cast<int32_t>(millis);
+}
+
static int32_t msBetween(nsecs_t start, nsecs_t end) {
- int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::nanoseconds(end - start))
- .count();
- delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
- return static_cast<int32_t>(delta);
+ return toMs(end - start);
}
void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
@@ -829,10 +833,9 @@
// TimeStats Histograms only retain positive values, so we don't need to check if these
// deadlines were really missed if we know that the frame had jank, since deadlines
// that were met will be dropped.
- timelineStats.displayDeadlineDeltas.insert(static_cast<int32_t>(info.displayDeadlineDelta));
- timelineStats.displayPresentDeltas.insert(static_cast<int32_t>(info.displayPresentJitter));
- timeStatsLayer.deltas["appDeadlineDeltas"].insert(
- static_cast<int32_t>(info.appDeadlineDelta));
+ timelineStats.displayDeadlineDeltas.insert(toMs(info.displayDeadlineDelta));
+ timelineStats.displayPresentDeltas.insert(toMs(info.displayPresentJitter));
+ timeStatsLayer.deltas["appDeadlineDeltas"].insert(toMs(info.appDeadlineDelta));
}
}
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index ee5542d..78f8a2f 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -463,3 +463,12 @@
access: Readonly
prop_name: "ro.surface_flinger.enable_layer_caching"
}
+
+# Enables SDR layer dimming
+prop {
+ api_name: "enable_sdr_dimming"
+ type: Boolean
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.enable_sdr_dimming"
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 47e14f6..9c567d6 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -53,6 +53,10 @@
prop_name: "ro.surface_flinger.protected_contents"
}
prop {
+ api_name: "enable_sdr_dimming"
+ prop_name: "ro.surface_flinger.enable_sdr_dimming"
+ }
+ prop {
api_name: "force_hwc_copy_for_virtual_displays"
prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
}
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 4753362..34c9182 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -19,6 +19,7 @@
#pragma clang diagnostic ignored "-Wconversion"
#include <gui/BufferItemConsumer.h>
+#include <private/android_filesystem_config.h>
#include "TransactionTestHarnesses.h"
namespace android {
@@ -170,7 +171,11 @@
args.displayToken = mDisplay;
ScreenCaptureResults captureResults;
- ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
+ {
+ // Ensure the UID is not root because root has all permissions
+ UIDFaker f(AID_APP_START);
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
+ }
Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, captureResults));
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 2e9c10c..6912fcf 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -84,7 +84,11 @@
Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true);
- ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
+ {
+ // Ensure the UID is not root because root has all permissions
+ UIDFaker f(AID_APP_START);
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
+ }
UIDFaker f(AID_SYSTEM);
@@ -528,7 +532,7 @@
ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
}
-TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
+TEST_F(ScreenCaptureTest, CaptureSecureLayer) {
sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
ISurfaceComposerClient::eFXSurfaceBufferState);
sp<SurfaceControl> secureLayer =
@@ -552,8 +556,12 @@
args.childrenOnly = false;
ScreenCaptureResults captureResults;
- // Call from outside system with secure layers will result in permission denied
- ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
+ {
+ // Ensure the UID is not root because root has all permissions
+ UIDFaker f(AID_APP_START);
+ // Call from outside system with secure layers will result in permission denied
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
+ }
UIDFaker f(AID_SYSTEM);
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index ff53a7b..3e4e130 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -1011,6 +1011,9 @@
constexpr size_t MISSED_FRAMES = 4;
constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
+ constexpr nsecs_t DISPLAY_DEADLINE_DELTA = 1'000'000;
+ constexpr nsecs_t DISPLAY_PRESENT_JITTER = 2'000'000;
+ constexpr nsecs_t APP_DEADLINE_DELTA = 3'000'000;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -1036,24 +1039,35 @@
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ JankType::SurfaceFlingerCpuDeadlineMissed,
+ DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
+ APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ JankType::SurfaceFlingerGpuDeadlineMissed,
+ DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
+ APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::DisplayHAL, 1, 2, 3});
+ JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed, 1, 2, 3});
+ JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerScheduling, 1, 2, 3});
+ JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::PredictionError, 1, 2, 3});
+ JankType::PredictionError, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
- 3});
+ JankType::AppDeadlineMissed | JankType::BufferStuffing,
+ DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
+ APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::BufferStuffing, 1, 2, 3});
+ JankType::BufferStuffing, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::None, 1, 2, 3});
+ JankType::None, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA});
std::string pulledData;
EXPECT_TRUE(mTimeStats->onPullAtom(10062 /*SURFACEFLINGER_STATS_GLOBAL_INFO*/, &pulledData));
@@ -1137,6 +1151,10 @@
TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
constexpr size_t LATE_ACQUIRE_FRAMES = 2;
constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
+ constexpr nsecs_t DISPLAY_DEADLINE_DELTA = 1'000'000;
+ constexpr nsecs_t DISPLAY_PRESENT_JITTER = 2'000'000;
+ constexpr nsecs_t APP_DEADLINE_DELTA_2MS = 2'000'000;
+ constexpr nsecs_t APP_DEADLINE_DELTA_3MS = 3'000'000;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
@@ -1155,22 +1173,32 @@
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000, frameRate60);
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerCpuDeadlineMissed, 1, 2, 3});
+ JankType::SurfaceFlingerCpuDeadlineMissed,
+ DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
+ APP_DEADLINE_DELTA_3MS});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerGpuDeadlineMissed, 1, 2, 3});
+ JankType::SurfaceFlingerGpuDeadlineMissed,
+ DISPLAY_DEADLINE_DELTA, DISPLAY_PRESENT_JITTER,
+ APP_DEADLINE_DELTA_3MS});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::DisplayHAL, 1, 2, 3});
+ JankType::DisplayHAL, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed, 1, 2, 3});
+ JankType::AppDeadlineMissed, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::SurfaceFlingerScheduling, 1, 2, 2});
+ JankType::SurfaceFlingerScheduling, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::PredictionError, 1, 2, 2});
+ JankType::PredictionError, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_2MS});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::AppDeadlineMissed | JankType::BufferStuffing, 1, 2,
- 2});
+ JankType::AppDeadlineMissed | JankType::BufferStuffing,
+ DISPLAY_DEADLINE_DELTA, APP_DEADLINE_DELTA_2MS,
+ APP_DEADLINE_DELTA_2MS});
mTimeStats->incrementJankyFrames({kRefreshRate0, kRenderRate0, UID_0, genLayerName(LAYER_ID_0),
- JankType::None, 1, 2, 3});
+ JankType::None, DISPLAY_DEADLINE_DELTA,
+ DISPLAY_PRESENT_JITTER, APP_DEADLINE_DELTA_3MS});
std::string pulledData;
EXPECT_TRUE(mTimeStats->onPullAtom(10063 /*SURFACEFLINGER_STATS_LAYER_INFO*/, &pulledData));