Merge "Add mm_event trace events to the atrace 'memory' category" into rvc-dev
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 1af6edd..5ee6a9f 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -374,6 +374,14 @@
bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
vold_decrypt == "1";
+ std::string updatable_bcp_packages =
+ MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
+ "--updatable-bcp-packages-file=%s");
+ if (updatable_bcp_packages.empty()) {
+ // Make dex2oat fail by providing non-existent file name.
+ updatable_bcp_packages = "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
+ }
+
std::string resolve_startup_string_arg =
MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
"--resolve-startup-const-strings=%s");
@@ -520,6 +528,7 @@
AddRuntimeArg(dex2oat_Xms_arg);
AddRuntimeArg(dex2oat_Xmx_arg);
+ AddArg(updatable_bcp_packages);
AddArg(resolve_startup_string_arg);
AddArg(image_block_size_arg);
AddArg(dex2oat_compiler_filter_arg);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 3ee8187..c7b7551 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -40,7 +40,7 @@
},
srcs: ["binderDriverInterfaceTest.cpp"],
- test_suites: ["device-tests", "vts-core"],
+ test_suites: ["device-tests", "vts"],
}
cc_test {
@@ -69,7 +69,7 @@
"libbinder",
"libutils",
],
- test_suites: ["device-tests", "vts-core"],
+ test_suites: ["device-tests", "vts"],
require_root: true,
}
@@ -131,7 +131,7 @@
"liblog",
"libutils",
],
- test_suites: ["device-tests", "vts-core"],
+ test_suites: ["device-tests", "vts"],
require_root: true,
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 8d79cf8..bd4d62c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1145,6 +1145,42 @@
ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err);
return err;
}
+
+ return reply.readInt32();
+ }
+
+ virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) {
+ if (!outToken) return BAD_VALUE;
+
+ Parcel data, reply;
+ status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ ALOGE("acquireFrameRateFlexibilityToken: failed writing interface token: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ err = remote()->transact(BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, data,
+ &reply);
+ if (err != NO_ERROR) {
+ ALOGE("acquireFrameRateFlexibilityToken: failed to transact: %s (%d)", strerror(-err),
+ err);
+ return err;
+ }
+
+ err = reply.readInt32();
+ if (err != NO_ERROR) {
+ ALOGE("acquireFrameRateFlexibilityToken: call failed: %s (%d)", strerror(-err), err);
+ return err;
+ }
+
+ err = reply.readStrongBinder(outToken);
+ if (err != NO_ERROR) {
+ ALOGE("acquireFrameRateFlexibilityToken: failed reading binder token: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+
return NO_ERROR;
}
};
@@ -1945,6 +1981,16 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> token;
+ status_t result = acquireFrameRateFlexibilityToken(&token);
+ reply->writeInt32(result);
+ if (result == NO_ERROR) {
+ reply->writeStrongBinder(token);
+ }
+ return NO_ERROR;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 09487ea..3cef256 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -508,6 +508,14 @@
*/
virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility) = 0;
+
+ /*
+ * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired,
+ * surface flinger will freely switch between frame rates in any way it sees fit, regardless of
+ * the current restrictions applied by DisplayManager. This is useful to get consistent behavior
+ * for tests. Release the token by releasing the returned IBinder reference.
+ */
+ virtual status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) = 0;
};
// ----------------------------------------------------------------------------
@@ -566,6 +574,7 @@
GET_GAME_CONTENT_TYPE_SUPPORT,
SET_GAME_CONTENT_TYPE,
SET_FRAME_RATE,
+ ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
// Always append new enum to the end.
};
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8c0f8f8..ef1fd02 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -859,6 +859,8 @@
return NO_ERROR;
}
+ status_t acquireFrameRateFlexibilityToken(sp<IBinder>* /*outToken*/) { return NO_ERROR; }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 106efd6..1622e77 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -93,6 +93,23 @@
return nullptr;
}
+void SensorService::SensorDirectConnection::updateSensorSubscriptions() {
+ if (!hasSensorAccess()) {
+ stopAll(true /* backupRecord */);
+ } else {
+ recoverAll();
+ }
+}
+
+void SensorService::SensorDirectConnection::setSensorAccess(bool hasAccess) {
+ mHasSensorAccess = hasAccess;
+ updateSensorSubscriptions();
+}
+
+bool SensorService::SensorDirectConnection::hasSensorAccess() const {
+ return mHasSensorAccess && !mService->mSensorPrivacyPolicy->isSensorPrivacyEnabled();
+}
+
status_t SensorService::SensorDirectConnection::enableDisable(
int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
int reservedFlags) {
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index ead08d3..fa88fbc 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -54,6 +54,9 @@
// called by SensorService when return to NORMAL mode.
void recoverAll();
+ void updateSensorSubscriptions();
+
+ void setSensorAccess(bool hasAccess);
protected:
virtual ~SensorDirectConnection();
// ISensorEventConnection functions
@@ -66,6 +69,7 @@
virtual int32_t configureChannel(int handle, int rateLevel);
virtual void destroy();
private:
+ bool hasSensorAccess() const;
const sp<SensorService> mService;
const uid_t mUid;
const sensors_direct_mem_t mMem;
@@ -76,6 +80,8 @@
std::unordered_map<int, int> mActivated;
std::unordered_map<int, int> mActivatedBackup;
+ std::atomic_bool mHasSensorAccess = true;
+
mutable Mutex mDestroyLock;
bool mDestroyed;
};
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 77d8c11..5be4ccd 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -70,17 +70,16 @@
}
bool SensorService::SensorEventConnection::needsWakeLock() {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
return !mDead && mWakeLockRefCount > 0;
}
void SensorService::SensorEventConnection::resetWakeLockRefCount() {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
mWakeLockRefCount = 0;
}
void SensorService::SensorEventConnection::dump(String8& result) {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
result.appendFormat("\tOperating Mode: ");
if (!mService->isWhiteListedPackage(getPackageName())) {
result.append("RESTRICTED\n");
@@ -92,6 +91,8 @@
result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
"max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
mMaxCacheSize);
+
+ std::lock_guard<std::mutex> _l(mConnectionLock);
for (auto& it : mSensorInfo) {
const FlushInfo& flushInfo = it.second.flushInfo;
result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n",
@@ -122,7 +123,7 @@
*/
void SensorService::SensorEventConnection::dump(util::ProtoOutputStream* proto) const {
using namespace service::SensorEventConnectionProto;
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
if (!mService->isWhiteListedPackage(getPackageName())) {
proto->write(OPERATING_MODE, OP_MODE_RESTRICTED);
@@ -160,7 +161,7 @@
bool SensorService::SensorEventConnection::addSensor(
int32_t handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
if (si == nullptr ||
!canAccessSensor(si->getSensor(), "Tried adding", mOpPackageName) ||
@@ -179,12 +180,12 @@
}
bool SensorService::SensorEventConnection::removeSensor(int32_t handle) {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
return mSensorInfo.erase(handle) > 0;
}
std::vector<int32_t> SensorService::SensorEventConnection::getActiveSensorHandles() const {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
std::vector<int32_t> list;
for (auto& it : mSensorInfo) {
list.push_back(it.first);
@@ -193,17 +194,19 @@
}
bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::recursive_mutex> _backlock(mBackupLock);
+ std::lock_guard<std::mutex> _lock(mConnectionLock);
return mSensorInfo.count(handle) + mSensorInfoBackup.count(handle) > 0;
}
bool SensorService::SensorEventConnection::hasAnySensor() const {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::recursive_mutex> _backlock(mBackupLock);
+ std::lock_guard<std::mutex> _lock(mConnectionLock);
return mSensorInfo.size() + mSensorInfoBackup.size() ? true : false;
}
bool SensorService::SensorEventConnection::hasOneShotSensors() const {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
for (auto &it : mSensorInfo) {
const int handle = it.first;
sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
@@ -220,7 +223,7 @@
void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle,
bool value) {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
if (mSensorInfo.count(handle) > 0) {
FlushInfo& flushInfo = mSensorInfo[handle].flushInfo;
flushInfo.mFirstFlushPending = value;
@@ -228,7 +231,7 @@
}
void SensorService::SensorEventConnection::updateLooperRegistration(const sp<Looper>& looper) {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
updateLooperRegistrationLocked(looper);
}
@@ -279,7 +282,7 @@
}
void SensorService::SensorEventConnection::incrementPendingFlushCount(int32_t handle) {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
if (mSensorInfo.count(handle) > 0) {
FlushInfo& flushInfo = mSensorInfo[handle].flushInfo;
flushInfo.mPendingFlushEventsToSend++;
@@ -295,7 +298,7 @@
std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
int count = 0;
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
if (scratch) {
size_t i=0;
while (i<numEvents) {
@@ -453,11 +456,18 @@
}
void SensorService::SensorEventConnection::stopAll() {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
- if (!mSensorInfo.empty()) {
- mSensorInfoBackup = mSensorInfo;
- mSensorInfo.clear();
+ bool backupPerformed = false;
+ std::lock_guard<std::recursive_mutex> _backlock(mBackupLock);
+ {
+ std::lock_guard<std::mutex> _lock(mConnectionLock);
+ if (!mSensorInfo.empty()) {
+ mSensorInfoBackup = mSensorInfo;
+ mSensorInfo.clear();
+ backupPerformed = true;
+ }
+ }
+ if (backupPerformed) {
for (auto& it : mSensorInfoBackup) {
int32_t handle = it.first;
@@ -471,7 +481,7 @@
}
void SensorService::SensorEventConnection::recoverAll() {
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::recursive_mutex> _l(mBackupLock);
for (auto& it : mSensorInfoBackup) {
int32_t handle = it.first;
SensorRequest &request = it.second;
@@ -612,7 +622,7 @@
// half the size of the socket buffer allocated in BitTube whichever is smaller.
const int maxWriteSize = helpers::min(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT/2,
int(mService->mSocketBufferSize/(sizeof(sensors_event_t)*2)));
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
// Send pending flush complete events (if any)
sendPendingFlushEventsLocked();
for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
@@ -724,7 +734,7 @@
{
status_t err = mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
if (err == NO_ERROR && mSensorInfo.count(handle) > 0) {
mSensorInfo[handle].samplingPeriodNs = samplingPeriodNs;
}
@@ -750,7 +760,7 @@
// and remove the fd from Looper. Call checkWakeLockState to know if SensorService
// can release the wake-lock.
ALOGD_IF(DEBUG_CONNECTIONS, "%p Looper error %d", this, fd);
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
mDead = true;
mWakeLockRefCount = 0;
updateLooperRegistrationLocked(mService->getLooper());
@@ -769,7 +779,7 @@
unsigned char buf[sizeof(sensors_event_t)];
ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
{
- std::lock_guard<std::recursive_mutex> _l(mConnectionLock);
+ std::lock_guard<std::mutex> _l(mConnectionLock);
if (numBytesRead == sizeof(sensors_event_t)) {
if (!mDataInjectionMode) {
ALOGE("Data injected in normal mode, dropping event"
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 3ba5c07..80e7431 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -146,7 +146,13 @@
sp<SensorService> const mService;
sp<BitTube> mChannel;
uid_t mUid;
- mutable std::recursive_mutex mConnectionLock;
+
+ // A lock that should be used when modifying mSensorInfo
+ mutable std::mutex mConnectionLock;
+
+ // A lock that should be used when modifying mSensorInfoBackup
+ mutable std::recursive_mutex mBackupLock;
+
// Number of events from wake up sensors which are still pending and haven't been delivered to
// the corresponding application. It is incremented by one unit for each write to the socket.
uint32_t mWakeLockRefCount;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 5ae7c51..29df825 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -302,6 +302,7 @@
void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
const auto& connections = connLock.getActiveConnections();
+ const auto& directConnections = connLock.getDirectConnections();
mLock.unlock();
for (const sp<SensorEventConnection>& conn : connections) {
@@ -309,6 +310,15 @@
conn->setSensorAccess(hasAccess);
}
}
+
+ for (const sp<SensorDirectConnection>& conn : directConnections) {
+ if (conn->getUid() == uid) {
+ conn->setSensorAccess(hasAccess);
+ }
+ }
+
+ // Lock the mutex again for clean shutdown
+ mLock.lock();
}
const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) {
@@ -645,7 +655,7 @@
connection->updateSensorSubscriptions();
}
for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
- connection->stopAll(true /* backupRecord */);
+ connection->updateSensorSubscriptions();
}
dev.disableAllSensors();
// Clear all pending flush connections for all active sensors. If one of the active
@@ -676,7 +686,7 @@
connection->updateSensorSubscriptions();
}
for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
- connection->recoverAll();
+ connection->updateSensorSubscriptions();
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3d67a6b..5039761 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2134,10 +2134,12 @@
writeToProtoDrawingState(layerProto, traceFlags);
writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
- // Only populate for the primary display.
- if (device) {
- const Hwc2::IComposerClient::Composition compositionType = getCompositionType(device);
- layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+ if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) {
+ // Only populate for the primary display.
+ if (device) {
+ const Hwc2::IComposerClient::Composition compositionType = getCompositionType(device);
+ layerProto->set_hwc_composition_type(static_cast<HwcCompositionType>(compositionType));
+ }
}
for (const sp<Layer>& layer : mDrawingChildren) {
@@ -2180,8 +2182,10 @@
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
- LayerProtoHelper::writeToProto(debugGetVisibleRegionOnDefaultDisplay(),
- [&]() { return layerInfo->mutable_visible_region(); });
+ if (traceFlags & SurfaceTracing::TRACE_COMPOSITION) {
+ LayerProtoHelper::writeToProto(debugGetVisibleRegionOnDefaultDisplay(),
+ [&]() { return layerInfo->mutable_visible_region(); });
+ }
LayerProtoHelper::writeToProto(surfaceDamageRegion,
[&]() { return layerInfo->mutable_damage_region(); });
@@ -2191,15 +2195,13 @@
}
}
- if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
- LayerProtoHelper::writeToProto(mSourceBounds,
- [&]() { return layerInfo->mutable_source_bounds(); });
- LayerProtoHelper::writeToProto(mScreenBounds,
- [&]() { return layerInfo->mutable_screen_bounds(); });
- LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect,
- [&]() { return layerInfo->mutable_corner_radius_crop(); });
- layerInfo->set_shadow_radius(mEffectiveShadowRadius);
- }
+ LayerProtoHelper::writeToProto(mSourceBounds,
+ [&]() { return layerInfo->mutable_source_bounds(); });
+ LayerProtoHelper::writeToProto(mScreenBounds,
+ [&]() { return layerInfo->mutable_screen_bounds(); });
+ LayerProtoHelper::writeToProto(getRoundedCornerState().cropRect,
+ [&]() { return layerInfo->mutable_corner_radius_crop(); });
+ layerInfo->set_shadow_radius(mEffectiveShadowRadius);
}
void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 02d0b53..14ef733 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -301,7 +301,7 @@
mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
return *mCurrentRefreshRate;
}
- return *mRefreshRates.at(mDefaultConfig);
+ return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
}
void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
@@ -326,38 +326,59 @@
init(inputConfigs, currentConfigId);
}
-status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
- float maxRefreshRate, bool* outPolicyChanged) {
+bool RefreshRateConfigs::isPolicyValid(const Policy& policy) {
+ // defaultConfig must be a valid config, and within the given refresh rate range.
+ auto iter = mRefreshRates.find(policy.defaultConfig);
+ if (iter == mRefreshRates.end()) {
+ return false;
+ }
+ const RefreshRate& refreshRate = *iter->second;
+ if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) {
+ return false;
+ }
+ return true;
+}
+
+status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
std::lock_guard lock(mLock);
- bool policyChanged = defaultConfigId != mDefaultConfig ||
- minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps;
- if (outPolicyChanged) {
- *outPolicyChanged = policyChanged;
- }
- if (!policyChanged) {
- return NO_ERROR;
- }
- // defaultConfigId must be a valid config ID, and within the given refresh rate range.
- if (mRefreshRates.count(defaultConfigId) == 0) {
+ if (!isPolicyValid(policy)) {
return BAD_VALUE;
}
- const RefreshRate& refreshRate = *mRefreshRates.at(defaultConfigId);
- if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) {
- return BAD_VALUE;
+ Policy previousPolicy = *getCurrentPolicyLocked();
+ mDisplayManagerPolicy = policy;
+ if (*getCurrentPolicyLocked() == previousPolicy) {
+ return CURRENT_POLICY_UNCHANGED;
}
- mDefaultConfig = defaultConfigId;
- mMinRefreshRateFps = minRefreshRate;
- mMaxRefreshRateFps = maxRefreshRate;
constructAvailableRefreshRates();
return NO_ERROR;
}
-void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
- float* maxRefreshRate) const {
+status_t RefreshRateConfigs::setOverridePolicy(const std::optional<Policy>& policy) {
std::lock_guard lock(mLock);
- *defaultConfigId = mDefaultConfig;
- *minRefreshRate = mMinRefreshRateFps;
- *maxRefreshRate = mMaxRefreshRateFps;
+ if (policy && !isPolicyValid(*policy)) {
+ return BAD_VALUE;
+ }
+ Policy previousPolicy = *getCurrentPolicyLocked();
+ mOverridePolicy = policy;
+ if (*getCurrentPolicyLocked() == previousPolicy) {
+ return CURRENT_POLICY_UNCHANGED;
+ }
+ constructAvailableRefreshRates();
+ return NO_ERROR;
+}
+
+const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const {
+ return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy;
+}
+
+RefreshRateConfigs::Policy RefreshRateConfigs::getCurrentPolicy() const {
+ std::lock_guard lock(mLock);
+ return *getCurrentPolicyLocked();
+}
+
+RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const {
+ std::lock_guard lock(mLock);
+ return mDisplayManagerPolicy;
}
bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
@@ -385,19 +406,25 @@
std::sort(outRefreshRates->begin(), outRefreshRates->end(),
[](const auto refreshRate1, const auto refreshRate2) {
- return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
+ if (refreshRate1->vsyncPeriod != refreshRate2->vsyncPeriod) {
+ return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
+ } else {
+ return refreshRate1->configGroup > refreshRate2->configGroup;
+ }
});
}
void RefreshRateConfigs::constructAvailableRefreshRates() {
// Filter configs based on current policy and sort based on vsync period
- HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig)->configGroup;
+ const Policy* policy = getCurrentPolicyLocked();
+ HwcConfigGroupType group = mRefreshRates.at(policy->defaultConfig)->configGroup;
ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
- mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
+ policy->defaultConfig.value(), group.value(), policy->minRefreshRate,
+ policy->maxRefreshRate);
getSortedRefreshRateList(
[&](const RefreshRate& refreshRate) REQUIRES(mLock) {
- return refreshRate.configGroup == group &&
- refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps);
+ return (policy->allowGroupSwitching || refreshRate.configGroup == group) &&
+ refreshRate.inPolicy(policy->minRefreshRate, policy->maxRefreshRate);
},
&mAvailableRefreshRates);
@@ -409,7 +436,8 @@
ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
"No compatible display configs for default=%d min=%.0f max=%.0f",
- mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps);
+ policy->defaultConfig.value(), policy->minRefreshRate,
+ policy->maxRefreshRate);
}
// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor
@@ -432,7 +460,7 @@
std::vector<const RefreshRate*> sortedConfigs;
getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs);
- mDefaultConfig = currentHwcConfig;
+ mDisplayManagerPolicy.defaultConfig = currentHwcConfig;
mMinSupportedRefreshRate = sortedConfigs.front();
mMaxSupportedRefreshRate = sortedConfigs.back();
constructAvailableRefreshRates();
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 87d4389..e749f8f 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -20,6 +20,7 @@
#include <algorithm>
#include <numeric>
+#include <optional>
#include <type_traits>
#include "DisplayHardware/HWComposer.h"
@@ -90,14 +91,47 @@
using AllRefreshRatesMapType =
std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
- // Sets the current policy to choose refresh rates. Returns NO_ERROR if the requested policy is
- // valid, or a negative error value otherwise. policyChanged, if non-null, will be set to true
- // if the new policy is different from the old policy.
- status_t setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate,
- float maxRefreshRate, bool* policyChanged) EXCLUDES(mLock);
- // Gets the current policy.
- void getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate,
- float* maxRefreshRate) const EXCLUDES(mLock);
+ struct Policy {
+ // The default config, used to ensure we only initiate display config switches within the
+ // same config group as defaultConfigId's group.
+ HwcConfigIndexType defaultConfig;
+ // The min and max FPS allowed by the policy.
+ float minRefreshRate = 0;
+ float maxRefreshRate = std::numeric_limits<float>::max();
+ // Whether or not we switch config groups to get the best frame rate. Only used by tests.
+ bool allowGroupSwitching = false;
+
+ bool operator==(const Policy& other) const {
+ return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate &&
+ maxRefreshRate == other.maxRefreshRate &&
+ allowGroupSwitching == other.allowGroupSwitching;
+ }
+
+ bool operator!=(const Policy& other) const { return !(*this == other); }
+ };
+
+ // Return code set*Policy() to indicate the current policy is unchanged.
+ static constexpr int CURRENT_POLICY_UNCHANGED = 1;
+
+ // We maintain the display manager policy and the override policy separately. The override
+ // policy is used by CTS tests to get a consistent device state for testing. While the override
+ // policy is set, it takes precedence over the display manager policy. Once the override policy
+ // is cleared, we revert to using the display manager policy.
+
+ // Sets the display manager policy to choose refresh rates. The return value will be:
+ // - A negative value if the policy is invalid or another error occurred.
+ // - NO_ERROR if the policy was successfully updated, and the current policy is different from
+ // what it was before the call.
+ // - CURRENT_POLICY_UNCHANGED if the policy was successfully updated, but the current policy
+ // is the same as it was before the call.
+ status_t setDisplayManagerPolicy(const Policy& policy) EXCLUDES(mLock);
+ // Sets the override policy. See setDisplayManagerPolicy() for the meaning of the return value.
+ status_t setOverridePolicy(const std::optional<Policy>& policy) EXCLUDES(mLock);
+ // Gets the current policy, which will be the override policy if active, and the display manager
+ // policy otherwise.
+ Policy getCurrentPolicy() const EXCLUDES(mLock);
+ // Gets the display manager policy, regardless of whether an override policy is active.
+ Policy getDisplayManagerPolicy() const EXCLUDES(mLock);
// Returns true if config is allowed by the current policy.
bool isConfigAllowed(HwcConfigIndexType config) const EXCLUDES(mLock);
@@ -208,6 +242,9 @@
// the policy.
const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);
+ const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
+ bool isPolicyValid(const Policy& policy);
+
// The list of refresh rates, indexed by display config ID. This must not change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
@@ -220,14 +257,10 @@
// the main thread, and read by the Scheduler (and other objects) on other threads.
const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock);
- // The default config. This will change at runtime. This is set by SurfaceFlinger on
- // the main thread, and read by the Scheduler (and other objects) on other threads.
- HwcConfigIndexType mDefaultConfig GUARDED_BY(mLock);
-
- // The min and max FPS allowed by the policy. This will change at runtime and set by
- // SurfaceFlinger on the main thread.
- float mMinRefreshRateFps GUARDED_BY(mLock) = 0;
- float mMaxRefreshRateFps GUARDED_BY(mLock) = std::numeric_limits<float>::max();
+ // The policy values will change at runtime. They're set by SurfaceFlinger on the main thread,
+ // and read by the Scheduler (and other objects) on other threads.
+ Policy mDisplayManagerPolicy GUARDED_BY(mLock);
+ std::optional<Policy> mOverridePolicy GUARDED_BY(mLock);
// The min and max refresh rates supported by the device.
// This will not change at runtime.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dd2be7c..4ceac4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -200,6 +200,15 @@
return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
}
+class FrameRateFlexibilityToken : public BBinder {
+public:
+ FrameRateFlexibilityToken(std::function<void()> callback) : mCallback(callback) {}
+ virtual ~FrameRateFlexibilityToken() { mCallback(); }
+
+private:
+ std::function<void()> mCallback;
+};
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -977,8 +986,11 @@
} else {
HwcConfigIndexType config(mode);
const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(config);
- result = setDesiredDisplayConfigSpecsInternal(display, config, refreshRate.fps,
- refreshRate.fps);
+ result = setDesiredDisplayConfigSpecsInternal(display,
+ scheduler::RefreshRateConfigs::
+ Policy{config, refreshRate.fps,
+ refreshRate.fps},
+ /*overridePolicy=*/false);
}
}));
@@ -1935,8 +1947,18 @@
// potentially trigger a display handoff.
updateVrFlinger();
- bool refreshNeeded = handleMessageTransaction();
- refreshNeeded |= handleMessageInvalidate();
+ bool refreshNeeded;
+ withTracingLock([&]() {
+ refreshNeeded = handleMessageTransaction();
+ refreshNeeded |= handleMessageInvalidate();
+ if (mTracingEnabled) {
+ mAddCompositionStateToTrace =
+ mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
+ if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
+ mTracing.notifyLocked("visibleRegionsDirty");
+ }
+ }
+ });
// Layers need to get updated (in the previous line) before we can use them for
// choosing the refresh rate.
@@ -2080,7 +2102,7 @@
mLayersWithQueuedFrames.clear();
if (mVisibleRegionsDirty) {
mVisibleRegionsDirty = false;
- if (mTracingEnabled) {
+ if (mTracingEnabled && mAddCompositionStateToTrace) {
mTracing.notify("visibleRegionsDirty");
}
}
@@ -2962,8 +2984,7 @@
void SurfaceFlinger::commitTransaction()
{
- withTracingLock([this]() { commitTransactionLocked(); });
-
+ commitTransactionLocked();
mTransactionPending = false;
mAnimTransactionPending = false;
mTransactionCV.broadcast();
@@ -3496,12 +3517,13 @@
return flags;
}
-bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess() {
+bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache) {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
const int uid = ipc->getCallingUid();
if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) &&
- !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
+ (usePermissionCache ? !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)
+ : !checkPermission(sAccessSurfaceFlinger, pid, uid))) {
return false;
}
return true;
@@ -4373,13 +4395,11 @@
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriod());
- HwcConfigIndexType defaultConfig;
- float minFps, maxFps;
- mRefreshRateConfigs->getPolicy(&defaultConfig, &minFps, &maxFps);
+ scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
StringAppendF(&result,
"DesiredDisplayConfigSpecs: default config ID: %d"
", min: %.2f Hz, max: %.2f Hz",
- defaultConfig.value(), minFps, maxFps);
+ policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate);
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
@@ -4818,8 +4838,12 @@
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
case GET_DISPLAYED_CONTENT_SAMPLE:
case NOTIFY_POWER_HINT:
- case SET_GLOBAL_SHADOW_SETTINGS: {
- if (!callingThreadHasUnscopedSurfaceFlingerAccess()) {
+ case SET_GLOBAL_SHADOW_SETTINGS:
+ case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
+ // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the
+ // necessary permission dynamically. Don't use the permission cache for this check.
+ bool usePermissionCache = code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN;
+ if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
IPCThreadState* ipc = IPCThreadState::self();
ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
ipc->getCallingPid(), ipc->getCallingUid());
@@ -5908,12 +5932,15 @@
}
}
-status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp<DisplayDevice>& display,
- HwcConfigIndexType defaultConfig,
- float minRefreshRate,
- float maxRefreshRate) {
+status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(
+ const sp<DisplayDevice>& display,
+ const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
Mutex::Autolock lock(mStateLock);
+ LOG_ALWAYS_FATAL_IF(!display->isPrimary() && overridePolicy,
+ "Can only set override policy on the primary display");
+ LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy");
+
if (!display->isPrimary()) {
// TODO(b/144711714): For non-primary displays we should be able to set an active config
// as well. For now, just call directly to setActiveConfigWithConstraints but ideally
@@ -5927,7 +5954,8 @@
constraints.seamlessRequired = false;
HWC2::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
- if (getHwComposer().setActiveConfigWithConstraints(*displayId, defaultConfig.value(),
+ if (getHwComposer().setActiveConfigWithConstraints(*displayId,
+ policy->defaultConfig.value(),
constraints, &timeline) < 0) {
return BAD_VALUE;
}
@@ -5935,11 +5963,12 @@
repaintEverythingForHWC();
}
- display->setActiveConfig(defaultConfig);
- const nsecs_t vsyncPeriod =
- getHwComposer().getConfigs(*displayId)[defaultConfig.value()]->getVsyncPeriod();
- mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, defaultConfig,
- vsyncPeriod);
+ display->setActiveConfig(policy->defaultConfig);
+ const nsecs_t vsyncPeriod = getHwComposer()
+ .getConfigs(*displayId)[policy->defaultConfig.value()]
+ ->getVsyncPeriod();
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
+ policy->defaultConfig, vsyncPeriod);
return NO_ERROR;
}
@@ -5948,17 +5977,20 @@
return NO_ERROR;
}
- bool policyChanged;
- if (mRefreshRateConfigs->setPolicy(defaultConfig, minRefreshRate, maxRefreshRate,
- &policyChanged) < 0) {
+ status_t setPolicyResult = overridePolicy
+ ? mRefreshRateConfigs->setOverridePolicy(policy)
+ : mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
+ if (setPolicyResult < 0) {
return BAD_VALUE;
}
- if (!policyChanged) {
+ if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) {
return NO_ERROR;
}
+ scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f",
- defaultConfig.value(), minRefreshRate, maxRefreshRate);
+ currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
+ currentPolicy.maxRefreshRate);
// TODO(b/140204874): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
@@ -5972,7 +6004,7 @@
auto& preferredRefreshRate = configId
? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
// NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
- : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig);
+ : mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig);
ALOGV("trying to switch to Scheduler preferred config %d (%s)",
preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str());
@@ -6007,9 +6039,13 @@
result = BAD_VALUE;
ALOGW("Attempt to set desired display configs for virtual display");
} else {
- result =
- setDesiredDisplayConfigSpecsInternal(display, HwcConfigIndexType(defaultConfig),
- minRefreshRate, maxRefreshRate);
+ result = setDesiredDisplayConfigSpecsInternal(display,
+ scheduler::RefreshRateConfigs::
+ Policy{HwcConfigIndexType(
+ defaultConfig),
+ minRefreshRate,
+ maxRefreshRate},
+ /*overridePolicy=*/false);
}
}));
@@ -6033,9 +6069,11 @@
}
if (display->isPrimary()) {
- HwcConfigIndexType defaultConfig;
- mRefreshRateConfigs->getPolicy(&defaultConfig, outMinRefreshRate, outMaxRefreshRate);
- *outDefaultConfig = defaultConfig.value();
+ scheduler::RefreshRateConfigs::Policy policy =
+ mRefreshRateConfigs->getDisplayManagerPolicy();
+ *outDefaultConfig = policy.defaultConfig.value();
+ *outMinRefreshRate = policy.minRefreshRate;
+ *outMaxRefreshRate = policy.maxRefreshRate;
return NO_ERROR;
} else if (display->isVirtual()) {
return BAD_VALUE;
@@ -6155,6 +6193,68 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) {
+ if (!outToken) {
+ return BAD_VALUE;
+ }
+ status_t result = NO_ERROR;
+ postMessageSync(new LambdaMessage([&]() {
+ if (mFrameRateFlexibilityTokenCount == 0) {
+ // |mStateLock| not needed as we are on the main thread
+ const auto display = getDefaultDisplayDeviceLocked();
+
+ // This is a little racy, but not in a way that hurts anything. As we grab the
+ // defaultConfig from the display manager policy, we could be setting a new display
+ // manager policy, leaving us using a stale defaultConfig. The defaultConfig doesn't
+ // matter for the override policy though, since we set allowGroupSwitching to true, so
+ // it's not a problem.
+ scheduler::RefreshRateConfigs::Policy overridePolicy;
+ overridePolicy.defaultConfig =
+ mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig;
+ overridePolicy.allowGroupSwitching = true;
+ result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy,
+ /*overridePolicy=*/true);
+ }
+
+ if (result == NO_ERROR) {
+ mFrameRateFlexibilityTokenCount++;
+ // Handing out a reference to the SurfaceFlinger object, as we're doing in the line
+ // below, is something to consider carefully. The lifetime of the
+ // FrameRateFlexibilityToken isn't tied to SurfaceFlinger object lifetime, so if this
+ // SurfaceFlinger object were to be destroyed while the token still exists, the token
+ // destructor would be accessing a stale SurfaceFlinger reference, and crash. This is ok
+ // in this case, for two reasons:
+ // 1. Once SurfaceFlinger::run() is called by main_surfaceflinger.cpp, the only way
+ // the program exits is via a crash. So we won't have a situation where the
+ // SurfaceFlinger object is dead but the process is still up.
+ // 2. The frame rate flexibility token is acquired/released only by CTS tests, so even
+ // if condition 1 were changed, the problem would only show up when running CTS tests,
+ // not on end user devices, so we could spot it and fix it without serious impact.
+ *outToken = new FrameRateFlexibilityToken(
+ [this]() { onFrameRateFlexibilityTokenReleased(); });
+ ALOGD("Frame rate flexibility token acquired. count=%d",
+ mFrameRateFlexibilityTokenCount);
+ }
+ }));
+ return result;
+}
+
+void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() {
+ postMessageAsync(new LambdaMessage([&]() {
+ LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0,
+ "Failed tracking frame rate flexibility tokens");
+ mFrameRateFlexibilityTokenCount--;
+ ALOGD("Frame rate flexibility token released. count=%d", mFrameRateFlexibilityTokenCount);
+ if (mFrameRateFlexibilityTokenCount == 0) {
+ // |mStateLock| not needed as we are on the main thread
+ const auto display = getDefaultDisplayDeviceLocked();
+ status_t result =
+ setDesiredDisplayConfigSpecsInternal(display, {}, /*overridePolicy=*/true);
+ LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token");
+ }
+ }));
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 60904f6..12efca1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -407,7 +407,8 @@
*/
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
- bool callingThreadHasUnscopedSurfaceFlingerAccess() EXCLUDES(mStateLock);
+ bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true)
+ EXCLUDES(mStateLock);
/* ------------------------------------------------------------------------
* ISurfaceComposer interface
@@ -503,6 +504,7 @@
float lightPosY, float lightPosZ, float lightRadius) override;
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
int8_t compatibility) override;
+ status_t acquireFrameRateFlexibilityToken(sp<IBinder>* outToken) override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
*/
@@ -574,9 +576,9 @@
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
// Sets the desired display configs.
- status_t setDesiredDisplayConfigSpecsInternal(const sp<DisplayDevice>& display,
- HwcConfigIndexType defaultConfig,
- float minRefreshRate, float maxRefreshRate)
+ status_t setDesiredDisplayConfigSpecsInternal(
+ const sp<DisplayDevice>& display,
+ const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
EXCLUDES(mStateLock);
// called on the main thread in response to setAutoLowLatencyMode()
@@ -968,6 +970,8 @@
return doDump(fd, args, asProto);
}
+ void onFrameRateFlexibilityTokenReleased();
+
/* ------------------------------------------------------------------------
* VrFlinger
*/
@@ -1073,6 +1077,7 @@
std::unique_ptr<SurfaceInterceptor> mInterceptor;
SurfaceTracing mTracing{*this};
bool mTracingEnabled = false;
+ bool mAddCompositionStateToTrace = false;
bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
const std::shared_ptr<TimeStats> mTimeStats;
const std::unique_ptr<FrameTracer> mFrameTracer;
@@ -1275,6 +1280,8 @@
std::atomic<bool> mInputDirty = true;
void dirtyInput() { mInputDirty = true; }
bool inputDirty() { return mInputDirty; }
+
+ int mFrameRateFlexibilityTokenCount = 0;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index a9c3332..0b1251e 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -60,6 +60,8 @@
mCanStartTrace.wait(lock);
android::base::ScopedLockAssertion assumeLock(mSfLock);
LayersTraceProto entry = traceLayersLocked(mWhere, displayDevice);
+ mTracingInProgress = false;
+ mMissedTraceEntries = 0;
lock.unlock();
return entry;
}
@@ -76,7 +78,15 @@
void SurfaceTracing::notify(const char* where) {
std::scoped_lock lock(mSfLock);
+ notifyLocked(where);
+}
+
+void SurfaceTracing::notifyLocked(const char* where) {
mWhere = where;
+ if (mTracingInProgress) {
+ mMissedTraceEntries++;
+ }
+ mTracingInProgress = true;
mCanStartTrace.notify_one();
}
@@ -175,7 +185,10 @@
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags, displayDevice));
- mFlinger.dumpOffscreenLayersProto(layers);
+
+ if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) {
+ mFlinger.dumpOffscreenLayersProto(layers);
+ }
entry.mutable_layers()->Swap(&layers);
if (mTraceFlags & SurfaceTracing::TRACE_HWC) {
@@ -183,6 +196,10 @@
mFlinger.dumpHwc(hwcDump);
entry.set_hwc_blob(hwcDump);
}
+ if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) {
+ entry.set_excludes_composition_state(true);
+ }
+ entry.set_missed_entries(mMissedTraceEntries);
return entry;
}
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 83872ed..a00e5d6 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -49,6 +49,7 @@
status_t writeToFile();
bool isEnabled() const;
void notify(const char* where);
+ void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */;
void setBufferSize(size_t bufferSizeInByte);
void writeToFileAsync();
@@ -57,11 +58,15 @@
enum : uint32_t {
TRACE_CRITICAL = 1 << 0,
TRACE_INPUT = 1 << 1,
- TRACE_EXTRA = 1 << 2,
- TRACE_HWC = 1 << 3,
+ TRACE_COMPOSITION = 1 << 2,
+ TRACE_EXTRA = 1 << 3,
+ TRACE_HWC = 1 << 4,
TRACE_ALL = 0xffffffff
};
void setTraceFlags(uint32_t flags);
+ bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ {
+ return (mTraceFlags & flags) == flags;
+ }
private:
static constexpr auto kDefaultBufferCapInByte = 5_MB;
@@ -103,6 +108,8 @@
std::mutex& mSfLock;
uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT;
const char* mWhere GUARDED_BY(mSfLock) = "";
+ uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0;
+ bool mTracingInProgress GUARDED_BY(mSfLock) = false;
mutable std::mutex mTraceLock;
LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index ac33a0e..acf621e 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -51,4 +51,10 @@
// Blob for the current HWC information for all layers, reported by dumpsys.
optional string hwc_blob = 4;
+
+ /* Includes state sent during composition like visible region and composition type. */
+ optional bool excludes_composition_state = 5;
+
+ /* Number of missed entries since the last entry was recorded. */
+ optional int32 missed_entries = 6;
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index dd04076..ce41291 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -83,8 +83,8 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_LT(refreshRateConfigs->setPolicy(HwcConfigIndexType(10), 60, 60, nullptr), 0);
- ASSERT_LT(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 20, 40, nullptr), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0);
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -126,7 +126,7 @@
ASSERT_EQ(expectedDefaultConfig, minRate60);
ASSERT_EQ(expectedDefaultConfig, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -155,7 +155,7 @@
90};
ASSERT_EQ(expectedPerformanceConfig, performanceRate);
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -180,7 +180,7 @@
EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
}
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
{
auto& current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.configId, HWC_CONFIG_ID_90);
@@ -212,7 +212,7 @@
EXPECT_EQ(expected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
EXPECT_EQ(expected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(expected60Config,
@@ -224,7 +224,7 @@
EXPECT_EQ(expected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
EXPECT_EQ(expected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(expected90Config,
@@ -235,7 +235,7 @@
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
EXPECT_EQ(expected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
EXPECT_EQ(expected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(expected60Config,
@@ -332,7 +332,7 @@
&ignored));
lr.name = "";
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected60Config,
@@ -370,7 +370,7 @@
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
&ignored));
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected90Config,
@@ -408,7 +408,7 @@
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
&ignored));
- ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected60Config,
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
@@ -1218,6 +1218,33 @@
}
}
+TEST_F(RefreshRateConfigsTest, groupSwitching) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& layer = layers[0];
+ layer.vote = LayerVoteType::ExplicitDefault;
+ layer.desiredRefreshRate = 90.0f;
+ layer.name = "90Hz ExplicitDefault";
+
+ bool touchConsidered;
+ ASSERT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered)
+ .configId);
+
+ RefreshRateConfigs::Policy policy;
+ policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+ policy.allowGroupSwitching = true;
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
+ ASSERT_EQ(HWC_CONFIG_ID_90,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered)
+ .configId);
+}
+
} // namespace
} // namespace scheduler
} // namespace android